代码随想录算法训练营第7天 | 哈希表和双指针结合、三数和四数之和

2024年7月9日

题454. 四数相加II

使用哈希表,分为两块,前两个数组找出各种情况,统计次数,时间复杂度为O($n^2$),后两个数组在找到各种情况的时候直接用哈希表去处前两个数组符合的相应次数即可。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        HashMap<Integer,Integer> map1 = new HashMap<>();
        int n = nums1.length;
        int res=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                map1.put(nums1[i]+nums2[j],map1.getOrDefault(nums1[i]+nums2[j],0)+1);
            }
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                int sum = nums3[i]+nums4[j];
                res+=map1.getOrDefault(-sum,0);
            }
        }
        return res;
    }
}

题383. 赎金信

比较普通,使用map记录第一个,然后用第二个减,如果最后减不到0就说明不够,就返回false。写代码要注意是大于还是小于。

题15. 三数之和
比较难,改了90多分钟,一开始想的用双层set对三元组去重,后来时间太长,改为标准解法。当left右侧等于left,left就进1,right左侧等于right,则right也减1。

双指针思想,多复习几次。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> list1 = new ArrayList<>();
        
        for (int i = 0; i < nums.length - 2; i++){
            if(nums[i]>0){
                return list1;
            }
            if(i>0 && nums[i]==nums[i-1]){
                continue;
            }
            int left=i+1,right=nums.length-1;
            while(left<right){
                int sum = nums[i]+nums[left]+nums[right];
                if(sum<0){
                    left+=1;
                }else if(sum>0){
                    right-=1;
                }else{
                    ArrayList<Integer> list2 = new ArrayList<>();
                    list2.add(nums[left]);
                    list2.add(nums[i]);
                    list2.add(nums[right]);
                    list1.add(list2);
                    while(left<right && nums[left]==nums[left+1]){
                        left+=1;
                    }
                    while(left<right && nums[right]==nums[right-1]){
                        right-=1;
                    }
                    left+=1;
                    right-=1;
                }
            }
        }
        
        return list1;
    }
}

题18. 四数之和

较难,写了快60分钟。基本上解法和三数之和一样,还是用双指针,外层用i和j控制,内层用left和right控制。
易错:

  • 四个数字都要分别去重,i和left和right去重方式不变,要注意j的去重的起始不是0而是i+1。
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        List<List<Integer>> list1 = new ArrayList<>();
        long sum=0;
        for(int i=0;i<nums.length;i++){
            if(i>0 && nums[i]==nums[i-1]){
                continue;
            }
            for(int j=i+1;j<nums.length;j++){
                if(j>i+1 && nums[j]==nums[j-1]){
                    continue;
                }
                int left=j+1;
                int right = nums.length-1;
                while(left<right){
                    sum = (long)nums[i]+nums[j]+nums[left]+nums[right];
                    if(sum<target){
                        left+=1;
                    }else if(sum>target){
                        right-=1;
                    }else{
                        ArrayList<Integer> list2 = new ArrayList<>();
                        list2.add(nums[i]);
                        list2.add(nums[j]);
                        list2.add(nums[left]);
                        list2.add(nums[right]);
                        list1.add(list2);
                        while(left<right && nums[right]==nums[right-1]){
                            right-=1;
                        }
                        while(left<right && nums[left]==nums[left+1]){
                            left+=1;
                        }
                        left+=1;
                        right-=1;
                    }
                }

            }
        }
        return list1;
    }
}
posted @ 2024-07-09 17:39  hailicy  阅读(2)  评论(0编辑  收藏  举报