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

思路简述

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


leetcode      双指针 哈希

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!