1. 程式人生 > 實用技巧 >15-三數之和

15-三數之和

題目:

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

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

示例:

給定陣列 nums = [-1, 0, 1, 2, -1, -4],

滿足要求的三元組集合為:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解答:

程式碼一:

直接三個巢狀迴圈,然後移動兩個index查詢符合要求的結果,注意:題目中輸出的內容是從小到大排序的,所以首先需要對輸入數字進行排序

vector<vector<int>> threeSum(vector<int
>& nums) { vector<vector<int>> result; if (nums.size() < 3) //元素至少3個 return result; //先排序 for (int i = 0; i < nums.size(); i++) { for (int j = i + 1; j < nums.size(); j++) { if (nums.at(i) > nums.at(j)) {
int tmp = nums.at(i); nums.at(i) = nums.at(j); nums.at(j) = tmp; } } } auto isExist = [](vector<int>& vec,vector<vector<int>>& results)->bool{ for (auto val : results) { if (val.at(0) == vec.at(0
) && val.at(1) == vec.at(1)) return true; } return false; }; int idx1 = 0, idx2 = 0; for (int i = 0; i < nums.size(); i++) { for (int j = i + 1; j < nums.size(); j++) { int twoSum = nums.at(i) + nums.at(j); for (int k = j + 1; k < nums.size(); k++) { if ((twoSum + nums.at(k)) == 0) { vector<int> val = { nums.at(i), nums.at(j), nums.at(k) }; bool has = isExist(val, result); if (!has) { result.push_back(val); break;//找到一個後就break,因為第一個、第二個數字已經找了,往後再找第三個為重複的 } } } } } return result; }

提交後,超出時間限制。。。

上面的氣泡排序修改為<algorithm>中的sort:

sort(nums.begin(), nums.begin() + nums.size());

提交後仍是超出時間限制。問題應該是查詢的那部分,時間複雜度為O(n^3),修改後如下,時間複雜度為O(n^2)

vector<vector<int>> threeSum2(vector<int>& nums)
{
    vector<vector<int>> result;
    if (nums.size() < 3)    //元素至少3個
        return result;

    //先排序
    sort(nums.begin(), nums.begin() + nums.size());

    if (nums.at(0) > 0)
        return result;

    //判斷是否已經存在的lambda
    auto isExist = [](vector<int>& vec, vector<vector<int>>& results)->bool{
        for (auto val : results)
        {
            if (val.at(0) == vec.at(0) && val.at(1) == vec.at(1))
                return true;
        }
        return false;
    };

    //1.排序後,如果前兩個相加>0了,後面就不用找了
    //2.對於第三個index,如果找到了就直接break了,因為前兩個值一樣,最終結果只有一條
    int idx1 = 0, idx2 = 0;
    for (int i = 0; i < nums.size(); i++)
    {
        idx1 = i + 1;
        if (idx1 >= nums.size())
            return result;
        if (nums.at(i) + nums.at(idx1) > 0)//前兩個數大於零,不再找
            break;

        idx2 = nums.size() - 1;
        while (idx1<nums.size() && idx2 > idx1)
        {
            if (nums.at(i) + nums.at(idx1) > 0)//前兩個數大於零,不再找
                return result;

            int val = nums.at(i) + nums.at(idx1) + nums.at(idx2);
            if (val == 0)
            {
                vector<int> val = { nums.at(i), nums.at(idx1), nums.at(idx2) };
                bool has = isExist(val, result);
                if (!has)
                    result.push_back(val);

                idx1++;
                idx2--;
            }
            else if (val > 0)
                idx2--;
            else if (val < 0)
                idx1++;
        }
    }

    return result;
}

提交幾次還是時間超出限制。。。應該是判斷是否重複的問題,因為已經排序過了,再通過函式判斷是否重複邏輯上存在重複,程式碼修改如下:

vector<vector<int>> threeSum2(vector<int>& nums)
{
    vector<vector<int>> result;
    if (nums.size() < 3)    //元素至少3個
        return result;

    //先排序
    sort(nums.begin(), nums.begin() + nums.size());

    if (nums.at(0) > 0)
        return result;

    ////判斷是否已經存在的lambda
    //auto isExist = [](vector<int>& vec, vector<vector<int>>& results)->bool{
    //    for (auto val : results)
    //    {
    //        if (val.at(0) == vec.at(0) && val.at(1) == vec.at(1))
    //            return true;
    //    }
    //    return false;
    //};

    //1.排序後,如果前兩個相加>0了,後面就不用找了
    //2.對於第三個index,如果找到了就直接break了,因為前兩個值一樣,最終結果只有一條
    int idx1 = 0, idx2 = 0;
    for (int i = 0; i < nums.size(); i++)
    {
        if (i > 0 && nums.at(i) == nums.at(i - 1))//跟上個元素相同的跳過,因為已經找了
            continue;

        idx1 = i + 1;
        if (idx1 >= nums.size())
            break;
        if (nums.at(i) + nums.at(idx1) > 0)//前兩個數大於零,不再找
            break;

        idx2 = nums.size() - 1;
        
        while (idx1<nums.size() && idx2 > idx1)
        {
            if (nums.at(i) + nums.at(idx1) > 0)//前兩個數大於零,不再找
                return result;

            if (idx1 > i+1 && nums.at(idx1) == nums.at(idx1 - 1))//
            {
                idx1++;
                continue;
            }

            int val = nums.at(i) + nums.at(idx1) + nums.at(idx2);
            if (val == 0)
            {
                vector<int> val = { nums.at(i), nums.at(idx1), nums.at(idx2) };
                //bool has = isExist(val, result);    //已經排序了,不用再判斷重複
                //if (!has)
                    result.push_back(val);

                idx1++;
                idx2--;
            }
            else if (val > 0)
                idx2--;
            else if (val < 0)
                idx1++;
        }
    }

    return result;
}

妹妹的終於過了。。。

待修改。。。