代码随想录算法训练营day7 | 454. 四数相加 II,383. 赎金信,15. 三数之和,18. 四数之和

news2024/11/24 4:42:12

目录

454. 四数相加 II

383. 赎金信

15. 三数之和

18. 四数之和


454. 四数相加 II

难度:medium

类型:哈希表

思路:

        本题是使用哈希法的经典题目,而0015.三数之和 (opens new window),0018.四数之和 (opens new window)并不合适使用哈希法,因为三数之和和四数之和这两道题目使用哈希法在不超时的情况下做到对结果去重是很困难的,很有多细节需要处理。

        对于本题我们使用哈希法,先将nums1和nums2遍历相加后的结果放进map,key为数组对应的和,value为该和出现的次数。然后再对nums3和nums4进行遍历相加,去map中寻找其和的相反数,若找到,就累计其value存储的出现次数。

代码:

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        // key存放nums1和nums2中元素对应和,value存放和出现的次数
        Map<Integer, Integer> map = new HashMap<>();
        int len = nums1.length;
        // 遍历nums1和nums2的元素和
        for (int i: nums1) {
            for (int j: nums2) {
                int sum = i + j;
                map.put(sum, map.getOrDefault(sum, 0) + 1);
            }
        }
        // 统计满足条件的元组数量
        int ans = 0;
        // 遍历nums3和nums4的元素和
        for (int i: nums3) {
            for (int j: nums4) {
                int sum = i + j;
                if (map.containsKey(-sum)) {
                    ans += map.get(-sum);
                }
            }
        }

        return ans;
    }
}

 复杂度分析:

  • 时间复杂度: O(n^2)
  • 空间复杂度:    O(n^2),最坏情况下A和B的值各不相同,相加产生的数字个数为 n^2

 

383. 赎金信

难度:easy

类型:哈希表

思路:

        用数组做哈希表,类似于242.有效的字母异位词,但有略微的区别。用hash存储magazine每个字母出现的次数,再遍历ransomNote元素出现的次数,hash中若有元素小于0,则说明不行;

代码:

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] hash = new int[26];

        for (int i = 0; i < magazine.length(); i++) {
            hash[magazine.charAt(i) - 'a']++;
        }
        for (int i = 0; i < ransomNote.length(); i++) {
            hash[ransomNote.charAt(i) - 'a']--;
        }
        for (int i: hash) {
            if (i < 0) {
                return false;
            }
        }
        return true;
    }
}

复杂度分析:

  • 时间复杂度: O(n)
  • 空间复杂度: O(1)

15. 三数之和

难度:medium

类型:哈希表,双指针

思路:

        因为要去重,所以使用哈希法太复杂,我们使用双指针法;

        i进行数组遍历,在每个i中,left和right分别从i+1和数组末尾相向出发;若nums[i] + nums[left] + nums[right] > 0 则right--,nums[i] + nums[left] + nums[right] < 0 则left++。

        需要注意的去重:

  •         对i去重,和后一个元素比较,为什么不是判断nums[i] == nums[i+1]呢?答:考虑[0,0,0];
  •         对right去重:若right > left && nums[right] == nums[right - 1],则right--;
  •         对left去重:同理

代码: 

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        // 二维列表存储结果
        List<List<Integer>> ans = new ArrayList<>();
        // 数组排序
        Arrays.sort(nums);
        // i遍历数组,i为三元组的第一个数
        for (int i = 0; i < nums.length - 2; i++) {
            // 剪枝,如果最小的数大于0,那么三元组的和不可能为0
            if (nums[i] > 0) {
                break;
            }
            // 对i去重,和后一个元素比较,为什么不是判断nums[i] == nums[i+1]呢?
            // 答:考虑[0,0,0]特殊情况,
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            int left = i + 1;
            int right = nums.length - 1;
            // 开始移动left和right
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                // 符合条件,存入结果列表
                if (sum == 0) {
                    ans.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    // 对right去重
                    while (right > left && nums[right] == nums[right - 1]) {
                        right--;
                    }
                    // 对left去重
                    while (right > left && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    // 去重后,还需要再移动一次才是新的元素
                    right--;
                    left++;
                } else if (sum > 0) {
                    right--;
                } else if (sum < 0) {
                    left++;
                }
            }
        }
        return ans;
    }
}

复杂度分析:

  • 时间复杂度: O(n^2)
  • 空间复杂度: O(1)

18. 四数之和

难度:medium

类型:哈希表,双指针

思路:

卡哥的四数之和解析,写得很好

        这道题是三数之和的扩展板,外面再套一层for就可以,五数之和、六数之和同理;

        注意:

  •         外面两层for都要进行去重;
  •         剪枝,如果第一个数大于target了就没必要继续寻找四元组了(num[i]如果为负数的,负数相加会得到更小的负数,所以nums[i]>0;
  •         防止溢出:long sum = (long)nums[i] + nums[j] + nums[left] + nums[right];
int的取值范围是-2,147,483,648 ~ 2,147,483,647,即-2^31 ~ 2^31-1。
long的取值范围是-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807,即-2^63 ~ 2^63-1。

        对于15.三数之和 (opens new window)双指针法就是将原本暴力O(n^3)的解法,降为O(n^2)的解法,四数之和的双指针解法就是将原本暴力O(n^4)的解法,降为O(n^3)的解法。

代码:

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ans = new ArrayList<>();
        Arrays.sort(nums);

        for (int i = 0; i < nums.length - 3; i++) {
            // 剪枝,如果第一个数大于target了就没必要继续寻找四元组了(num[i]如果为负数的,负数相加会得到更小的负数,所以nums[i]>0)
            if (nums[i] > 0 && nums[i] > target) {
                break;
            }

            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }

            for (int j = i + 1; j < nums.length - 2; j++) {
                // i变成了三数之和
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }
                int left = j + 1;
                int right = nums.length - 1;
                
                while (left < right) {
                    // int sum = nums[i] + nums[j] + nums[left] + nums[right];
                    // 防止溢出
                    long sum = (long)nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum == target) {
                        ans.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        while (left < right && nums[right] == nums[right - 1]) {
                            right--;
                        }
                        while (left < right && nums[left] == nums[left + 1]) {
                            left++;
                        }
                        right--;
                        left++;
                    } else if (sum > target) {
                        right--;
                    } else if (sum < target) {
                        left++;
                    }
                }
            }
        }
        return ans;
    }
}

复杂度分析:

  • 时间复杂度: O(n^3)
  • 空间复杂度: O(1)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/771126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

迁移 Gitee 仓库到 Github

Step1: 在Gitee找到你要迁移的仓库, 并复制 克隆|下载 链接 Step2: 打开 Github, 找到 按钮选择 Import Step3: 打开 Github, 找到 按钮选择 Import Step4: Waiting... 等待导入成功 Over~ 还有一种镜像更新的方案, Gitee 支持镜像同步, 但是我使用时无法获取到仓库名,…

开源的短视频生成和编辑工具 Open Chat Video Editor

GitHub - SCUTlihaoyu/open-chat-video-editor: Open source short video automatic generation tool

MySQL的四种主要存储引擎

目录 目录 目录 &#xff08;一&#xff09;MyISAM &#xff08;二&#xff09;InnoDB 1)自动增长列&#xff1a; 2)外键约束&#xff1a; &#xff08;三&#xff09;MEMORY &#xff08;四&#xff09;MERGE 什么是存储引擎&#xff1f; 对MySQL来说&#xff0c;它…

系列七、VMware中的CentOS服务不息屏

一、场景 VMware中安装好CentOS7等虚拟机后&#xff0c;过一段时间会自动息屏&#xff0c;这个时候如果想执行操作&#xff0c;需要重新输入 用户名/密码&#xff0c;体验感不好。 二、解决方法 应用程序》系统工具》设置》Privacy》锁屏》自动锁屏&#xff08;关闭&#xff0…

Windows11 C盘瘦身

1.符号链接 将大文件夹移动到其他盘&#xff0c;创建成符号链接 2.修改Android Studio路径设置 1.SDK路径 2.Gradle路径 3.模拟器路径 设置环境变量 ANDROID_SDK_HOME

GRE和MGRE

目录 GRE GRE环境的搭建 MGRE MGRE的配置 MGRE环境下的RIP网络 MGRE实验 VPN 说到GRE&#xff0c;我们先来说个大家熟悉一点的&#xff0c;那就是VPN技术。 背景需求 企业、组织、商家等对专用网有强大的需求。 高性能、高速度和高安全性是专用网明显的优势。 物理专…

【数据结构】时间复杂度---OJ练习题

目录 &#x1f334;时间复杂度练习 &#x1f4cc;面试题--->消失的数字 题目描述 题目链接 &#x1f334;解题思路 &#x1f4cc;思路1&#xff1a; malloc函数用法 &#x1f4cc;思路2&#xff1a; &#x1f4cc;思路3&#xff1a; &#x1f334;时间复杂度练习 &…

具有吸引子的非线性系统(MatlabSimulink实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码&Simulink仿真实现 &#x1f4a5;1 概述 要在Simulink中实现具有吸引子的非线性系统&#xff0c;可以按照以下步骤进行操作&#xff1a; 1. 打开Simulink并创建一个…

Nginx基础(复习理论篇)

一、Nginx基本概念 1、Nginx是什么 Nginx是一个高性能的Http和反向代理服务器&#xff0c;其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上Nginx的并发能力确实在同类型的网页服务器中表现较好。 Nginx专为性能优化而开发&#xff0c;性能是其最重要的考量&…

Oracle/plsql报错ORA-01932:ADMIN选项未授权给角色‘CONNECT’

情况如下&#xff1a; create user hikeytdm identified by hikeytdm default tablespace hikeytdm temporary tablespace temp; grant connect,resource,dba to hikeytdm; --grant报错ORA-01932&#xff1a;ADMIN选项未授权给角色‘CONNECT’&#xff0c;应该在cmd里或plsql里…

pytorch学习--第一个模型(线性模型)

目标 我们想通过随机初始化的参数 ω , b \omega ,b ω,b能在迭代过程中使预测值和目标值能无限接近 y ω x b y\omega xb yωxb 定义数据 x torch.rand([60, 1])*10 y x*2 torch.randn(60,1)构建模型 利用pytorch中的nn.Module 想要构建模型时&#xff0c;继承这个类…

SylixOS下SSH和SFTP连接

简要 基于网络的连接&#xff08;telnet&#xff0c;ftp&#xff09;方便高效&#xff0c;但其是基于明文的通信&#xff0c;容易被窃取、篡改和攻击&#xff0c;存在网络安全问题&#xff0c;尤其在进行远程访问时&#xff0c;穿过复杂未知的公网环境非常危险&#xff0c;为此…

linux之Ubuntu系列(八)用户管理 修改文件权限

修改文件权限 chown 修改拥有者 修改 文件|目录 的拥有者 sudo chown 用户名 文件名|目录 递归修改文件|目录的组 sudo chgrp -R 组名 文件|目录 递归修改文件权限 chmod -R xxx 文件|目录

mongoDB 分组汇总统计-执行语句(亲测)

# 注意 “gl_id” 需要分组的字段名 “gl_idlCount” 分组后获取数量的字段名&#xff08;可随意命名&#xff09; db.getCollection(集合名).aggregate([{ "$group": {"_id": {"gl_id": "$gl_id"},"gl_idlCount": { "…

一文读懂FPC(16)- 关于过孔盖油和过孔开窗的区分

FPC系列文章目录 1.什么是FPC 2.什么是R-FPC 3&#xff0c;FPC的基材 4.FPC基材压延铜和电解铜的区别 5&#xff0c;FPC的辅材 6&#xff0c;FPC常见的四种类型 7&#xff0c;FPC的生产流程简介 8&#xff0c;R-FPC的生产流程简介 9&#xff0c;FPC的发展及应用 10&a…

优思学院|六西格玛管理:依据事实的质量管理方式

一个企业的质量管理制度是否规范&#xff0c;也就是质量管理体系是否很完备的问题&#xff0c;要考察管理体系是否还有哪里不尽完美&#xff1f;各部门之间的连系、调整是否能够顺利进行&#xff1f;各自是否达成在质量保证上的任务等&#xff0c;进行质量管理体系的审核&#…

【无线通信模块】什么是PCB板载天线,PCB板载天线UART/USB接口WiFi模块

基于射频技术的无线模块需要通过天线来发射和接收电磁波信号&#xff0c;市场上常见的天线类型有陶瓷天线、板载天线、棒状天线以及外接天线&#xff0c;外接天线是通过在PCB板上预留IPEX座子&#xff0c;可选天线类型就比较多。本篇SKYLAB小编带大家了解一下板载天线的UART接口…

ROS:pluginlib

目录 一、前言二、概念三、作用四实际用例4.1需求4.2流程4.3准备4.4创建基类4.5创建插件4.6注册插件4.7构建插件库4.8使插件可用于ROS工具链4.8.1配置xml4.8.2导出插件 4.9使用插件4.10执行 一、前言 pluginlib直译是插件库&#xff0c;所谓插件字面意思就是可插拔的组件&…

vue使用docxtemplater导出word实现使用textarea输入的内容换行

注:本文只做导出word并且换行操作&#xff0c;不做vue引入docxtemplater步骤 先看一下实现效果 这是文本域输入的 这是导出来的结果 可以看出来导出来的结果也是换行的呢 接下来我们手摸手操作一下流程 首先咱们捋一捋思路 知道文本域的换行的换行标识符&#xff0c;我们发…

Spingboot 多模块引入第三方jar包

1. 在需要的模块中引入jar包 2. 在此模块中的pom.xml 中引用 3. 要想打包部署服务器&#xff0c;需要在启动模块中添加配置信息 ps&#xff1a;启动模块要引用此模块才能将此一起jar打包部署 <build><plugins><plugin><groupId>org.springframework.…