求和问题(利用哈希表、双指针)
近几天做了几道求和相关的题,用的方法基本都一样,所以放到一起写。包括
1、两数之和(leetcode第1题)
2、三数之和(leetcode第15题)
3、最接近的三数之和(leetcode第16题)
4、四数之和(leetcode第18题)
两数之和
题目描述
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,
并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
哈希表
简单介绍一下哈希表,首先需要知道什么是哈希函数。关键值根据某种映射关系计算出他存储的位置地址,这种映射关系就称之为哈希函数,即存储地址 = f (关键值)。f即为哈希函数。采用这种方式将关键值存储在一块空间中,这块空间成为哈希表,哈希表最适合求解的问题是查找与给定值相等的值的位置。简化了比较过程,所以效率大大提高。
代码块
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; ++i) {
if (hashtable.containsKey(target - nums[i])) {
return new int[]{hashtable.get(target - nums[i]), i};
}
hashtable.put(nums[i], i);
}
return new int[0];
}
}
代码解释
1、创建一个空的哈希表;
2、遍历列表,观察是否存在 target-nums[i] 的值,没有的话,将(nums[i], i)放入哈希表中;
3、存在的话,直接返回target-nums[i]的索引以及i的值;
出错
1、for循环没有写数据类型
2、创建返回的新数组时没有new
三数之和
题目描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
代码块
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList();
int n = nums.length;
if(nums == null || n<3) return ans;
Arrays.sort(nums);
for(int i = 0;i < n;i++){
if (nums[i]>0) break;
if (i>0 && nums[i]==nums[i-1]) continue;
int L = i+1;
int R = n-1;
while (L<R){
int sum = nums[i] + nums[L] + nums[R];
if (sum == 0){
ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
while(L<R && nums[L]==nums[L+1]) L++;
while(L<R && nums[R]==nums[R-1]) R--;
L++;
R--;
}
else if(sum<0) L++;
else if(sum>0) R--;
}
}
return ans;
}
代码解释
1、建立一个空列表用来返回最后结果
2、将数组排序
3、遍历数组,如果第一个数就大于target,则直接跳出循环,返回空列表
4、去重,如果nums[i]==nums[i-1],则直接遍历下一个元素
5、定义双指针,分别指向遍历到的元素的下一个元素,以及整个数组的最后一个元素
6、当左指针小于右指针时,循环
7、定义sum等于三数之和,如果sum>target,则右指针往左移,如果sum<target,则左指针往右移
8、如果sum=target,两指针同时移动,但要注意去重,如果指针移动后的元素与移动前相等,则继续移动。
出错
1、Arrays.sort(nums); 排序关键字搞错
2、 if(i>0 && nums[i] == nums[i-1]) continue; 忽略了i>0;
3、ans.add(Arrays.asList(nums[i],nums[L],nums[R])); 没有将数组转化为列表;
最接近的三数之和
题目描述
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
思路基本与上一题一样,只不过多了一个判断三数之和与target的差什么时候最小
代码块
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int n = nums.length;
int best = 10000000;
for(int i = 0;i<n;i++){
if(i>0 && nums[i] == nums[i-1]){
continue;
}
int j = i+1,k = n-1;
while(j<k){
int sum = nums[i] + nums[j] + nums[k];
if(sum == target){
return sum;
}if(Math.abs(sum - target)<Math.abs(best - target)){
best = sum;
}
if(sum<target){
while(j<k && nums[j+1] == nums[j]){
j++;
}
j++;
}
if(sum>target){
int k0 = k-1;
while(j<k0 && nums[k0] == nums[k]){
k0--;
}
k = k0;
}
}
}
return best;
}
四数之和
题目描述
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
代码块
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<> ();
int n = nums.length;
if(nums == null || n<4){
return result;
}
Arrays.sort(nums);
for(int i1 = 0;i1<n-3;i1++){
if(i1>0 && nums[i1]==nums[i1-1]){
continue;
}
int Max = nums[i1]+nums[n-3]+nums[n-2]+nums[n-1];
if(Max<target){
continue;
}
int Min = nums[i1]+nums[i1+1]+nums[i1+2]+nums[i1+3];
if(Min>target){
break;
}
for(int i2 = i1 + 1;i2<n-2;i2++){
if(i2>i1+1 && nums[i2]==nums[i2-1]){
continue;
}
int Maxx = nums[i1]+nums[i2]+nums[n-2]+nums[n-1];
if(Maxx<target){
continue;
}
int Minn = nums[i1]+nums[i2]+nums[i2+1]+nums[i2+2];
if(Minn>target){
break;
}
int i3 = i2+1;
int i4 = n-1;
while(i3<i4){
int value = nums[i1]+nums[i2]+nums[i3]+nums[i4];
if(value == target){
result.add(Arrays.asList(nums[i1],nums[i2],nums[i3],nums[i4]));
i3++;
while(i3<i4 && nums[i3] == nums[i3-1]){
i3++;
}
i4--;
while(i3<i4 && nums[i4]==nums[i4+1]){
i4--;
}
}else if(value>target){
i4--;
}else{
i3++;
}
}
}
}
return result;
}
代码解释
思路仍然是一样的,不再赘述,不过是多了一个for循环。
总结:
希望以后再遇到求和与目标值作比较问题的问题能够首先想到双指针。