leetcode解題筆記:Two sum系列解題思路
- Two Sum
- 3Sum
- 3Sum Closest
Two Sum
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9 ,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
解法一
一下能想到的思路就是內外兩個迴圈找和為target的兩個數字,這樣的複雜度是O(n*n)。
解法二
想到能否用雜湊表,每遍歷到一個元素num,看target-num是否在hash表中,如果在就得出答案,如果不在就將當前num放入雜湊表中。
public int[] twoSum(int[] nums, int target) {
HashMap<Integer,Integer> map= new HashMap<Integer,Integer>();
int [] result = new int[2];
for(int i=0;i<nums.length;i++){
if(map.containsKey(target-nums[i])){
result[0]=i;
result[1] = map.get(target-nums[i]);
break;
}else{
map.put(nums[i],i);
}
}
return result;
}
這種解法是O(n)的時間複雜度,但要額外增加O(n)的雜湊表儲存空間。
解法三
可以換個角度來考慮問題,如果給定的陣列是已排序的陣列,那麼就可以設定lo和hi兩個指標,如果這兩個數字的和比target要大,那麼就lo++,否則hi–。這樣排序陣列需要O(NlogN),找和的過程需要O(N),但是空間是in-place的。
其實這是167. Two Sum II - Input array is sorted
丟擲的問題。這樣我們就不用對陣列排序了。
public int[] twoSum(int[] numbers, int target) {
int i = 0;
int j = numbers.length-1;
int[] result = new int[2];
while(j>i){
if(numbers[i]+numbers[j] == target){
result[0] = i+1;
result[1] = j+1;
break;
}else if(numbers[i]+numbers[j] < target){
i++;
}else{
j--;
}
}
return result;
}
時間複雜度為O(N)
3Sum
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: 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]
]
這次是尋找3個數的和為0的組合。可以接著2Sum解法三的思路來想。首先先對陣列排序;然後從頭開始每次取一個數作為sum,則此題變成了在後面的陣列中尋找兩個數其和為-sum,就和上面的過程一樣。
這裡還要注意一個重複的問題,當我們對陣列排序後,重複的數是排列在一起的,此時若已經取過一個解後就不要再取重複的解了。
public List<List<Integer>> threeSum(int[] nums) {
int len = nums.length;
List<List<Integer>> result = new ArrayList<List<Integer>>();
Arrays.sort(nums);
for(int i=0;i<len;i++){
//防止重複解
if(i==0 || nums[i]!=nums[i-1]){
int sum = 0-nums[i];
int lo = i+1;
int hi = len-1;
while(lo<hi){
if(nums[lo]+nums[hi] == sum){
result.add(Arrays.asList(nums[i], nums[lo], nums[hi]));
//防止重複解
while(lo<hi && nums[lo] == nums[lo+1])lo++;
while(lo<hi && nums[hi] == nums[hi-1])hi--;
lo++;
hi--;
}else if(nums[lo]+nums[hi]>sum){
hi--;
}else{
lo++;
}
}
}
}
return result;
}
這種解法的時間複雜度為O(N*N)
3Sum Closest
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
For example, given array S = {-1 2 1 -4}, and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
其實和上面的過程一樣,只不過是相等比較轉換成了差值的比較。
public int threeSumClosest(int[] nums, int target) {
int len = nums.length;
if(len<3) return -1;
Arrays.sort(nums);
int result = nums[0]+nums[1]+nums[2];
for(int i=0;i<len-2;i++){
int lo = i+1;
int hi = len-1;
while(lo<hi){
int sum = nums[i]+nums[lo]+nums[hi];
if(sum == target){
return sum;
}else{
if(Math.abs(sum-target) < Math.abs(target-result)){
result = sum;
}
if(sum>target){
hi--;
}else{
lo++;
}
}
}
}
return result;
}
這種解法的時間複雜度為O(N*N)
總結
可以發現,two sum的解法三是適用於其他變種的,都是在陣列已排序的情況下根據當前和與target的比較情況移動指標,其中也要特別注意避免重複解的問題。