前言
一般对于这种数量相加的,我们的思路可以是先对数组进行排序,然后使用双指针的方法
两数相加
题目介绍

思路讲解
因为是需要返回下标,所以排序双指针有点不合适了。
这里思路有两个:
(1)暴力破解,时间复杂度很高O(N^2 ),未额外创建空间,但时间复杂度过高不推荐
(2)借用hash表,数值和下标以键值对的方式存入,这样时间复杂度小了O(N),创建hash表增加了额外空间,故空间复杂度O(N)
代码
暴力法:
时间复杂度:O(N^2 )
空间复杂度:O(1)
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
// 依次遍历
for(int i=0;i<nums.length;i++){
for(int j=i+1;j<nums.length;j++){
if(nums[i]+nums[j]==target){
result[0]=i;
result[1] = j;
}
}
}
return result;
}
}
hash表法:
时间复杂度:O(N )
空间复杂度:O(N)
class Solution {
public int[] twoSum(int[] nums, int target) {
// 哈希表中的key为数值,value为索引
Map<Integer,Integer> map = new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.containsKey(target-nums[i])){
return new int[]{map.get(target-nums[i]),i};
}
map.put(nums[i],i);
}
return new int[0];
}
}
三数相加
题目介绍

思路讲解
1、先对数组进行排序,使用的方法是Arrays.sort(nums);
2、固定第一个数值,后两个数值使用双指针
3、注意的几点:① 排序后的数组是从小到大的,如果排序后的第一个大于0,直接返回,后边直接不用看了;
② 为了避免重复结果,依次遍历的时候需要判断是否与前一个数相同,上指针也需要判断是否与前/后一个数相同
③ 双指针循环条件left<right一定要写在前边,写在后边会出现越界的情况
代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// 需要返回的结果
List<List<Integer>> result = new ArrayList<>();
int len = nums.length;
if(len<3) return result;
// 对数组进行排序
Arrays.sort(nums);
// 开始遍历
for(int i=0;i<len-2;i++){
// 如果排序后的第一个数就大于0,直接结束,因为后边的更比0大
if(nums[i]>0){return result;}
// 如果当前数和前一个数相等,直接跳过,因为属于重复数组
if(i>0 && nums[i]==nums[i-1]){continue;}
// 使用双指针
int left = i+1;
int right = len-1;
while(left < right){
// 如果符合要求
if(nums[i]+nums[left]+nums[right]==0){
// 将符合条件的添加到列表中
result.add(Arrays.asList(nums[i],nums[left],nums[right]));
// left需要遍历了,如果left后边的数值一样,left+1略过
// 注意,left<right需要写在前边,写在后边会出现outOfIndex的情况
while(left<right && nums[left]==nums[left+1]){left++;}
left++;
// right需要遍历了,如果right前边的数值一样,right-1同样略过
while(left<right && nums[right]==nums[right-1]){right--;}
right--;
}else if(nums[i]+nums[left]+nums[right]<0){
left++;
}else{
right--;
}
}
}
return result;
}
}
四数相加
题目介绍

思路讲解
看懂了三数相加,那么四数相加就是比三数多了一层遍历
1、排序,这个不用多数了,排序后是从小到大
2、第一层遍历,是确定第一个数:① 它最最小的三个数相加(即最小值)要是 > 目标值,那么后边一定大,直接结束
② 它与最大的三个数相加(即最大值)要是 < 目标值,那么跳过该轮,直接下一轮,因为最小数需要增加
③ 前两个不符合 即该遍历中 最小值 < 目标值 < 最大值,说明可能会有数能组成目标值,需要遍历了
3、第二层遍历,思路同上边的三数想加了,只不过第二层遍历是从i后边第一个数开始遍历。
(如果代码看不懂,建议多看两遍三数想加的)
代码
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
// 如果nums的长度小于4,直接返回
List<List<Integer>> result = new ArrayList<>();
int len = nums.length;
if(len<4) return result;
// 对数组进行排序
Arrays.sort(nums);
// 遍历第一个数
for(int i=0;i<len-3;i++){
// 这里是为了避免重复答案,直接略过
if(i>0 && nums[i]==nums[i-1]) continue;
// 如果最小的4个数都比目标值大,那么后边的也不用算了,肯定大
if((long)nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target) break;
// 最小的数和最大的三个数想加比目标值小,那么最小的数据需要移动了,直接进入下一轮
if((long)nums[i]+nums[len-3]+nums[len-2]+nums[len-1]<target) continue;
// 到这里说明最小的这个数,可以和后边的数组成符合目标值的组合
// 第二层遍历,先从i后边的依次遍历
// 其实到这里,就相当于是三数相加了,target-nums[i]就是三数想加的结果了
for(int j=i+1;j<len-2;j++){
// 这里又是先判断,用来去除重复答案的
if(j>i+1 && nums[j]==nums[j-1]) continue;
// 后边的就跟三数相加一样的思路了,不多解释了
if((long)nums[i]+nums[j]+nums[j+1]+nums[j+2]>target) break;
if((long)nums[i]+nums[j]+nums[len-2]+nums[len-1]<target) continue;
int left = j+1;
int right = len-1;
while(left < right){
long sum = (long) nums[i]+nums[j]+nums[left]+nums[right];
if(sum==target){
result.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
while(left<right && nums[left]==nums[left+1]){
left++;
}
left++;
while(left<right && nums[right]==nums[right-1]) {
right--;
}
right--;
}else if(sum > target){
right--;
}else{
left++;
}
}
}
}
return result;
}
}

被折叠的 条评论
为什么被折叠?



