算法练习day7

news2024/11/20 11:25:49

四数相加II

代码随想录 0454.四数相加II

454. 四数相加 II - 力扣(LeetCode)

(用时:0.5小时)

思路

本道题是需要在四个数组中,各找一个数,这些数加起来能够等于0,那么就是答案元组。各个数组的数字元组中的位置是固定的,0001和1000是不同的答案。

普通的解法一般是四重循环遍历,逻辑简单粗暴就不再赘述。

这道题可以用哈希表配合进行求解。

  • 先算前两个数组元素相加的结果,将他们的结果存入哈希表中,这里是一个二重循环。

    对于前两个数而言,1 2和2 1他们的和虽然都是3,但是情况是不一样的,属于3的情况出现了两次。题目要输出答案元组的个数,因此选择使用hashset。

  • 接着再算后两个数组元素相加结果,通过hashset查找前两个数的和中符合条件的,组成一个完整的答案元组。在此过程中用计数器累加即可。

错误

思路理解的差不多,但是在写的时候,一些细节方面还是出了问题:

  1. 累加时,累加的数值出现问题。

  2. (疑问)hashset的key和value取什么

个人理解如下:

  • (疑问)hashset的key和value取什么

    hashset是用来记录前两个数字的和出现情况的。那么key应该是两个数字的和,value应该是这个和出现的频率(次数)。

  • 累加时,累加的数值出现问题。

    前面说了,hashset记录的是前两个数字的和出现的频率,那么在累加的时候,应该是要加上频率(次数)而非单纯的加一。

代码实现

hashset实现:

public int FourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4)
{
    int ans = 0, temp;
    Dictionary<int, int> dic = new Dictionary<int, int>();
​
    //记录前两位相加的结果出现的频率
    foreach (int num1 in nums1)
    {
        foreach (int num2 in nums2)
        {
            if(dic.ContainsKey(num1 + num2))
            {
                dic[num1 + num2]++;
            }
            else
            {
                dic.Add(num1 + num2, 1);
            }
        }
    }
​
    //计算后两位相加的结果,通过这个结果与最终结果的差值查找是否有前两位的和匹配
    foreach(int num3 in nums3)
    {
        foreach(int num4 in nums4)
        {
            temp = 0 - num3 - num4;
​
            if(dic.ContainsKey(temp))
            {
                ans+= dic[temp];
            }
        }
    }
​
    return ans;
}

赎金信

代码随想录 0383.赎金信

383. 赎金信 - 力扣(LeetCode)

(用时:0.3小时)

思路

本题和前面一道四数相加II有点像,只是这道题的变成了两个。

magazine 中的每个字符只能在 ransomNote 中使用一次,那么就不是查看元素出现的频率,而是单纯查看是否出现即可。

字母一共26个(题目假设只看小写)并不多,故用数组实现哈希表。

错误

这道题是比较简单的题,但是在一些细节方面还是出了问题:

  1. 看错题,以为是要查看字母出现的频率。

  2. 要先处理magazine再处理ransomNote。

个人理解如下:

  • 看错题,以为是要查看字母出现的频率。

    这个问题就没什么好说的了。。。查看字母的频率用键值对结构(dictionary)、查看字母是否出现用hashset。数组结构两种都可以用,用数组要看这个表会有多大。

  • 要先处理magazine再处理ransomNote。

    题目意思是检验ransomNote的字母在magzine的情况(magazine 中的每个字符只能在 ransomNote 中使用一次)。那么magzine要么是包含ransomNote的关系(返回true),要么就是不匹配的关系(返回false)。

    先得得到magzine的元素,再探究ransomNote所有的元素是否在ransomNote出现,且magzine的字母只用一次。

代码实现

/// <summary>
/// 哈希数组实现
/// </summary>
/// <param name="ransomNote"></param>
/// <param name="magazine"></param>
/// <returns></returns>
public bool CanConstruct(string ransomNote, string magazine)
{
    int[] hash = new int[26];
​
    for (int i = 0; i < magazine.Length; i++)
    {
        hash[magazine[i] - 'a']++;
    }
​
    for (int i=0;i<ransomNote.Length;i++)
    {
        hash[ransomNote[i] - 'a']--;
    }
​
    for (int i=0;i<hash.Length;i++)
    {
        if (hash[i]<0)
        {
            return false;
        }
    }
​
    return true;
}

三数之和

代码随想录 0015.三数之和

15. 三数之和 - 力扣(LeetCode)

(用时:1小时)

思路

和前面的四数相加II不同,本道题是在一个数组中找答案,答案元组不能重复(例如123 和321其实是一个元组)

本题的重点在于去重。

题目是在哈希表章节出现的,去重、唯一性第一反应是用哈希表做。卡哥并没有讲解哈希的方法,因为去重很麻烦

  • 哈希的思路应该是先求出前两项a+b的和,再通过答案和哈希表查找第三项c是否存在。

  • 哈希的结构中,hashset是只记录是否存在,不记录存在次数的,那么可能出现,1 2 1,而1只出现过一次,同一个元素被多次使用。此时感觉可以用键值对的类型来记录出现次数?

  • 但是如果要记录次数,就得配合其他的变量使用。比如让某个数字使用了一次值就--,这是循环一轮时的操作,在新一轮的值又得恢复原本的值。。。这里就很麻烦。

  • 此外,用记录出现次数的键值对类型来做也要额外去重(这里就是卡哥说的去去重麻烦),额外对答案列表中重复的元组去重。

  • 去重的方式其实就是来个二重循环,定一个元组,然后对其他的元组进行遍历比较。这里元组中数字的顺序还不一样,意味着if的条件不能单纯的num1[i]==num2[i]这种,还得处理。

卡哥讲授的是双指针的方法。

  • 一重循环探索确定第一项数字a。

  • 循环中用left和right分别对数字a后的区域进行收缩判断。

  • 这个方法的数组要是有序的。

  • 这中间加上数字a的去重和剪枝操作。

总结来说:

  • 先对数组排序,这里的思路是认为数组升序。

  • 排序后,最外层的循环遍历数字a的情况。

    遍历过程中对数字a进行去重,如果此时a的数值已经出现过了,那就向后遍历(因为是有序的,重复的数字会连续出现)。

    还可以对数字a剪枝。题目的和固定为是0,那么如果数字a大于0,那么该数组不可能会有答案元组(因为是升序的,数字a是三个数字中最小的)

  • 在确定数字a后,用left和right分别表示数组后续剩下的区域,对这块区域进行收缩。

  • 收缩过程中,如果找到了合适的值就可保留下来。

    若nums[i] + nums[left] + nums[right] == 0,表示这组答案是可以的,记录下来即可,然后两个指针一起收缩。 若<0,表示目前的有值有点小,那么让left++即可(数组升序) 若>0,表示目前的有值有点大,那么让right--即可(同理)

  • 收缩过程中,要对left和right对应的值进行去重。

    相同的数值是连续出现的,让left和right指向的值和相邻值不同,即可达到去重的目的。

    需要注意的是,去重是在该答案已经有了的情况下才需要对left和right接下来的值进行去重。这说明left和right的去重是要在答案元组被记录下来后的(卡哥提到的“先记录下来再去重”)

疑问点

看完视频和讲解,对解法还是有一些质疑:

  1. 疑问1:为什么找到答案时,双指针同时收缩?

  2. 疑问2:right和left的去重逻辑和双指针收缩顺序的问题?

  3. 疑问3(错误):数字a的剪枝

个人理解如下:

  • 为什么找到答案时,双指针同时收缩?

    找到答案后,i、left和right的值都是固定的。如果只是收缩left或right,加法式子中其中两个加数不变,那么另一个加数的值也应该是固定的,那么此时这组答案应该有了就重复了。

  • right和left的去重逻辑和双指针收缩顺序的问题?

    这里个人认为放在前后都行。

    卡哥是先去重,再收缩。收缩比较的是left和left+1(right和right-1)。我个人是right和left的去重逻辑放在双指针收缩前,收缩比较的是left和left-1(right和right+1)。这里顺序与收缩逻辑对应一下就可以了。

  • 数字a的剪枝

    这里在写程序时也出现了错误(但是因为是前一天做的,现在忘了这里是怎么错的。。。放上来当作巩固吧)。结果要求是0,数组是升序,那么如果第一个数都大于了0,此数组中想要三个数相加为0是无解的。

代码实现

双指针法:

/// <summary>
/// 双指针法
/// </summary>
/// <param name="nums"></param>
/// <returns></returns>
public IList<IList<int>> ThreeSumFun1(int[] nums)
{
    IList<IList<int>> ans = new List<IList<int>>();
    int left, right;
​
    Array.Sort(nums);
​
    for (int i = 0; i < nums.Length; i++)
    {
        if (nums[i] > 0) return ans;
​
        if (i > 0 && nums[i] == nums[i - 1]) continue;
​
        left = i + 1;
        right = nums.Length - 1;
​
        while (left < right)
        {
            if (nums[i] + nums[left] + nums[right] == 0)
            {
                ans.Add(new List<int> { nums[i], nums[left], nums[right] });
                left++;
                right--;
​
                while (left < right && nums[left] == nums[left - 1]) left++;
                while (left < right && nums[right] == nums[right + 1]) right--;
            }
            else if (nums[i] + nums[left] + nums[right] < 0)
            {
                left++;
            }
            else
            {
                right--;
            }
        }
​
    }
    return ans;
}

四数之和

代码随想录 0018.四数之和

18. 四数之和 - 力扣(LeetCode)

(用时:2小时)

思路

这道题的思路是在前一道三数之和的基础上的。

三数之和中,哈希法太过复杂,因此卡哥优先讲解的是双指针法,这道题依旧使用的是双指针法。由于多了一个数,因此循环需要多加一层。

本道题就是先确定前两个数字ab,然后依旧用left和right收缩。

错误

写的时候错了一些:

  1. 错误1:b剪枝操作的返回值出了问题

个人理解如下:

  • b剪枝操作的返回值出了问题

    在三数之和时,只有一层循环因此在剪枝时,直接让整个函数返回列表也是可以的。这个想法延续要了四数之和,四数之和的第一层循环是和三数一样,因此没有出问题,但是第二层循环不能这么写。

    以力扣报错的 -3, -2, -1, 0, 0, 1, 2, 3 这组数据为例。一共是8组答案,程序只判断出了7组,落了一组。经过调试,发现是在-2 0 0 2 这组答案出现后,后面一组的答案没有出现,下图是出现问题前记录的一组答案:

    image-20240510121123236

    接着往后继续调试,在某一步中,发现第二层循环对b的剪枝操作让函数直接跳出了。

    image-20240510121256764

    查看后发现,i和j下标对应的数组值相加后恰好大于target且他们也大于0。但是后续的-1 0 0 1也是一组答案,这里由于b剪枝的原因直接跳过了。这里就是问题所在。

    image-20240510121339577

代码实现

双指针法:

/// <summary>
/// 双指针法
/// </summary>
/// <param name="nums"></param>
/// <param name="target"></param>
/// <returns></returns>
public IList<IList<int>> FourSumFun(int[] nums, int target)
{
    IList<IList<int>> ans = new List<IList<int>>();
    int left, right;
​
    Array.Sort(nums);
    for (int i=0;i<nums.Length;i++)
    {
        //a剪枝操作
        if (nums[i] > 0 && nums[i] > target) break;
​
        //a去重操作
        if (i > 0 && nums[i] == nums[i - 1]) continue;
​
        for (int j=i+1;j<nums.Length;j++)
        {
            //b剪枝操作
            if (nums[i] + nums[j] > 0 && nums[i] + nums[j] > target) break;
​
            //b去重操作
            if (j > i + 1 && nums[j] == nums[j - 1]) continue;
​
            left = j + 1;
            right = nums.Length-1;
​
            while(left<right)
            {
                if (nums[i] + nums[j] + nums[left] + nums[right] == target)
                {
                    ans.Add(new List<int>() { nums[i], nums[j], nums[left], nums[right] });
​
                    left++;
                    right--;
​
                    //去重
                    while (left < right && nums[left] == nums[left - 1]) left++;
​
                    //去重
                    while (left < right && nums[right] == nums[right + 1]) right--;
                }
                else if (nums[i] + nums[j] + nums[left] + nums[right] < target)
                {
                    left++;
                }
                else
                {
                    right--;
                }
            }
        }
    }
​
​
    return ans;
}

后记

前三道题是在昨天(5.9)写的,没来得及文字记录。最后一道题和文字记录都是今天(5.10)写的。

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

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

相关文章

ChatGPT未来可能应用于iPhone?

苹果接即将与OpenAI达成协议 ChatGPT未来应用于iPhone 前言 就在5月11日&#xff0c;苹果公司正与OpenAI进行深入讨论&#xff0c;计划在其最新的iOS操作系统中整合OpenAI的先进技术。这一举措是苹果公司在为其产品线融入更先进的人工智能功能所做努力的一部分。 目前情况双方…

Vue路由拆分

1.在src下建立router&#xff0c;在router中建立文件index 2.将main.js中部分内容复制 App <template> <div><a href"#/friend">朋友</a><br><a href"#/info">信息</a><br><a href"#/music&quo…

源代码防泄密的重要性

​源代码”作为互联网企业的核心资产之一&#xff0c;其安全性至关重要。源代码泄露不仅可能导致企业丧失技术优势&#xff0c;还可能引发知识产权纠纷、增加竞争对手的市场竞争力&#xff0c;甚至可能被用于恶意目的&#xff0c;如开发恶意软件等。因此&#xff0c;保护源代码…

没有公网ip,如何实现外网访问内网?

目前拨号上网是最广泛的上网方式&#xff0c;这种方式优点是价格便宜&#xff0c;缺点是没有固定公网ip&#xff0c;每次重新您拨号ip地址都会变。如果有一台服务器&#xff0c;需要实现外网访问&#xff0c;在没有固定公网ip的环境下&#xff0c;该如何实现呢&#xff1f;使用…

apk反编译修改教程系列-----让你反编译apk中 事半功倍的辅助编译软件列举【十六】

在反编译apk中。排除我们常用的编译软件外。还有很多辅助编译软件。例如用来查看代码 转换语言 加解密算法 文件监听 弹窗定位 activity记录 签名验证 dex文件混淆 签校测试 apk伪加密 apk对齐 拆分dex 合并dex 等等类似的功能 通过此课程了解; 01----反编译软件中列…

哪些软件格式在win跟linux上都能运行?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「linux的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 有一些软件格式在Windows和Li…

基于yolov8的水果检测系统,系统既支持图像检测,也支持视频和摄像实时检测(pytorch框架)【python源码+UI界面+功能源码详解】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; 基于yolov8的水果检测系统&#xff0c;系统既支持图像检测&#xff0c;也支持视频和摄像实时检测_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov8的水果检测系统是在pytorch框架下实…

JAVA毕业设计139—基于Java+Springboot+Vue的农产品销售商城(源代码+数据库+万字论文)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的农产品销售商城(源代码数据库万字论文)139 一、系统介绍 本项目前后端分离&#xff0c;分为管理员、用户两种角色 1、用户&#xff1a; 注册登录、农产品…

【hana】hana1.0多容器常用命令

基础命令 数据库 连接数据库 hdbsql -u system -p {passwd} -i 02 -d {dbname}查询所有数据库 SELECT DATABASE_NAME, ACTIVE_STATUS FROM M_DATABASES;停止数据库&#xff0c;会修改数据库状态为No ALTER SYSTEM STOP DATABASE testdb; 启动数据库&#xff0c;会修改数据…

租用香港Windows服务器要注意的几种安全防护措施

在网络世界里&#xff0c;永远没有绝对的安全&#xff0c;但我们可以通过采取适当的措施使风险降低。对于选择香港Windows服务器租赁的企业和个人来说&#xff0c;保护数据的安全性与隐私至关重要。下面将介绍几种关键的租用香港Windows服务器时应注意的安全防护措施。 1.使用本…

美颜滤镜SDK解决方案,稳定可靠,易于集成

高质量的视觉体验已成为企业吸引用户、提升品牌形象的关键&#xff0c;美摄科技凭借其领先的美颜滤镜SDK技术&#xff0c;为企业提供了从人像美颜到多元场景处理的全方位解决方案&#xff0c;助力企业轻松实现视觉升级。 一、强大能力&#xff0c;覆盖多场景 美摄科技美颜滤镜…

使用JavaScript日历小部件和DHTMLX Gantt的应用场景(二)

DHTMLX Suite UI 组件库允许您更快地构建跨平台、跨浏览器 Web 和移动应用程序。它包括一组丰富的即用式 HTML5 组件&#xff0c;这些组件可以轻松组合到单个应用程序界面中。 DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足项目管理应用…

微软如何打造数字零售力航母系列科普09 - 什么是Dynamics 365 Customer Insight 以及如何使用它?

什么是Dynamics 365 Customer Insight(客户见解)以及如何使用它? 新的Dynamics 365 Customer Insights平台在Microsoft Inspire 2023上推出&#xff0c;为CX创新者提供了对组合客户数据平台&#xff08;CDP&#xff09;和旅程编排工具的访问。 更新后的解决方案于2023年9月首…

特产销售|基于Springboot+vue的藏区特产销售平台(源码+数据库+文档)​

目录 基于Springbootvue的藏区特产销售平台 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道…

课程设计 大学生竞赛系统

课程设计 大学生竞赛系统 wx:help-assignment 学生用户&#xff1a; wx:help-assignment 首页&#xff1a;推荐一些竞赛&#xff0c;热门活动等&#xff1b; 广场&#xff1a;用户可以通过广场来发表动态&#xff0c;同时也可以查看别人发布的动态&#xff0c;并且可以 关注…

智慧公厕管理系统的四层架构:感知层、传输层、平台层和应用层

智慧公厕管理系统是一种利用先进技术实现智能化管理和优化厕所体验的创新解决方案。该系统采用复杂的架构&#xff0c;涵盖了多个应用子系统&#xff0c;致力于提高公厕的卫生状况、资源利用效率、安全性以及用户体验。本文将以智慧公厕源头实力厂家广州中期科技有限公司&#…

网络安全专业岗位详解+自学学习路线图

很多网安专业同学一到毕业就开始迷茫&#xff0c;不知道自己能去做哪些行业&#xff1f;其实网络安全岗位还是蛮多的&#xff0c;下面我会介绍一些网络安全岗位&#xff0c;大家可以根据自身能力与喜好决定放哪个方向发展。 渗透测试/Web安全工程师 主要是模拟黑客攻击&#…

WP All Import Pro插件下载 - 一键导入,无限可能

在当今快节奏的数字时代&#xff0c;网站内容的更新和管理是每个网站管理员和开发者的日常工作。但是&#xff0c;传统的手动更新方法不仅耗时&#xff0c;而且容易出错。现在&#xff0c;有了WP All Import Pro&#xff0c;这一切都将改变。 WP All Import Pro 是一款专为Wor…

认识设计模式SOLID原则

SOLID 是一个缩写词&#xff0c;代表面向对象编程 (OOP) 的五个设计原则&#xff0c;旨在促进更简单、更健壮和可更新的代码。 SOLID 缩写中的每个字母都代表了开发易于维护和随时间扩展的软件的原则。 SOLID原则是面向对象编程和设计的五项基本指导原则&#xff0c;由罗伯特C…