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

系列文章目录


目录

  • 系列文章目录
  • 454.四数相加II
    • 使用HashMap法
  • 383.赎金信
    • 哈希解法(数组)
  • 15.三数之和
    • 双指针法
  • 18.四数之和
    • 双指针法


454.四数相加II

题解:该题和1.两数之和的方法是一样的,这个题的难点在于keyvalue分别是什么。key是相加的值,value是这个值出现的次数。怎么计算这个值出现的次数又是另一个难点了。需要用到Map接口的getDoDefault方法,getOrDefault(key,0):找到key对应的value,如果key不存在,就返回0

使用HashMap法

import java.util.HashMap;

//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        HashMap<Integer, Integer> map = new HashMap<>();
        //统计两个数组中的元素之和,同时统计出现的次数,放入map
        for (int i = 0; i < nums1.length; i++) {
            for (int j = 0; j < nums2.length; j++) {
                int sum = nums1[i] + nums2[j];
/*                if (!map.containsKey(sum)) {//如果没加过该key
                    map.put(sum, 1);
                } else {//加过该key则替换value值,将value+1
                    map.put(sum, map.get(sum) + 1);
                }*/
                map.put(sum, map.getOrDefault(sum, 0) + 1);
            }
        }

        //统计剩余的两个元素的和,在map中找是否存在相加为0的情况,同时记录次数
        int count = 0;
        for (int i = 0; i < nums3.length; i++) {
            for (int j = 0; j < nums4.length; j++) {
                int sum = nums3[i] + nums4[j];
                if (map.containsKey(-sum)) {
                    count += map.get(-sum);
                }
            }
        }
        return count;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

注:统计key值出现的次数,有两种方法改变value值。
①利用只能加入一个key,若重复加入key则替换value来实现。

if (!map.containsKey(sum)) {//如果没加过该key
    map.put(sum, 1);
} else {//加过该key则替换value值,将value+1
    map.put(sum, map.get(sum) + 1);
}

②通过getDoDefault方法实现。(快一些)

map.put(sum, getOrDefault(sum, 0) + 1);

383.赎金信

题解:因为两个字符串都是由小写字母组成的,所以说数据的范围是确定的,那么就可以用数组结构。用每个字符对应其数组下标,数组值就是每个字母出现的次数,最后遍历另一个字符串,需要的字母就-1,最后看结果数组的是否有负值,有负值说明字母是不够的,返回false

哈希解法(数组)

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        //剪枝
        if (ransomNote.length() > magazine.length()) {
            return false;
        }

        int[] record = new int[26];
        //遍历第一个字符串,通过record数据记录 magazine里各个字符出现次数
        for (int i = 0; i < magazine.length(); i++) {
            record[magazine.charAt(i) - 'a']++;
        }
        /*//遍历ransomNote+判断数组值是否为负
        for (int i = 0; i < ransomNote.length(); i++) {
            if(--record[ransomNote.charAt(i)-'a']<0){//只要有一个数组值为负数,就返回false
                return false;
            }
        }*/
        // 遍历ransomNote,在record里对应的字符个数做--操作
        for (int i = 0; i < ransomNote.length(); i++) {
            record[ransomNote.charAt(i) - 'a']--;
        }
        //判断数组值是否为负
        for (int i = 0; i < record.length/*ransomNote.length()*/; i++) {
            // 如果小于零说明ransomNote里出现的字符,magazine没有
            if (record[i]/*record[ransomNote.charAt(i) - 'a']*/ < 0) {
                return false;
            }
        }
        return true;
    }
}

在这里插入图片描述
注:从字符到数组下标的映射比较耗时间,故最后判断数组值是否为负时直接遍历record数组即可,不要再映射了。


15.三数之和

题解:在同一个数组中找一个三个数(这三个数的下标不同),相加和为0这个三元组不能重复,但里面的元素可以重复。如果数组是 [0,0,1,1,-1,-1,-2],则 [0,1,-1][0,1,-1]不合法,但是[1,1,-2]合法。

双指针法

import java.util.ArrayList;
import java.util.Arrays;

//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //注意题目中方法要求返回<List<Integer>>泛型
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
        // 找出a + b + c = 0
        // a = nums[i], b = nums[left], c = nums[right]
        for (int i = 0; i < nums.length; i++) {
            // 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
            if (nums[i] > 0) {
                return result;
            }

            //去重a
            //一定要有i>0条件,因若i=0,此时nums[i-1]=-1,数组越界异常
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;//跳过本次循环进入下次循环,不能i++因还会执行本次循环
            }

            int left = i + 1;
            int right = nums.length - 1;
            while (left < right) {
                //剪枝:排序之后如果最后一个元素小于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
                if(nums[right]<0){
                    System.out.println("1111");
                    return result;
                }
                if (nums[i] + nums[left] + nums[right] > 0) {
                    right--;
                } else if (nums[i] + nums[left] + nums[right] < 0) {
                    left++;
                } else {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    // 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
                    while (left < right && nums[right] == nums[right - 1]) right--;
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    right--;
                    left++;
                }
            }
        }
        return result;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

注:①题目中方法要求返回<List<Integer>>泛型,故在创建ArrayList时要注意。
Arrays类里面包含了一系列静态方法,用于管理或操作数组,故调用sort方法对数组进行自然排序。
在这里插入图片描述
③剪枝操作:排序后,在遍历数组时,

  1. 如果三个数中最小的数即a=nums[i]已经>0,则已不可能三个数之和为0,故可直接退出。

           for (int i = 0; i < nums.length; i++) {
                //剪枝:排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
                if (nums[i] > 0) {
                    return result;
                }
                ...
           }
    
  2. 如果最后一个元素c=nums[right]已经<0,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了。

           while (left < right) {
               //剪枝:排序之后如果最后一个元素小于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
               if(nums[right]<0){
                   System.out.println("1111");
                   return result;
               }
               ...
           }
    

④对a进行去重时,一定要有i>0条件,因若i=0,此时nums[i-1]=-1,数组越界异常。
在这里插入图片描述
⑤对b=nums[left],c=nums[right]的去重操作。

  1. 放在找到三元组之前,[0,0,0] 的情况,可能直接导致 right<=left 直接退出循环了,此时还没加入一个三元组,从而漏掉了[0,0,0]这种三元组。

    while (left < right) {
         // 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
         /*
         while (right > left && nums[right] == nums[right - 1]) right--;
         while (right > left && nums[left] == nums[left + 1]) left++;
         */
         if (...)
         ...
    }
    
  2. 去重逻辑应该放在找到一个三元组之后,对b、c去重。此时判断right是否与左边元素相等,若相等则跳过该左边的元素;判断left是否与右边元素相等,若相等则跳过该右边的元素。最后两行的 right--; left++;不管b、c有没有重复都得有,其意味着三元组此时已经=0,不论单独移动哪一边,都不会再有=0的情况了,故必须得同时移动。
    在这里插入图片描述

  3. 很多同学写本题的时候,去重的逻辑多加了 对rightleft 的去重:nums[right] == nums[right + 1]其实比较的还是当前right指针即right + 1与左边元素right,因前面有个 right--;,已经将right指针左移了,此时指向的是左边元素。nums[left] == nums[left - 1]同理。

    while (right > left) {
        if (nums[i] + nums[left] + nums[right] > 0) {
            right--;
            // 去重 right
            while (left < right && nums[right] == nums[right + 1]) right--;
        } else if (nums[i] + nums[left] + nums[right] < 0) {
            left++;
            // 去重 left
            while (left < right && nums[left] == nums[left - 1]) left++;
        } else {
        }
    }
    

    在这里插入图片描述
    因此时是在!=0的条件下去重的,不论是right还是left,即使去重了,去重后得到的rightleft指针还是指向三元组!=0的元素。

在这里插入图片描述


18.四数之和

双指针法

在这里插入图片描述


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络建设与运维培训介绍和能力介绍

1.开过的发票 3.培训获奖的证书 4合同签署 5.实训设备

垃圾回收器介绍

java堆内存结构包括&#xff1a;新生代和老年代&#xff0c;其中新生代由一个伊甸区和2个幸存区组成&#xff0c;2个幸存区是大小相同&#xff0c;完全对称的&#xff0c;没有任何差别。我们把它们称为S0区和S1区&#xff0c;也可以称为from区和to区。 JVM的垃圾回收主要是针对…

Spring具体拓展点:后置处理器

一图胜千言 mermaid示例图&#xff1a; #mermaid-svg-YEqFb5JcEk5FWkwO {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-YEqFb5JcEk5FWkwO .error-icon{fill:#552222;}#mermaid-svg-YEqFb5JcEk5FWkwO .error-text{fi…

详细分析Mysql中的LOCATE函数(附Demo)

目录 1. 基本概念2. Demo3. 实战 1. 基本概念 LOCATE()函数在SQL中用于在字符串中查找子字符串的位置 它的一般语法如下&#xff1a; LOCATE(substring, string, start)LOCATE()函数返回子字符串在主字符串中第一次出现的位置 如果未找到子字符串&#xff0c;则返回0 具体的…

stm32学习笔记:SPI通信协议原理(未完)

一、SPI简介(serial Peripheral Interface&#xff08;串行 外设 接口&#xff09;) 1、电路模式&#xff08;采用一主多从的模式&#xff09;、同步&#xff0c;全双工 1 所有SPI设备的SCK、MOSI、MISO分别连在一起 2 主机另外引出多条SS控制线&#xff0c;分别接到各从机的S…

数据集成工具 ---- datax 3.0

1、datax: 是一个异构数据源离线同步工具&#xff0c;致力于实现关系型数据库&#xff08;mysql、oracle等&#xff09;hdfs、hive、hbase等各种异构数据源之间的数据同步 2、参考网址文献&#xff1a; https://github.com/alibaba/DataX/blob/master/introduction.mdhttps:/…

代码随想录算法训练营Day46 ||leetCode 139.单词拆分 || 322. 零钱兑换 || 279.完全平方数

139.单词拆分 class Solution { public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string> wordSet(wordDict.begin(), wordDict.end());vector<bool> dp(s.size() 1, false);dp[0] true;for (int i 1; i < s.size(); …

【Linux】-Linux下的软件商店yum工具介绍(linux和windows互传文件仅仅一个拖拽搞定!!!!)

目录 1.Linux 软件包管理器yum 1.1快速认识yum 1.2 yumz下载方式&#xff08;如何使用yum进行下载&#xff0c;注意下载一定要是root用户或者白名单用户&#xff08;可提权&#xff09;&#xff09; 1.2.1下载小工具rzsz 1.2.2 rzsz使用 1.2.2查看软件包 1.3软件的卸载 2.yum生…

三、HarmonyOS 应用开发入门之运行Hello World

目录 1、课程对象 1.1、有移动端开发经验 1.2、无移动端开发经验 1.3、对 HarmonyOS 感兴趣 2、DevEco Studio 的使用 2.1、DevEco Studio 的关键特性 智能代码编辑 低代码开发 多段双向实时预览 多端模拟仿真 2.2、安装配置 DevEco Studio 2.2.1、官网开发工具下载地…

蓝桥杯真题讲解:三国游戏(贪心)

蓝桥杯真题讲解&#xff1a;三国游戏&#xff08;贪心&#xff09; 一、视频讲解二、正解代码 一、视频讲解 蓝桥杯真题讲解&#xff1a;三国游戏&#xff08;贪心&#xff09; 二、正解代码 //三国游戏&#xff1a;贪心 #include<bits/stdc.h> #define int long lon…

哪些订单预计会亏?一张报表告诉你

各位数据的朋友&#xff0c;大家好&#xff0c;我是老周道数据&#xff0c;和你一起&#xff0c;用常人思维数据分析&#xff0c;通过数据讲故事。 销售订单一般是企业在销售活动中重要的单据&#xff0c;当我们接到一个客户的订单时&#xff0c;就需要在系统中录入一个销售订…

jQuery模态框弹窗提示代码

jQuery模态框弹窗提示代码 下载地址 jQuery模态框弹窗提示代码

Volatile与JMM

被Volatile修饰的变量有两大特点 可见性 有序性&#xff08;禁重排&#xff09; 如何保证的&#xff1f;内存屏障 Volatile的内存语义 当写一个Volatile变量的时候&#xff0c;JMM会把该线程对应的本地内存共享变量值立即刷新回主内存。 当读一个Volatile变量的时候&…

【Java语言】遍历List元素时删除集合中的元素

目录 前言 实现方式 1.普通实现 1.1 使用【for循环】 方式 1.2 使用【迭代器】方式 2.jdk1.8新增功能实现 2.1 使用【lambda表达式】方式 2.2 使用【stream流】方式 注意事项 1. 使用【for循环】 方式 2. 不能使用增强for遍历修改元素 总结 前言 分享几种从List中移…

程序语言设计

一、程序设计语言及其构成 1.程序设计语言 2.高级程序设计语言划分 3.常见的高级程序语言 4.标记语言 5.程序设计语言的构成 二、表达式 表达式的类型及转换规则 三、传值和传址调用 1.数据类型 2.传值和传址调用 四、语言处理程序 1.语言处理程序 语言处理程序&#xff1…

【JS】浅谈浅拷贝与深拷贝

浅拷贝与深拷贝 前言一、浅拷贝&#xff1f;1.1是什么&#xff1f;1.2做什么&#xff1f;1.3为什么使用&#xff1f;1.4实现方式&#xff1f;1.5 应用场景&#xff1f; 二、深拷贝&#xff1f;2.1是什么&#xff1f;2.2做什么&#xff1f;2.3为什么使用&#xff1f;2.4实现方式…

成都产业园排名出炉!金牛区这个园区成数字产业聚集地

近日&#xff0c;成都产业园排名榜单正式发布&#xff0c;可以看出金牛区成数字产业聚集地&#xff0c;其中&#xff0c;备受瞩目的国际数字影像产业园荣登榜首。这一排名不仅彰显了国际数字影像产业园在数字产业领域的卓越表现&#xff0c;更凸显了成都作为西部重要城市在科技…

51单片机系列-单片机定时器

&#x1f308;个人主页&#xff1a;会编辑的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” 软件延时的缺点 延时过程中&#xff0c;CPU时间被占用&#xff0c;无法进行其他任务&#xff0c;导致系统效率降低&#xff0c;延时时间越长&#xff0c;该缺点就越明显&…

HBuilder发行微信小程序

首先需要完善mainifest.json中的基本配置 这个需要组测dcloud才可以获取&#xff0c;注册后点击重新获取就可以。 然后发行前还需要完成dcloud的信息&#xff0c;这个他会给你网址 点击连接完成信息填写就可以了 然后就可以发行了。 发行成功后会自动跳转微信小程序&#xff…

day02vue学习

day02 一、今日学习目标 1.指令补充 指令修饰符v-bind对样式增强的操作v-model应用于其他表单元素 2.computed计算属性 基础语法计算属性vs方法计算属性的完整写法成绩案例 3.watch侦听器 基础写法完整写法 4.综合案例 &#xff08;演示&#xff09; 渲染 / 删除 / 修…