从两数之和到四数之和

今天终于开始刷力扣了,一刷就是两数到四数,这谁能料得到呢?菜鸡刷题都是:视频题解+讨论区题解=自己的题解。刚刚开封,有点小小の成就感~其中大部分是Java过的
在这里插入图片描述话不多说,进入正篇,从两数之和开始吧!

两数之和

传送门

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

这题无脑暴力的话,很好做,但是复杂度为O(n^2),不太行的🦆!还记得我们昨天说的宗旨吗!哦不,应该是前天了~管他呢,这个宗旨无论何时都不会变——不妨时间换空间!这题通常的空间是用的map,由于需要返回的是数组下标,所以我们把数值作为键,下标作为值(通过值去找下标)
思路很巧妙,遍历到一个元素时,如果发现target-这个元素的值在map里的话,就把这两者的下标放入一个只有俩元素的数组返回,否则,如果不在map里的话,就把遍历得到的这个元素的值和下标加入map(这是为了在后面如果遇到了它的真命天子就可以一起快乐回城啦!)

代码时间
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        if(nums.length <= 1) return res;
        HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
        for(int i = 0; i < nums.length; i++){
            int num = nums[i];
            int value = target - num;
            if(map.containsKey(value)){
                res[0] = i;
                res[1] = map.get(value);
                return res;
            }else {
                map.put(num,i);
            }
        }
        return res;
    }
}
三数之和

三数、四数就没法再利用一个数据结构去开辟空间了,需要我们自己老老实实地遍历,当然也不会非常老实地写个三重循环(见过。。找n个还真的写n重循环的,这就是后浪吗??tql(/≧▽≦)/)首先,排序;然后,适当剪枝(四数里剪枝的优势更明显);最后,返回。
其实根本思路是第一个数遍历,后面两个数弄个区间去加加减减,四数里就是再套一层遍历。
注意:要跳过相同元素
这里第一个元素的“跳”和后面区间边界的“跳”不太一样——第一个元素要跳的话,要拿自己和前一个比(从第二个元素开始);区间元素如果要跳的话,(以左边界为例)拿自己和后一个比,如果相等就跳,跳完之后还有是要++
因为如果第一个元素和后一个元素相等就continue的话,会漏解,比如[-1,-1,2],虽然第一个元素不能再是-1了,但是第二个元素还可以是-1。
区间挪移类似二分。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList();
        if(nums.length <= 2) return res;
        int n = nums.length;
        Arrays.sort(nums);
        for(int i=0;i<nums.length;i++){
            if(nums[i]>0) break; //如果第一个就>0,就没有必要了
            if(i>0&&nums[i]==nums[i-1]) continue; //去重
            int left = i+1;
            int right = n-1;
            while(left < right){
                int sum = nums[i] + nums[left] + nums[right];
                if(sum==0){
                    res.add(Arrays.asList(nums[i],nums[left],nums[right]));//巧妙!一行解决
                    while(left<right && nums[left+1]==nums[left]) left++;
                    while(left<right && nums[right-1]==nums[right]) right--;
                    left++;
                    right--;
                }else if(sum<0) left++;
                else right--;
            }
        }
        return res;
    }
}
四数之和

既然已经排好了序,就要好好利用这个顺序的优势——如果前面(最小的四个都>target了)就直接break好了,后面就不用看了,肯定更大;如果本元素加上最后面三个<target了,本轮也不用继续了,直接continue吧。
除了多套了一层循环,多了一些剪枝的操作,其他基本与上题无异。

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<>();
        if(nums.length <= 3) return res;
        Arrays.sort(nums);
        int length = nums.length;
        //k从0开始,i从k+1开始,j指向i+1,h指向最大值(最后一个元素)
        for(int k = 0; k < length-3; k++){
            if(k>0 && nums[k]==nums[k-1]) continue;//去重
            if((nums[k]+nums[k+1]+nums[k+2]+nums[k+3])>target) break;//不用看了
            if((nums[k]+nums[length-1]+nums[length-2]+nums[length-3])<target) continue;
            for(int i = k+1; i < length-2; i++){
                if(i>k+1 && nums[i]==nums[i-1]) continue;
                int j = i+1;
                int h = length-1;
                if((nums[k]+nums[i]+nums[j]+nums[j+1])>target) break;
                if((nums[k]+nums[i]+nums[h]+nums[h-1])<target) continue;
                while(j < h){
                    int curr = nums[k]+nums[i]+nums[j]+nums[h];
                    if(curr == target){
                        res.add(Arrays.asList(nums[k],nums[i],nums[j],nums[h]));
                        while(j<h && nums[j]==nums[j+1]) j++;
                        while(j<h && nums[h]==nums[h-1]) h--;
                        j++;
                        h--;
                    }else if(curr < target) j++;
                    else h--;
                }
            }
        }
        return res;
    }
}

今天打卡完成!晚上争取把“流”的博文写完!英语考试冲冲冲!tnnd马原居然用学习通手机端人脸识别监考,呜呜呜呜,展现我超凡 炒饭记忆力的时候又到了!加油!你相信自己可以你就可以!你看的《鬼灭》还有《刀剑》都极力在渲染一件事——信念的力量!现在我说起来多少有些苍白,自己去看,用心感受你就会察觉到笔者用心用力去传达的东西~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值