算法打卡Day07 | 哈希表篇-四数相加、赎金信、三数之和、四数之和

59 阅读3分钟

454.四数相加

题目链接:leetcode.cn/problems/4s…

关键词:降低时间复杂度,使用map存放值和个数

暴力解法就是四个for循环去遍历,为了达到更优的时间复杂度,就去两两遍历查找,复杂度为O(n²)

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        HashMap<Integer, Integer> map = new HashMap<>();
        int result = 0;
        //⏰只用到数组的值就可以使用foreach遍历,map获取没有则使用getOrDefault给出默认值
        for (int i : nums1) {
            for (int j : nums2) {
                int sum = i + j;
                map.put(sum, map.getOrDefault(sum,0)+1);
            }
        }
        // for(int i = 0; i <nums1.length; i++){
        //     for(int j = 0; j <nums2.length; j++){
        //         int count = nums1[i] + nums2[j];
        //         if(map.containsKey(count)){
        //             map.put(count, map.get(count)+1);
        //         }else{
        //             map.put(count, 1);
        //         }
        //     }
        // }
        for (int i : nums3) {
            for (int j : nums4) {
                int sum = 0 - (i + j);
                result += map.getOrDefault(sum, 0);
            }
        }
        // for(int i = 0; i <nums3.length; i++){
        //     for(int j = 0; j <nums4.length; j++){
        //         int count = 0 - (nums3[i] + nums4[j]);
        //         if(map.containsKey(count)){
        //             result += map.get(count);
        //         }
        //     }
        // }
        return result;
    }
}

383.赎金信

题目链接:leetcode.cn/problems/ra…

关键词:str1中是否包含str2

本题和有效字母异位词的区别是:有效字母异位数个数是一致的,所以只要判断最后的哈希数组有值!=0,则为false;但这里面个数是不一致的,所以就要magazine++,ransomNote--,此时有负数则说明ransomNote中有的字符在magazine中没有

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] arr = new int[26];
        if(ransomNote.length() > magazine.length()){
            return false;
        }
        for(int i=0; i<magazine.length(); i++){
            int index = magazine.charAt(i) - 'a';
            arr[index]++;
        }
        for(int i=0; i<ransomNote.length(); i++){
            int index = ransomNote.charAt(i) - 'a';
            arr[index]--;
        }
        for(int i : arr){
            if(i<0) return false;
        }
        return true;
    }
}

15.三数之和

题目链接:leetcode.cn/problems/3s…

关键词:ijk不相等;总和为0;元素不重复

双指针法、校验重复元素,先存放本次情况,下次再遇到就跳过

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //使用双指针法
        List<List<Integer>> result = new ArrayList<>();
        //先对数组排序
        Arrays.sort(nums);
        //定义遍历数组的ileftright
        for(int i = 0; i<nums.length; i++){
            if(nums[i]>0){
                return result;
            }
            //对a去重
            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }
            int left = i + 1;
            int right = nums.length - 1;
            while(right > left){
                int sum = nums[i] + nums[left] +nums[right];
                if(sum > 0){
                    right--;
                }else if(sum < 0){
                    left++;
                }else{
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    //对b、c去重
                    while(left<right && nums[right]== nums[right-1]) right--;
                    while(left<right && nums[left]== nums[left+1]) left++;
                    left++;
                    right--;
                }
            }
        }
        return result;
    }
}

18.四数之和

题目链接:leetcode.cn/problems/4s…

关键词:abcd各个下标值不相同,四元组元素不重复

剪枝+去重:相较于三数之和多了一层循环,以及此处的target可能为负数,简直操作中限制条件要>=0

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        //相较于三数之和多了一层循环
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
        for(int k = 0; k<nums.length; k++){
            //剪枝
            if(nums[k]>=0 && nums[k]>target){
                break;
            }
            //去重
            if(k>0 && nums[k] == nums[k-1]){
                continue;
            }
            for(int i = k+1; i<nums.length; i++){
                //剪枝 将k和i作为一个整体
                if(nums[k]+nums[i]>=0 && nums[k]+nums[i]>target){
                    break;
                    //⏰return result;这种写法在此处不正确!只是跳出当前这层循环!不是所有循环!
                }
                //去重
                if(i>k+1 && nums[i] == nums[i-1]){
                    continue;
                }
                int left = i+1;
                int right = nums.length-1;
                while(left < right){
                    int sum = nums[k]+nums[i]+nums[left]+nums[right];
                    if(sum > target){
                        right--;
                    }else if(sum < target){
                        left++;
                    }else{
                        result.add(Arrays.asList(nums[k], nums[i], nums[left], nums[right]));
                        while(left<right && nums[right]==nums[right-1]) right--;
                        while(left<right && nums[left]==nums[left+1]) left++;
                        right--;
                        left++;
                    }
                }
            }
        }
        return result;
    }
}