力扣(LeetCode)試題--最接近的三數之和 c++實現

3Sum Closest(最接近的三數之和)

Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

給定一個包括 n 個整數的數組 nums 和 一個目標值 target。找出 nums 中的三個整數,使得它們的和與 target 最接近。返回這三個數的和。假定每組輸入只存在唯一答案。

示例:

輸入:nums = [-1,2,1,-4], target = 1
輸出:2
解釋:與 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

算法1:暴力求解

將所有可能的三個數的組合窮舉出來,然後依次計算與target最接近的和

int diff(const int& v1,const int&v2) {
    int re = v1 - v2;
    return re > 0 ? re : -re;
}

int threeSumClosest1(vector<int>& nums, int target) {
    int sum = 0;
    int sum_temp;
    int diff_min = INT16_MAX;
    vector<int>::iterator begin = nums.begin();
    vector<int>::iterator end = nums.end();

    for (vector<int>::iterator i=begin; i != end - 2; i++) {
        for (vector<int>::iterator j = i + 1; j != end - 1; j++) {
            for (vector<int>::iterator k = j + 1; k != end; k++) {
                sum_temp = *i + *j + *k;
                int dif_temp = this->diff(sum_temp, target);
                if (dif_temp==0)
                {
                    return sum_temp;
                }
                if (dif_temp<diff_min)
                {
                    diff_min = dif_temp;
                    sum = sum_temp;
                }
            }
        }
    }
    return sum;
}

算法優化

先對數據按照升序排序,假設在一次循環中,得到的三個數之和與target的差>0,則最內層循環沒有必要繼續進行,因爲繼續循環下去後面的三個數之和與target差值都會大於當前的差值

int diff(const int& v1,const int&v2) {
    int re = v1 - v2;
    //return re > 0 ? re : -re;
    return re;
}
int threeSumClosest2(vector<int>& nums, int target) {
    int sum = 0;
    int sum_temp;
    int diff_min = INT16_MAX;
    vector<int>::iterator begin = nums.begin();
    vector<int>::iterator end = nums.end();
    sort(begin, end);

    for (vector<int>::iterator i = begin; i != end - 2; i++) {
        for (vector<int>::iterator j = i + 1; j != end - 1; j++) {
            for (vector<int>::iterator k = j + 1; k != end; k++) {
                sum_temp = *i + *j + *k;
                int dif_temp = this->diff(sum_temp, target);
                if (dif_temp==0)
                {
                    return sum_temp;
                }

                if (abs(dif_temp) < abs(diff_min))
                {
                    diff_min = dif_temp;
                    sum = sum_temp;
                }

                if (diff_min>0 && dif_temp>diff_min)
                {
                    break;
                }

            }
        }
    }

    return sum;

}

使用暴力求解的算法時間複雜度爲O(n3)O(n^3)

算法2:雙指針

爲了減少算法的時間複雜度,可以考慮使用雙指針,將算法的三層循環編程雙層循環

先對數組升序排序

設三個數的指針分別爲i.j,ki.j,k

  • 固定i=v[0]i=v[0],考慮其他兩個數的位置
  • j=i+1,k=nj=i+1,k=n
  • 判斷當前的三個數之和sumsum
    • sum<target j++ : 即如果三數之和比target小,則差異更小的數只可能在[j+1,k]之間產生
    • sum>target k– :即如果三數之和比target大,則差異更小的數只可能在[j,k-1]之間產生
  • 記錄每次組合的三數之和,更新當前最小和

這樣,當一個數固定下來之後,另外兩個數的可能產生差異最小的組合通過掃描一次數組就可以完成,即線性時間複雜度,對第一個數枚舉,整個算法的複雜度爲O(n2)O(n^2)

在這裏插入圖片描述

int diff(const int& v1,const int&v2) {
    int re = v1 - v2;
    //return re > 0 ? re : -re;
    return re;
}

int threeSumClosest3(vector<int>& nums, int target) {
    int sum = 0;
    int sum_temp;
    int diff_temp;
    int diff_min = INT16_MAX;
    vector<int>::iterator begin = nums.begin();
    vector<int>::iterator end = nums.end();
    sort(begin, end);

    for (vector<int>::iterator i = begin; i != end - 2; i++) {
        vector<int>::iterator j = i + 1;
        vector<int>::iterator k = end - 1;
        while (j!=k)
        {
            sum_temp = *i + *j + *k;
            diff_temp = diff(sum_temp, target);


            if (diff_temp == 0)
            {
                return sum_temp;
            }

            if (abs(diff_temp)<abs(diff_min))
            {
                diff_min = diff_temp;
                sum = sum_temp;
            }

            if (diff_temp < 0)
            {
                j++;
            }
            else {
                k--;
            }
        }



    }
    return sum;
}

算法性能對比

算法 時間 內存
暴力求解 1896ms 9.9MB
雙指針 16ms 10.3MB
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章