代码随想录-刷题第七天

454. 四数相加II

题目链接:454. 四数相加II

思路:哈希法。使用map集合,key存放a+b的值,value存放a+b出现的次数。使用两层循环,循环前两个数组,找出a+b,对map赋值。再用两层循环,遍历后两个数组,找出符合map中符合目标的值,并通过value获取出现的次数并累加。(其实就是将四数相加变成两数相加,将时间复杂度从O(n4)降至O(n2)

时间复杂度:O(n2)

java 复制代码
class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        int count = 0;    // 统计a+b+c+d = 0 出现的次数
        Map<Integer, Integer> map = new HashMap<>();
        // 先遍历前两个数组,将a+b以及出现的次数放到map中
        for (int a : nums1) {
            for (int b : nums2) {
                map.put(a + b, map.getOrDefault(a + b, 0) + 1);
            }
        }
        // 然后遍历后两个数组,从map中找到符合条件的a+b并计数
        for (int c : nums3) {
            for (int d : nums4) {
                if (map.containsKey(0 - (c + d))) {
                    count += map.get(0 - (c + d));
                }
            }
        }
        return count;
    }
}

383. 赎金信

题目链接:383. 赎金信

思路:哈希法。其实就是字母异位词的扩展题目,思路同字母异位词。

时间复杂度:O(n)

java 复制代码
class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        // 变向的字母异位词
        int[] count = new int[26];
        for (int i = 0; i < ransomNote.length(); i++) {
            count[ransomNote.charAt(i) - 'a']++;
        }
        for (int i = 0; i < magazine.length(); i++) {
            count[magazine.charAt(i) - 'a']--;
        }
        for (int i : count) {
            if (i > 0) {   // 仅在此处有差别
                return false;
            }
        }
        return true;
    }
}

15. 三数之和

题目链接:15. 三数之和

思路:使用双指针法。(本题的重点在于考察去重操作。)先对数组进行排序。使用i遍历一遍数组,遍历过程中,left初始为i+1,right初始为最后一个元素,然后如果left和right指向的元素符合目标值,将三个数放进结果中;如果不符合目标值,调整left和right的位置。

注意:要对三个数都进行去重操作。

i指向的是a,如果和前一个元素重复,就没必要再进行遍历了,跳过执行下一个元素。

left指向的是b,如果存入结果后,后一个元素仍然和当前元素相同,跳过后一个元素。

right指向的是c,如果存入结果后,前一个元素仍然和当前元素相同,跳过前一个元素。

通过双指针将时间复杂度由O(n3)降至了O(n2)

时间复杂度:O(n2)

java 复制代码
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        // 双指针法
        List<List<Integer>> res = new LinkedList<>();
        // 先进行排序
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            // 如果当前最小的元素都大于0了,返回res就可以了
            if (nums[i] > 0) return res;
            // 对a去重,如果和前一个元素相同,说明已经判断过了,执行下一个
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            int left = i + 1, right = nums.length - 1;
            while (left < right) {
                if (nums[i] + nums[left] + nums[right] < 0) {
                    left++;
                } else if (nums[i] + nums[left] + nums[right] > 0) {
                    right--;
                } else {
                    res.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    while (left < right && nums[left] == nums[left + 1]) { // 对b去重
                        left++;
                    }
                    while (left < right && nums[right] == nums[right - 1]) { // 对c去重
                        right--;
                    }
                    left++;
                    right--;
                }
            }
        }
        return res;
    }
}

8. 四数之和

题目链接:8. 四数之和

思路:使用双指针法,原理同三数之和。因为这次目标值可以指定为负数,所以要注意剪枝时的操作。用i和j确定a和b,用left和right寻找符合条件c和d。(同样要注意,这四个数,每个数都要进行去重操作。)

不要判断nums[k] > target 就返回了,三数之和 可以通过 nums[i] > 0 就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。比如:数组是[-4, -3, -2, -1]target-10,不能因为-4 > -10而跳过。但是我们依旧可以去做剪枝,逻辑变成nums[i] > target && (nums[i] >= 0 || target >= 0)就可以了。

四数之和的双指针解法是两层for循环nums[k] + nums[i]为确定值,依然是循环内有left和right下标作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况。

那么一样的道理,五数之和、六数之和等等都采用这种解法。

时间复杂度:O(n3)

java 复制代码
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        // 双指针法,类似三数之和
        List<List<Integer>> res = new LinkedList<>();
        // 先排序
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > target && (nums[i] >= 0 || target >= 0)){
                // 剪枝操作
                return res;
            }
            if (i > 0 && nums[i] == nums[i - 1]) { // 对a去重
                continue;
            }
            for (int j = i + 1; j < nums.length; j++) {
                if (j > i + 1 && nums[j] == nums[j - 1]) // 对b去重
                    continue;
                int left = j + 1, right = nums.length - 1;
                while (left < right) {
                    if (nums[i] + nums[j] + nums[left] + nums[right] < target) {
                        left++;
                    } else if (nums[i] + nums[j] + nums[left] + nums[right] > target) {
                        right--;
                    } else {
                        res.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        while (left < right && nums[left] == nums[left + 1]) {
                            // 对c去重
                            left++;
                        }
                        while (left < right && nums[right] == nums[right - 1]) {
                            // 对d去重
                            right--;
                        }
                        left++;
                        right--;
                    }
                }
            }
        }
        return res;
    }
}

哈希表题目总结

从哈希表的理论基础到数组、set和map的经典应用,把哈希表的全貌呈现出来。

同时也强调虽然map是万能的,详细介绍了什么时候用数组,什么时候用set

相信通过代码随想录中的哈希表总结篇,大家可以对哈希表有一个全面的了解。


相关推荐
penguin_bark4 分钟前
69. x 的平方根
算法
一休哥助手14 分钟前
Redis 五种数据类型及底层数据结构详解
数据结构·数据库·redis
这可就有点麻烦了14 分钟前
强化学习笔记之【TD3算法】
linux·笔记·算法·机器学习
救救孩子把15 分钟前
深入理解 Java 对象的内存布局
java
落落落sss17 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
苏宸啊20 分钟前
顺序表及其代码实现
数据结构·算法
万物皆字节23 分钟前
maven指定模块快速打包idea插件Quick Maven Package
java
lin zaixi()23 分钟前
贪心思想之——最大子段和问题
数据结构·算法
FindYou.24 分钟前
C - Separated Lunch
算法·深度优先
夜雨翦春韭29 分钟前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法