Three Sum
【題目】
Given an array nums
of n integers, are there elements a, b, c in nums
such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
(給定一個包含 n 個整數的數組 nums
,判斷 nums
中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。)
Note:
The solution set must not contain duplicate triplets.
(注意:答案中不可以包含重複的三元組。)
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
【分析】
乍一看這道題,最最最最直接暴力的方法是:我們可以採用對a,b,c三層for循環。但是我們提交之後時間複雜度一定會超出題目的時間限制。因爲通常這種題目所給的用例會非常大,這道題暴力求解的時間複雜度是n^3,所以我們應該尋求方法,降低時間複雜度。
所以我們想到這道題目與Two Sum類似,我們可以先用a對數組進行遍歷;因爲題目要求是a + b + c = 0,所以這道題就變成了b + c的值等於-a,然後用之前我寫過的Two Sum那道題的方法就可以了。
上面那種方法的確可以把結果跑出來,但是時間複雜度依然不是很理想,所以今天我想介紹另一種方法,這種方法我在之前的博客中也談到過:用雙向指針。
- 首先我們要對數組進行升序排序,然後定義第一個數字a =nums[index]; 對數組nums進行遍歷,所以有: for (index = 0; index < nums.length; index++)
- 其次我們需要定義兩個指針,一個從左到右(我定義叫left),另一個從右到左(我定義叫right);left = index + 1(左指針從index = 0的下一個開始)right = nums.length - 1(數組長度減一即爲最後一位,index從0開始)
- 我們有其餘兩個數字b和c,b = nums[left], c = nums[right] ,total = a + b + c,在left < right的條件下, 我們分三種情況討論:1. total < 0; 2. total > 0; 3. total = 0
- 第一種情況:說明三個數字中需要有一個數字變大,a是遍歷整個數組,在外層,不能動;而c是從右向左移動,數組是升序排序,向左移動只能使結果越來越小,因此只能b向右移動,即:left++; 第二種情況同理,需要有數字變小,a還是不能動,b向右移動只能越來越大,所以只能c向左,即:right--; 第三種情況就是解,需要加到result中,然後左右指針同時移動到下一位即:同時進行 left++和 right--。
- 最後我們需要對答案進行去重操作,因爲題目要求是all unique。舉個例子:假如一個數組{-1, -1, -1, 1, 0, -2, 2},我們知道-1,-1,2相加是0。但是我們不知道某一個解中的-1究竟是哪個-1,所以我們應該去重。
Java實現代碼如下:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for (int index = 0; index < nums.length; index++){
int a = nums[index];
if (index >= 1 && nums[index - 1] == a) {
continue;
}
int left = index + 1;
int right = nums.length - 1;
while (left < right) {
int b = nums[left];
int c = nums[right];
int total = a + b + c;
if (total < 0) {
left++;
} else if (total > 0) {
right--;
} else {
result.add(Arrays.asList(a, b, c)); //noted
while (left < right && b == nums[left + 1]) {
left++;
}
while (left < right && c == nums[right - 1]) {
right--;
}
left++;
right--;
}
}
}
return result;
}
}