LeetCode_3Sum,快速排序演算法
一.題目3Sum Total Accepted: 45112 Total Submissions: 267165My Submissions
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
- Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
- The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4}, A solution set is: (-1, 0, 1) (-1, -1, 2)Show TagsHave you met this question in a real interview? Yes No
Discuss
二.解題技巧 這道題和另外一道題Two Sum很類似,不過這道題是在數組中尋找三個數,使得其和為0,同時要求這三個數只能出現一次。如果單純得使用暴力演算法來做的話,時間複雜度為O(n^3),且很難判斷這一組數是否已經出現過。 如果考慮將數組A(元素個數為n)進行升序排序,那麼按照順序將數組中的第i個數作為三個數中最小的數,尋找從A的第i+1個數到n-1個數中滿足和為-A[i]的數,就可以找到滿足三個數和為0的組合了,但是,單獨考慮這種情況,會出現重複的問題。要保證不出現重複的情況,當i!=0時,如果第i個數與第i-1個數相同的話,則不進行處理,直接處理第i+1個元素。這樣,只要保證三個數中最小的數是按照順序遞增的,那麼演算法找到的解就都是不重複的。 這道題的邊界條件在於:由於我們選擇的是三個數中的最小值,因此,對於這個數的迴圈是[0, n-2),同時,要對最小值進行消除重複的元素時,需要從第1個元素開始判斷,如果從第0個元素開始判斷的時候,可能會將0,0,0這種情況忽略掉,因此,在消除重複的最小元素時,必須從第1個元素才開始。 這道題在尋找數組A中的兩個數的和為-A[i]時,可以考慮利用數組A是已經排序的條件,進行左右夾逼操作。在進行左右搜尋的時候,需要將左右兩邊收縮到與當前元素不同的元素為止,這樣做有兩個原因:1.可以減少計算量;2.噹噹前的兩個元素的和剛好等於-A[i]的時候,如果沒有進行上面的縮放操作,那麼就可能將重複的三個數儲存下來,導致結果出錯。
三.實現代碼
class Solution{public: vector<vector<int> > threeSum(vector<int> &num) { int Size = num.size(); vector<vector<int> > Result; if (Size < 3) { return Result; } sort(num.begin(), num.end()); for (int Index_outter = 0; Index_outter < (Size - 2); Index_outter++) { int First = num[Index_outter]; int Second = num[Index_outter + 1]; const int Target = 0; if ((Index_outter != 0) && (First == num[Index_outter - 1])) { continue; } int Start = Index_outter + 1; int End = Size - 1; while (Start < End) { Second = num[Start]; int Third = num[End]; int Sum = First + Second + Third; if (Sum == Target) { vector<int> Tmp; Tmp.push_back(First); Tmp.push_back(Second); Tmp.push_back(Third); Result.push_back(Tmp); Start++; End--; while (num[Start] == num[Start - 1]) { Start++; } while (num[End] == num[End + 1]) { End--; } } if (Sum < Target) { Start++; while (num[Start] == num[Start -1]) { Start++; } } if (Sum > Target) { End--; if (num[End] == num[End + 1]) { End--; } } } } return Result; }};
四.體會 我自己的想法時,將數組進行排序,然後按照順序選擇數組A[1, n-1)中的元素作為三個數中的中位元來在剩下的已經排好序的數組中尋找滿足條件的其他兩個數。但是,選擇中位元的這種情況需要考慮的邊界條件比較複雜,並沒有選擇最小值來得方便一些,同時,選擇中位元之後,將已經排序的數組分成了兩段,這樣在進行收縮的時候,需要分別判斷兩個兩邊與i的關係,也比較容易出錯。 這道題通過對數組進行排序,從而按照順序選擇不同的最小值來避免出現重複的情況,這確實是一個比較好的編程技巧。
著作權,歡迎轉載,轉載請註明出處,謝謝