【算法-哈希表5】看似哈希,实则双指针。

今天,带来哈希表和双指针相关算法的讲解。文中不足错漏之处望请斧正!

理论基础点这里


四数之和

题意简化

四数之和,去重版:找不重复的四元组

  • 四元组四个元素下标不同, 和为target
  • 四元组不重复
    • 由于输出四元组的顺序没有限制, 所以四元组之间, 元素的值必须完全不同
      • 一个四元组中的元素能以任意顺序构成另一个四元组, 就称两个四元组是重复的
      • 只对a/b/c/d的某一个去重, 还会遇到重复的四元组

题意转化

在数组nums中收集所有满足条件的四元组(不能重复),四元组条件:

  • 四个元素下标不同
  • 四元素和为target

解决思路(抽象)

根据《三数之和》,我们还是选择用双指针的方法来做。
循环不断拿取四元组, 满足条件就收割(不能收割重复的结果)。

怎么拿数

怎么拿数能最快拿到结果(避免暴力遍历全部组合)?

排序,根据有序性动态控制双指针, 控制四数之和的大小, 保证自己逐渐接近结果, 而不是死板地暴力遍历所有可能性。

  • 两层循环静态拿数, 两个指针动态拿数
    • 静态拿数:i++, j++
    • 动态拿数:双指针根据四数之和与target的大小移动

怎么去重

对a/b/c/d都要去重。

对ab的去重: ab是每次固定拿取的元素, 从这里去重, 是静态去重。
解释:假如本轮的a/b和上一轮的a/b相同, 并且上一轮的a和b可以和后面的某两个元素cd组成结果集, 那么我这一轮的ab也会找到上一轮已经组合过的cd再次组合, 成为重复的结果集

对cd的去重:cd是每次动态拿取的元素, 从这里去重, 是动态去重
解释:[0, -1, -1, -1, 1, 1, 1],这个例子只有一个结果集:[0, -1, 0]当我们收获了第一个结果集[0, -1, 1]后,left和right按理讲都往里面收缩一下。但不一定只是一下,如果只收缩一下,那就可能会重复收割相同的结果集。

编程实现(具体)

剪枝有细节。

剪枝

有些朋友可能会延续三数之和的思路,直接这样剪枝:

if(nums[i] > target) break;

但这样其实是默认了a、b、c、d都是正数。本题会有这样的情况:

nums = [-4, -1, 0, 0]
target = -5

再看看,[-4, -1, 0, 0]明明是符合条件的结果集,但是nums[i](-4) > target(-5),直接break了。

所以,我们只有nums[i]target都为正数才能剪枝。

class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> result;// 排序sort(nums.begin(), nums.end());// 取固定的ab, 取动态变化的cd, 收割结果集for (int i = 0; i < nums.size(); ++i) { // 固定取a// 对a剪枝: 本题有负数, 只有二者都为正数才能这样剪枝if (nums[i] > 0 && target > 0 && nums[i] > target) break; if (i > 0 && nums[i] == nums[i - 1]) continue; // a的去重for (int j = i + 1; j < nums.size(); ++j) { // 固定取b// 对ab的和剪枝:if (nums[i] + nums[j] > 0 && target > 0 && nums[i] + nums[j] > target) break;if (j > i + 1 && nums[j] == nums[j - 1]) continue; // b的去重int left = j + 1; // 移动取c dint right = nums.size() - 1;while (left < right) { // left 和 right 移动取 cd , 收割结果集long long sum = (long long)nums[i] + nums[j] + nums[left] + nums[right]; // long long 防止相加溢出if (sum > target) --right; // 四数之和大于target, 某个数需要变小, 让right--else if (sum < target) ++left; // 四数之和小于target, 某个数需要变大, 让left++else { // 收割结果集, 并跳过相同结果集(去重)result.push_back({nums[i], nums[j], nums[left], nums[right]});while (left < right && nums[left] == nums[left + 1]) ++left; // c的去重while (left < right && nums[right] == nums[left - 1]) --right; // d的去重// left 和 right 迭代, 继续移动, 收割结果集++left;--right;                        }}}}return result;}
};

步骤概括:

  • 排序
  • fori静态取a
    • 对a剪枝
    • 对a去重, 跳过已经收割过的结果集
    • forj静态取b
      • 对a+b剪枝
      • 对b去重, 跳过已经收割过的结果集
      • left和right动态取cd
        • 四数之和小于target, 某个数需要变大, 让left++
        • 四数之和大于target, 某个数需要变小, 让right–
        • 四数之和等于target, 收割结果
          • 对cd去重
            • 因为本身就在移动找结果集, 所以取到结果后才能开始去重
          • left 和 right 迭代, 继续移动, 收割结果集
  • 返回结果集

今天的分享就到这里了,感谢您能看到这里。

这里是培根的blog,期待与你共同进步!

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

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

相关文章

MySQL之BETWEEN AND包含范围查询总结

一、时间范围 查询参数格式与数据库类型相对应时&#xff0c;between and包含头尾&#xff0c;否则依情况 当数据库字段中存储的是yyyy-MM-dd格式&#xff0c;即date类型&#xff1a; 用between and查询&#xff0c; 参数yyyy-MM-dd格式时&#xff0c;包含头尾&#xff0c;相当…

Java虚拟机(JVM)的调优技巧和实战2

JVM是Java应用程序的运行环境&#xff0c;它负责管理Java应用程序的内存分配、垃圾收集等重要任务。在JVM的默认设置下&#xff0c;可能存在一些性能问题&#xff0c;因此需要进行调优。在本次分享中&#xff0c;作者将介绍一些实用的JVM实战调优技巧&#xff0c;以提高Java应用…

JVM 监控命令详解

文章目录 JDK 中与常用命令行工具jpsjstatjinfojmap导出 dump 文件查看堆内存信息 jstack JVM 可视化分析工具 JDK 中与常用命令行工具 jps 查看当前服务器正在执行的 Java 进程 $> jps 7584 Application 16433 AdminApplication 14209 Jps 5813 Bootstrap 5575 TestApplic…

HTML+CSS+ElementUI搭建个人博客静态页面展示(纯前端)

网站演示 搭建过程 技术选取:HTML/CSS VUE2 ElementUI(Version - 2.15.14)编程软件:VSCode 环境配置与搭建 安装指令 1. 先确保你的电脑已经安装好了npm和node npm -vnode -v2. ElementUI下载&#xff0c;推荐使用 npm 的方式安装 npm i element-ui -S3. CDN引入 <!--…

根据list集合进行分页

/*** param pageInfo* param caseInfoList*/ public static Map<String, Object> resultPageList(PageInfo pageInfo, List<?> caseInfoList) {Map<String, Object> resultMap new HashMap<>();int pageSize 0;int count 0;//刚开始的页面为第一页pa…

C语言入门——第十七课

一、二分查询 1.概念 二分查询又被称为二分查找&#xff0c;是一种在有序数组或序列中快速查找到对应元素的一种方法。每次查找范围缩小至原来的一半。 ①前提条件 数组和列表必须有序&#xff0c;否则无法进行二分查找。 ②初始化 确定查找数组和列表的左边界&#xff0…

C盘变红怎么办?一个快速解决C盘快满的方法

前情提要 通常解决C盘快满的方法是&#xff1a; 找到C盘—右击选择“属性”—选择“详细信息”—卸载不常用的软件或者清除临时文件 缺点&#xff1a;成效甚微 今日重点 1.背景知识&#xff1a;微信是我们日常工作和生活都离不开的工具&#xff0c;我们每天使用微信会产生大量…

java网络编程Socket output is already shutdown

在java的网络编程中使用TCP协议在Client端和Server端循环收发消息时&#xff0c;如果用的是BufferedReader和BufferedWriter&#xff0c;出现Client端只能发送一次消息&#xff0c;当发送第二次消息时&#xff0c;Server端已经关闭的情况&#xff0c;具体报错为&#xff1a;Soc…

C 语言共用体(Union)

C 语言共用体(Union) 在本教程中&#xff0c;您将学习C语言编程中的共用体。更具体地说&#xff0c;如何创建共用体&#xff08;联合体&#xff09;&#xff0c;访问其成员以及了解共用体与组织之间的差异。共用体又被称为联合体, 和结构体同属于C语言数据类型中的结构类型。 …

Mendix与Java组件的完美结合实践

前言 在技术驱动的今天&#xff0c;应用开发的速度和质量已经成为企业竞争力的决定性因素。Mendix&#xff0c;作为一款领先的低代码开发平台&#xff0c;已经为全球数千家企业提供了快速、高效的开发解决方案。但在某些情况下&#xff0c;企业的特定需求可能超出了Mendix的标…

sqli-labs(3)

11. 看到登录框直接or 11 在hackerabar中我们可以看到这里是post传递的数据&#xff0c;在get中用--来注释后面的内容 因为get中#是用来指导浏览器动作的&#xff0c;--代表注释是空格&#xff0c;所以这里用# 之后就和get的一样了 1 order by 2 # order by 3报错 联合注入 …

21款奔驰GLS450升级23P驾驶辅助 提升安全出行

辅助驾驶越来越多的被大家所青睐&#xff01;为了提升驾驶安全性和舒适便捷性奔驰改装原厂半自动驾驶23P辅助系统 23P智能辅助驾驶系统还是很有必要的&#xff0c;因为在跑高速的时候可以使用23P智能驾驶的自动保持车速&#xff0c;保持车距&#xff0c;车道自动居中行驶以及自…

CRM商机管理软件:构建客户为中心的管理理念

企业为什么选择CRM商机管理软件&#xff1f;1.CRM软件能够帮助企业建立以客户为中心的管理理念&#xff1b;2.CRM商机管理软件全面直观的展示客户数据&#xff1b;3.市场人员可以制订个性化的营销策略&#xff1b;4.移动应用为外出的销售带来的便利。 1.构建客户为中心的管理理…

C++实现KNN和K-Means

学校机器学习课程的实验课要求实现KNN和K-Means&#xff1a; &#xff08;平时没听课&#xff09;临时去查了一下KNN和K-Means是啥&#xff0c;然后自己用C写了小例子&#xff0c;想着写都写了那就把代码贴出来吧。 顺便再聊聊自己对于这俩算法的理解。 下面是文心一言的回答…

十年诉讼,迈瑞真的赢了吗?

迁延十年&#xff0c;迈瑞与科曼的知识产权纠纷案究竟要如何解读&#xff1f; 发端于2013年&#xff0c;两家国内医疗器械行业知名公司间的专利互诉官司&#xff0c;成为全行业最具代表性的案例。但这一案例本质并不复杂&#xff1a;不过商业利益之争。 要在烈度不断抬升的市…

项目管理PMP6.0-五大过程组、十大知识领域、四十九个过程(记忆码:7664363734)

项目管理PMP6.0-五大过程组、十大知识领域、四十九个过程&#xff08;记忆码&#xff1a;7664363734&#xff09; 项目经理的影响力范围三者关系图&#xff08;五大过程组、十大知识领域、四十九个过程&#xff09;五大过程组十大知识领域十大知识领域之间联系 四十九个过程&am…

如何通过提升客户体验带来更大的增长、更好的客户留存率?

客户期望的转变 在一个日益数字化的世界里&#xff0c;有必要采取以客户为中心的思维方式。因为客户与企业互动的方式有很多是在数字空间发生的&#xff0c;客户的需求和模式已经转变。 这种情况已经酝酿了几年&#xff0c;但在2020年才打开闸门。随着疫情的爆发&#xff0c;企…

FTX的前世今生:崛起、辉煌与崩塌

FTX&#xff0c;一度被誉为加密货币领域的明星交易所&#xff0c;其快速的崛起和令人瞩目的崩塌吸引了全球的关注。让我们回顾一下FTX的前世今生&#xff0c;了解其短暂的辉煌和骤然的崩塌。 1. 崛起&#xff1a; FTX的创始人山姆班克曼-弗里德在加密货币领域具有深厚的背景和…

Linux主机间的相互免秘钥

主机间的相互免秘钥 1.生成密钥 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa运行以上命令后会在 ~/.ssh/ 目录下生成一对密钥对。 2.拷贝公钥 把自己的公钥传递给对方主机即可&#xff0c;这个公钥文件必须放在对方主机的~/.ssh/authorized_keys 文件中。 ssh-copy-id -i ~/.s…