代码随想录-刷题第七天

news/2024/7/7 21:18:27

454. 四数相加II

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

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

时间复杂度:O(n2)

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)

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)

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)

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

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



http://lihuaxi.xjx100.cn/news/1830225.html

相关文章

requests请求django接口跨域问题处理

参考&#xff1a; https://zhuanlan.zhihu.com/p/416978320 https://blog.csdn.net/SweetHeartHuaZai/article/details/130983179 使用httpx代替requests import httpxheaders {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.3…

机器学习第13天:模型性能评估指标

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 文章目录 交叉验证 保留交叉验证 k-折交叉验证 留一交叉验证 混淆矩阵 精度与召回率 介绍 精度 召回率 区别 使用代码 偏差与方差 介绍 区…

详解Rust编程中的生命周期

1.摘要 生命周期在Rust编程中是一个重要概念, 它能确保引用像预期的那样一直有效。在Rust语言中, 每一个引用都有其生命周期, 通俗讲就是每个引用在程序执行的过程中都有其自身的作用域, 一旦离开其作用域, 其生命周期也宣告结束, 值不再有效。幸运的是, 在绝大多数时间里, 生…

java实现连接linux(上传文件,执行shell命令等)

1 导入pom <dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version></dependency> 2 编写配置类 package com.budwk.app.atest;import com.budwk.app.common.config.AppExceptio…

计算机毕业设计 基于SpringBoot的无人智慧超市管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解+答疑

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Oracle SQL 注入上的 Django GIS 函数和聚合漏洞 (CVE-2020-9402)

漏洞描述 Django 于2020年3 月4日发布了一个安全更新&#xff0c;修复了 GIS 函数和聚合中的 SQL 注入漏洞。 参考链接&#xff1a; Django security releases issued: 3.0.4, 2.2.11, and 1.11.29 | Weblog | Django 该漏洞要求开发者使用 JSONField/HStoreField;此外&…

实现流量控制和熔断降级

Sentinel Sentinel 是阿里巴巴开源的一款高可用性和流量控制的分布式系统。它最初是为了解决阿里巴巴内部的微服务架构中的流量控制和熔断降级问题而开发的。Sentinel 旨在提供实时的流量控制、熔断降级、系统负载保护等功能&#xff0c;以保障应用的高可用性和稳定性。以下是…

LeetCode Hot100 102.二叉树的层序遍历

题目&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 方法&#xff1a;迭代 class Solution {public List<List<Integer>> levelOrder(TreeNode root) {if …