leetcode上有2sum,做完了让你做3sum,然后还有3sum closest, 4sum等一系列神奇的sum,所以今天就把这些sum放在一起看看,能不能总结出什么神奇的东西~
1.TwoSum
问题描述:
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].
解题思路:
本题可以使用map在存储值和下标,因为有且只有一个解,所以当我们找到解就可以break。
如果数组中存在两个相同的值来构成解,如target = 6, 解为(3,3)。总有一个值在第二个值的后面,所以在加入map的时候会被覆盖。所以需要检查获得的下标值是否与当前用于查找的数字的下标值相同来判断是否取得为同个位置的数字。
解法:
class Solution { public int[] twoSum(int[] nums, int target) { HashMap<Integer, Integer> map = new HashMap<Integer,Integer>(); int[] ret = {-1, -1}; for(int i = 0; i < nums.length; i++){ map.put(nums[i], i); } for(int i = 0; i < nums.length; i++){ int another = target - nums[i]; if(map.containsKey(another) && map.get(another) != i){ ret[0] = i; ret[1] = map.get(another); break; } } return ret; } }
此时时间复杂度因为O(n)
15. 3Sum
问题描述:
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.
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] ]
解题思路:
寻找三个数使得其和为0,并且返回的是数字的值而非下标,那此时我们不妨先将其排序,并检查最大值,若最大值小于0那么绝对不存在有三个数字他们的和可以等于0。需要注意的是,当我们取数组的值的时候,需要考虑数组中不存在值的情况。
我们可以取一个值,然后在剩下的数字中寻找两个值,他们的和是0-所取的值,来转化成 TwoSum问题。此时的TwoSum问题与之前TwoSum问题的不同之处在于我们想要得到的是值而非下标,那么我们可以用循环来解决这个问题。
因为题目中要求的为唯一的三元组,所以我们需要避免重复,注意查重。
解法:
class Solution { public List<List<Integer>> threeSum(int[] nums) { Arrays.sort(nums); ArrayList<List<Integer>> ret = new ArrayList<>(); if(nums.length == 0 || nums[nums.length-1] < 0) return ret; for(int idx = 0; idx < nums.length; idx++){ if(nums[idx] > 0) break; if(idx > 0 && nums[idx] == nums[idx-1]) continue; int target = 0 - nums[idx]; int i = idx + 1; int j = nums.length - 1; while(i < j){ if(nums[i]+nums[j] == target){ ArrayList<Integer> triplet = new ArrayList<Integer>(); triplet.add(nums[idx]); triplet.add(nums[i]); triplet.add(nums[j]); ret.add(triplet); while(i < j && nums[i] == nums[i+1]) i++; while(i < j && nums[j] == nums[j-1]) j--; i++; j--; }else if(nums[i]+nums[j] < target){ i++; }else{ j--; } } } return ret; } }
还有一点需要注意的是,在寻找TwoSum的时候,当寻找到了值,即 nums[i]+nums[j] == target时,在该块中要记得对下标进行加减变化,否则下标不变会陷入死循环。两个while的目的是移到最后一个相同的值。
本题参考了http://www.cnblogs.com/grandyang/p/4481576.html的解法。
16. 3Sum Closest
问题描述:
Given an array nums
of n integers and an integer target
, find three integers in nums
such that the sum is closest to target
. Return the sum of the three integers. You may assume that each input would have exactly one solution.
Example:
Given array nums = [-1, 2, 1, -4], and target = 1. The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
解题思路:
这道题和上面的那个3Sum感觉差不多。不一样的地方在于,寻找的不是一个确切的值,而是与target最相近的值。
我们也可以使用上面的方法,不过这次就要对所有数字进行遍历啦
解法:
class Solution { public int threeSumClosest(int[] nums, int target) { Arrays.sort(nums); int ret = nums[0]+nums[1]+nums[2]; for(int idx = 0; idx < nums.length; idx++){ int i = idx+1; int j = nums.length-1; while(i < j){ int curTotal = nums[idx] + nums[i] + nums[j]; ret = Math.abs(curTotal - target) < Math.abs(ret-target) ? curTotal : ret; if(curTotal < target) i++; else if(curTotal > target) j--; else return curTotal; } } return ret; } }
我在做的时候我遇见的一个问题,在一开始的时候我给ret的初始值为Integer.MAX_VALUE, 然而并不能通过OJ,因为当target=-1时,对ret进行减target操作此时实际上是+1,此时超出了int所能表示的最大数字,则会溢出,那么就不能得到准确的值了,所以我将其改为了任意的一个组合,保险起见就0,1,2了。
18. 4Sum
问题描述:
我的思路:
一开始我用的暴力破解法,对,写了4个循环,这样时间复杂度是O(n4), 结果统计的柱状图赏已经见不到我的身影了。。。
要避免重复的结果的计算和判断,然后结合3Sum的处理方法,将O(n4)降为O(n3)
代码:
class Solution { public: vector<vector<int>> fourSum(vector<int>& nums, int target) { sort(nums.begin(), nums.end()); set<vector<int>> Vset; for(int a = 0; a < int(nums.size() - 3); a++){ if(a > 0 && nums[a] == nums[a-1]) continue; for(int b = a+1; b < int(nums.size() - 2); b++){ if(b > a+1 && nums[b] == nums[b-1]) continue; int left = b + 1; int right = nums.size() -1 ; while(left < right){ int sum = nums[a] + nums[b] + nums[left] + nums[right]; if(sum == target){ vector<int> qua{nums[a], nums[b], nums[left], nums[right]}; Vset.insert(qua); left++; right--; } else if(sum < target) left++; else right--; } } } return vector<vector<int>>(Vset.begin(), Vset.end()); } };