領釦刷題---15.三數之和
題目要求:
給定一個包含 n 個整數的陣列 nums
,判斷 nums
中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。
注意:答案中不可以包含重複的三元組。
小白第一次寫部落格,希望大佬多多指教。
這是一道在領釦上標記為中等的陣列題目,題目的難點在於去除重複的三元組。我們想去除重複的元素,就要先弄清楚,重複的答案是如何出來的,按照正常的思路,我們可以跑一個三層for迴圈,每一次都不斷由前面的和後面的匹配,直到所有的組合被匹配完畢,滿足要求的答案被找到,但是在跑的過程中如果前面的數有和後面的數重複的,那我們跑的過程中必然會將其記錄兩次。弄清楚了重複的原因,現在就需要想辦法去除重複。這樣問題就變成了陣列的去重,陣列去重我們一般採用的都是先排序的方式,前面與後面對比,去重。
按照我們的思路程式碼如下:
//程式語言c++
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> a;//建立容器 int len=nums.size(); vector<int>temp;//中間變數,用於後面儲存每一次找到的結果 if(nums.size()<=2) return a;//如果所給的陣列長度小於3,直接返回 sort(nums.begin(),nums.end());//使用sort方法對資料進行排序 int i,j,k,sum; for(i=0;i<len-2;i++)//第一層迴圈 { if(nums[i]>0)//nums[0]如果大於0代表資料都為正數,直接退出 break; if(i>0&&nums[i]==nums[i-1])//用於去除重複值,只使用第一次出現的資料 continue; j=i+1; while(j<=len-2) { if(j>i+1&&nums[j]==nums[j-1])//去重 { j++; continue; } k=j+1; while(k<=len-1) { if(k>j+1&&nums[k]==nums[k-1])//去重 { k++; continue; } sum=nums[i]+nums[j]+nums[k]; if(sum==0) { temp.push_back(nums[i]); temp.push_back(nums[j]); temp.push_back(nums[k]); a.push_back(temp); temp.clear();//清空 k++; } else k++; } j++; } }
return a; } };
提交之後,會提示超時,所以我們改進程式碼,考慮到存在的三重for迴圈是為了得到和0匹配的結果,在借鑑了大佬的方法之後,我們可以將其改為二重迴圈,利用前後向中間靠的原則,尋找答案。這是一種程式設計的基本技巧,如果沒有掌握可以借鑑學習,改變後的程式碼如下:
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> a; int len=nums.size(); vector<int>temp; if(nums.size()<=2) return a; sort(nums.begin(),nums.end()); int i,j,k,sum; for(i=0;i<len-2;i++) { if(nums[i]>0) break; if(i>0&&nums[i]==nums[i-1]) continue; j=i+1;//未匹配資料的前端 k=len-1;未匹配資料的後端 while(j<k)//如果出現交叉,則代表後面的資料都匹配完畢 { if(j>i+1&&nums[j]==nums[j-1])//用於去除重複值,由於k每次都是找到就跳出,所以不用去重操作 { j++; continue; } sum=nums[i]+nums[j]+nums[k]; if(sum==0)//儲存資料 { temp.push_back(nums[i]); temp.push_back(nums[j]); temp.push_back(nums[k]); a.push_back(temp); temp.clear(); j++; } else if(sum>0)//如果大於0代表資料過大則將k減小,則匹配的k值減小 k--; else j++; } }
return a; } };
可以發現這一次很輕鬆就通過了,完成了這道題目之後我們可以嘗試去做16,18兩題,思路大致相同。