1.两数之和
public int[] calsum1(int[] nums,int tar) {
HashMap<Integer,Integer>map1=new HashMap<>();
for(int i=0;i<nums.length;i++) {
if(map1.containsKey(tar-nums[i])) {
int[] ans=new int[] {map1.get(tar-nums[i]),i};
return ans;
}
map1.put(nums[i],i);
}
return null;
}
解题步骤
1.设置map,其key为nums数组里的各元素,其value则为该元素对应的下标。2.遍历数组,先判断map里是否有key等于target-nums[i]。
3.如果有,返回key对应的value下标和当前遍历的下标(题目中说只有一个答案符合,把这个问题简化了)
4.如果没有,把当前nums[i]和对应的下标i存入map。
454.四数相加2
public int foursumcount(int[] a,int[] b,int[] c,int[] d) {
Map<Integer,Integer> table=new HashMap<Integer,Integer>();
for(int i=0;i<a.length;i++) {
for(int j=0;j<b.length;j++) {
int ans=a[i]+b[j];
table.put(ans, table.getOrDefault(ans, 0)+1);
}
}
int count=0;
for(int i=0;i<c.length;i++) {
for(int j=0;j<d.length;j++) {
if(table.containsKey(0-(c[i]+d[j]))) {
count+=table.get(0-(c[i]+d[j]));
}
}
}
return count;
}
思路简述
本题的解题关键就是设立一个map,其key保存ab数组任意两数之和,其value保存这个两数之和出现的次数。
然后判断这个map里是不是有key等于(0-c[i]-d[j])的,也就是等于cd数组任意两数之和的倒数。并设立一个计数器count,如果有,就加上这个key对应的value。
15.三数之和
public List<List<Integer>> threeSum(int[] nums) {
int len=nums.length;
List<List<Integer>> res=new ArrayList<>();//一开始就设置好数据格式,方便统一返回格式
if(nums==null||len<3) {
return res ;//注意!这里不能返回null,应该按照设置的格式来返回
}
Arrays.sort(nums);//排序
for(int i=0;i<len;i++) {
if(nums[i]>0) {//如果此时这个数就大于0,那么之后就不可能会等于零,直接退出就好
break;
}
// 错误去重方法,将会漏掉-1,-1,2 这种情况
/*
if (nums[i] == nums[i + 1]) {
continue;
}
*/
if(i>0&&nums[i]==nums[i-1]) {//去重,如果当前的值和前面的值相等,那么直接跳过
continue;
}
int left=i+1;
int right=len-1;
while(left<right){
int count=nums[left]+nums[i]+nums[right];
// 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
/*
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
*/
if(count>0) {//当三者之和大于0时,减少值,右指针--;
/*while(left<right&&nums[right]==nums[right-1]) {//去重,
right--;
}*/
//也可以加上上面的去重,但是会很大增加内存消耗,时间也没有快多少
//而且此时的去重不能加上left指针的去重,防止直接导致right《=left的情况
right--;
}
else if(count<0) {//当三者之和小于0,增加值,左指针++;
/*while(left<right&&nums[left]==nums[left+1]) {//去重
left++;
}*/
//也可以加上上面的去重,但是会很大增加内存消耗,时间也没有快多少
//而且此时的去重不能加上right指针的去重,防止直接导致right《=left的情况
left++;
}
else {
res.add(Arrays.asList(nums[i],nums[left],nums[right]));
// 去重逻辑应该放在找到一个三元组之后
while(left<right&&nums[left]==nums[left+1]) {//去重
left++;
}
while(left<right&&nums[right]==nums[right-1]) {//去重
right--;
}
left++;//当三者之和等于0时,左右指针同时内缩区间
right--;
}
/*去重逻辑放在最后也是不对的,此时的right和left都已经移动到下一个下标了。
* 如果要放,也是放在left++,right--前面,按照当前的指针进行去重
while(left<right&&nums[left]==nums[left+1]) {//去重
left++;
}
while(left<right&&nums[right]==nums[right-1]) {//去重
right--;
}*/
}
}
return res;
}
解题步骤
这道题最主要的思路就是排序+双指针+合理去重
1.特判,对于数组长度 n,如果数组为 null或者数组长度小于 3,返回 []。
2.对数组进行排序。因为排序之后,相同的元素会排在一起,方便进行去重。
3.遍历排序后数组:
3.1若 nums[i]>0nums[i]>0:因为已经排序好,所以后面不可能有三个数加和等于 0,直接返回结果。
3.2 对于重复元素:跳过,避免出现重复解
4.令左指针 L=i+1,右指针 R=n-1,当 L<R时,执行循环:
4.1当 nums[i]+nums[L]+nums[R]==0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 L,R移到下一位置,寻找新的解
4.2 若和大于 0,说明 nums[R] 太大,R左移,此时可以考虑是否右界是否和下一位置重复,去除重复解
4.3 若和小于 0,说明 nums[L]太小,L右移,此时可以考虑是否左界和下一位置重复,去除重复解。
18.四数之和
List<List<Integer>> res=new ArrayList<>();
int len=nums.length;
if(nums==null||len<4) {//首先进行长度判断
return res; //统一返回的数据结构
}
Arrays.sort(nums);//排序
for(int i=0;i<len-3;i++) { //i指向第一个数字,所以i<len-3即可
if(nums[i]+nums[len-3]+nums[len-2]+nums[len-1]<target) {//因为已经排序,说明本次循环最大结果也是小于target,所以直接进入下一次循环
continue;
}
if(nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target) {//因为已经排序,说明此时的i包括之后的i和剩余的三个数字相加肯定大于target了,直接跳出整个循环
break;
}
// 错误去重方法,将会漏掉-1,-1,2 这种情况,错误的原因是i在最外层,里面还有指向其他三个数的指针。不能只考虑i
/*
if (nums[i] == nums[i + 1]) {
continue;
}
*/
//正确去重指向第一个数的i指针的方法
if(i>0&&nums[i]==nums[i-1]) {
continue;
}
for(int j=i+1;j<len-2;j++) {//j指针指向第二个数字,应小于len-2;
if(nums[i]+nums[j]+nums[len-1]+nums[len-2]<target) {//同i指针的去重思路
continue;
}
if(nums[i]+nums[j]+nums[j+1]+nums[j+2]>target) {//同i指针的去重思路
break;
}
if(j>i+1&&nums[j]==nums[j-1]){//注意,这里不再是i>0,而应该是j>i+1;其余同i指针的去重思路
continue;
}
int left=j+1;//定义指向第三个数的left指针
int right=len-1;//定义指向第四个数的right指针,从数组末开始
while(left<right) {//以下的思路和三数之和基本一致,不再赘述
int count=nums[i]+nums[j]+nums[left]+nums[right];
if(count<target) {
left++;
}
else if(count>target) {
right--;
}
else {
res.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
while(left<right&&nums[left]==nums[left+1]){
left++;
//continue;
}
while(left<right&&nums[right]==nums[right-1]) {
right--;
//continue;
}
left++;
right--;
}
}
}
}
return res;
}
思路简述
本题主要思路就是在三数之和的基础上再套一个循环就可以了,设置四个指针,指向四个数字,然后再注意一下去重方面。