&LeetCode0015& 三數之和

題目

給定一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。

注意:答案中不可以包含重複的三元組。

示例:

給定數組 nums = [-1, 0, 1, 2, -1, -4],
滿足要求的三元組集合爲:
[
[-1, 0, 1],
[-1, -1, 2]
]

來源:力扣(LeetCode

思路

首先,對原數組進行排序,遍歷排序後的數組,需要注意不是遍歷到最後一個停止,而是到倒數第三個就可以;
其次,可以做個剪枝優化,即遍歷到正數的時候就 break,因爲數組現在是有序的,如果第一個要 fix 的數就是正數了,則後面的數字就都是正數,就永遠不會出現和爲0的情況;
然後,還要加上重複就跳過的處理,處理方法是從第二個數開始,如果和前面的數字相等,就跳過,因爲不想把相同的數字fix兩次;
再次,對於遍歷到的數,用0減去這個 fix 的數得到一個 target,然後只需要在之後找到兩個數之和等於 target 即可;
最後,用兩個指針分別指向 fix 數字之後的數組的首尾兩個數,如果兩個數和正好爲 target,則將這兩個數和 fix 的數一起存入結果中。然後就是跳過重複數字的步驟,兩個指針都需要檢測重複數字。如果兩數之和小於 target,則將左邊那個指針i右移一位,使得指向的數字增大一些。同理,如果兩數之和大於 target,則將右邊那個指針j左移一位,使得指向的數字減小一些。

C++代碼

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
    {
        vector<vector<int>> res;
        sort(nums.begin(), nums.end());

        if (nums.empty() || nums.back() < 0 || nums.front() > 0)
            return {};

        for (int k = 0; k < (int)nums.size() - 2; ++k)
        {
            if (nums[k] > 0)
                break;
            if (k > 0 && nums[k] == nums[k - 1])
                continue;
            int target = 0 - nums[k], i = k + 1, j = (int)nums.size() - 1;

            while (i < j)
            {
                if (nums[i] + nums[j] == target)
                {
                    res.push_back({nums[k], nums[i], nums[j]});

                    while (i < j && nums[i] == nums[i + 1])
                        ++i;
                    while (j < j && nums[j] == nums[j - 1])
                        --j;
                    ++i;
                    --j;
                }
                else if (nums[i] + nums[j] < target)
                {
                    ++i;
                }
                else
                {
                    --j;
                }
            }
        }
        return res;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章