leetcode刷题之某数之和集锦

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;	
}

思路简述

本题主要思路就是在三数之和的基础上再套一个循环就可以了,设置四个指针,指向四个数字,然后再注意一下去重方面。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值