代码随想录刷题训练营第七天|● 454.四数相加II ● 383. 赎金信 ● 15. 三数之和 ● 18. 四数之和 ● 总结

news2024/11/25 7:08:01

四数相加

看完题后的思路

在这里插入图片描述

首先想到了暴力解法,四重for循环,时间复杂度为0(n^4).接着往下想,四数相加不正好是(两数相加)+(两数相加)吗,可以依次求出两数相加的结果存入hash表中 和-[下标1,下标2],然后再进行两数相加.

思路

上面的思路中,有两点疑问:

  1. (1+2)+(3+4)=(1+3)+(2+4)吗? 1,2,3,4代表数组
    是相等的,
    在这里插入图片描述
    如上图,挑选(0,0,0,1),如果挑选数组是(1+2)+(3+4),反映到值上就是 (1-2)+(-1+2),如果是(1+3)+(2+4),反映到值上就是(1-1)+(-1+2),四个家加数并没有改变,改变只是加数的顺序

代码

    // 454 四数相加
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        HashMap<Integer, List<int[]>> sum1_2 = towSumOfArra(nums1, nums2);
        HashMap<Integer, List<int[]>> sum3_4 = towSumOfArra(nums3, nums4);
        //开始第二层求和
       return twoSum02(sum1_2, sum3_4);
    }
    public  HashMap<Integer, List<int[]>> towSumOfArra(int[] nums1,int nums2[]){
        HashMap<Integer, List<int[]>> map = new HashMap<>();
        for (int i = 0; i <nums1.length; i++) {
            for (int j = 0; j < nums2.length; j++) {
                int sum=nums1[i]+nums2[j];
                List<int[]> list = map.getOrDefault(sum, new ArrayList<>());
               list.add(new int[]{i,j});
                map.put(sum,list);
            }
        }
        return map;
    }

    public int twoSum02( HashMap<Integer, List<int[]>> map1, HashMap<Integer, List<int[]>> map2) {
        int res=0;
        for (Map.Entry<Integer, List<int[]>> entry : map1.entrySet()) {
            Integer key = entry.getKey();
            if (map2.containsKey(-1*key)){
                res+=(map1.get(key).size()*map2.get(-1*key).size());
            }
        }
        return res;
    }
}

复杂度

暴力:
时间复杂度 0(n^4)
空间复杂度 0(1)
hash表法
时间复杂度 0(n^2) (两两求和时)
空间复杂度0(n^2)
在这里插入图片描述

难点 收获

错误的将数组两两组合,再相加,导致结果重复

    // 454 四数相加
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        HashMap<Integer, List<int[]>> sum1_2 = towSumOfArra(nums1, nums2);
        HashMap<Integer, List<int[]>> sum1_3 = towSumOfArra(nums1, nums3);
        HashMap<Integer, List<int[]>> sum1_4 = towSumOfArra(nums1, nums4);
        HashMap<Integer, List<int[]>> sum2_3 = towSumOfArra(nums2, nums3);
        HashMap<Integer, List<int[]>> sum2_4 = towSumOfArra(nums2, nums4);
        HashMap<Integer, List<int[]>> sum3_4 = towSumOfArra(nums3, nums4);
        //开始第二层求和
       return twoSum02(sum1_2, sum3_4)+twoSum02(sum1_3,sum2_4)+twoSum02(sum1_4,sum2_3);


    }
    public  HashMap<Integer, List<int[]>> towSumOfArra(int[] nums1,int nums2[]){
        HashMap<Integer, List<int[]>> map = new HashMap<>();
        for (int i = 0; i <nums1.length; i++) {
            for (int j = 0; j < nums2.length; j++) {
                int sum=nums1[i]+nums2[j];
                List<int[]> list = map.getOrDefault(sum, new ArrayList<>());
               list.add(new int[]{i,j});
                map.put(sum,list);
            }
        }
        return map;
    }

    public int twoSum02( HashMap<Integer, List<int[]>> map1, HashMap<Integer, List<int[]>> map2) {
        int res=0;
        for (Map.Entry<Integer, List<int[]>> entry : map1.entrySet()) {
            Integer key = entry.getKey();
            if (map2.containsKey(-1*key)){
                res+=(map1.get(key).size()*map2.get(-1*key).size());
            }
        }
        return res;
    }

三刷时再看一遍

三数之和

看完题后的思路

想到了排序,使用双指针指向正数最小与负数最小,希望正数最小+负数最小能够递增,这样第三个指针从最大处递减
但是两个指针移动相同的方向,都是递增,所以无法一遍筛选出所有的情况

思路

排完序,i从0开始,left从i-1开始,right从数组末尾开始,通过left与right的移动来判断包含i的,且i是最小的元素的加和中有没有符合条件的
为什么left要从i+1开始?
因为i前面的的已经判断完,其作为最小的被加数的情况已经判断完
问题: 如何去重
在这里插入图片描述
去重的逻辑
三元组不能重复,三元组内的元素可以重复
对于三个数 a,b,c 分别对应nums[minItermIndex] nums[left] nums[right],如果nums[minItermIndex]==nums[minItermIndex-1],则重复,因为以a为最小元素的和在minItermIndex-1已经找遍了.当找到a+b+c=0时,此时不能跳出循环,因为可能还有例如 -2 -1+3与-2+0-2,所以left与right也要去重

  while (left<right&&nums[left]==nums[left+1]){
                        left++;
                    }
                     while (left<right&&nums[right]==nums[right-1]){
                         right--;
                     }
                     left++;
                     right--;
                }

代码

   public List<List<Integer>> threeSum(int[] nums) {
        int minItermIndex=0;// 最小一项的下标
        Arrays.sort(nums);
        ArrayList<List<Integer>> lists = new ArrayList<>();
        for (; minItermIndex < nums.length-2; minItermIndex++) {
            // 去重 如果
            if (minItermIndex>0&&nums[minItermIndex-1]==nums[minItermIndex]){
                continue;
            }
            int left=minItermIndex+1,right=nums.length-1;
            int minIterm = nums[minItermIndex];
            while (left<right){
                int sum = minIterm + nums[left] + nums[right];
                if (sum<0){
                   left++; 
                }else if (sum==0){
                    ArrayList<Integer> list = new ArrayList<>();
                  list.add(nums[minItermIndex]);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    lists.add(list);
                    //不能 break; 因为可能还有 等于0的组合
                    //去重02 当最小元素定下来,left不能与上一种相同 0-1+1 与 0+0-0
                    while (left<right&&nums[left]==nums[left+1]){
                        left++;
                    }
                     while (left<right&&nums[right]==nums[right-1]){
                         right--;
                     }
                     left++;
                     right--;
                }else {
                    right--;
                }
            }
           
        }
        return lists;
    }

复杂度

时间复杂度 0(n^2) 每一轮双指针开销是0(1),一共n轮
空间复杂度 0(1)

收获

  1. 学到了一种双指针双向单调的情形,排序数组,双指针指向两端
  2. 欢动窗口中,也是一种双指针双向单调的情形,left+1,窗口减小,right+1,窗口增加
    三刷还要再来一遍

四数之和

四数之和与三数之和本质上一样,只粘出代码

    // 四数之和
        public List<List<Integer>> fourSum(int[] nums, int target) {
            Arrays.sort(nums);
            ArrayList<List<Integer>> lists = new ArrayList<>();
            for (int i = 0; i < nums.length; i++) {
                // 去重
                if (i>0&&nums[i]==nums[i-1]){
                    continue;
                }
                // 剪枝
                    // 剪枝
                    if ((target<=0&&nums[i]>0)){
                    
                        break;
                    }
                for (int j = i+1; j <nums.length ; j++) {
                    if (j>i+1&&nums[j]==nums[j-1]){
                        continue;
                    }
                    long sum_ij = nums[i] + nums[j];
                    long diff = target - sum_ij;
                
                    int left=j+1,right=nums.length-1;
                    while (left<right){
                        int sum =nums[left] + nums[right];
                        if (sum<diff){
                            left++;
                        }else if (sum==diff){
                            ArrayList<Integer> list = new ArrayList<>();
                            list.add(nums[i]);
                            list.add(nums[j]);
                            list.add(nums[left]);
                            list.add(nums[right]);
                            lists.add(list);
                            //不能 break; 因为可能还有 等于0的组合
                            //去重02 当最小元素定下来,left不能与上一种相同 0-1+1 与 0+0-0
                            while (left<right&&nums[left]==nums[left+1]){
                                left++;
                            }
                            while (left<right&&nums[right]==nums[right-1]){
                                right--;
                            }
                            left++;
                            right--;
                        }else {
                            right--;
                        }
                    }
                    
                }
            }
            return lists;
        } 

三刷再来一遍

赎金信

太简单了,粘贴代码如下

   // 赎金信
    public boolean canConstruct(String ransomNote, String magazine) {
        if (ransomNote.length()>magazine.length()){
            return false;
        }
        int ransomNoteMap[]=new int[26];
        int magazineMap[]=new int[26];
        for (int i = 0; i < ransomNote.length(); i++) {
            char c = ransomNote.charAt(i);
            ransomNoteMap[c-'a']++;
        }

        for (int i = 0; i < magazine.length(); i++) {
            char c = magazine.charAt(i);
            magazineMap[c-'a']++;
        }

        for (int i = 0; i < 26; i++) {
            if (ransomNoteMap[i]>magazineMap[i]){
                return false;
            }
        }
        return true;
    }

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

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

相关文章

渗透测试基础入门【01】——测试流程(IPC$)

渗透测试基础入门【01】——测试流程&#xff08;IPC$&#xff09; 注意&#xff0c;攻击对方需要对方授权&#xff0c;本文章目的只为教学&#xff0c;不要拿去干违法的事 1 渗透测试流程 授权&#xff08;获取目标用户授权&#xff0c;否则是违法行为&#xff09;信息收集 …

【4 - 降维算法PCA和SVD - 原理部分】菜菜sklearn机器学习

课程地址&#xff1a;《菜菜的机器学习sklearn课堂》_哔哩哔哩_bilibili 第一期&#xff1a;sklearn入门 & 决策树在sklearn中的实现第二期&#xff1a;随机森林在sklearn中的实现第三期&#xff1a;sklearn中的数据预处理和特征工程第四期&#xff1a;sklearn中的降维算法…

nacos注册源码分析

Nacos注册服务 cosumer启动的时候&#xff0c;从nacos server上读取指定服务名称的实例列表&#xff0c;缓存到本地内存中。 开启一个定时任务&#xff0c;每隔10s去nacos server上拉取服务列表 nacos的push机制&#xff1a; 通过心跳检测发现服务提供者出现心态超时的时候…

SpringCloud学习笔记 - 流控规则 - Sentinel

1. Sentinel流控规则简介 这里的流控指的是“流量控制”&#xff0c;进一步解释说明&#xff1a; 资源名&#xff1a;唯一名称&#xff0c;默认请求路径。 针对来源&#xff1a;Sentinel可以针对调用者进行限流&#xff0c;填写微服务名&#xff0c;默认default&#xff08;不…

爬虫解析模块(bs4,selenium)

bs4文档 from bs4 import BeautifulSoupBeautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。Beautiful Soup自动将输入文档转换为Unicode编码&#xff0c;输出文档转换为utf-8编码。 解析器 解析器使用方法优势劣势Python标准库BeautifulS…

Dubbo——入门介绍

目录1.概述1.1.什么是 Dubbo &#xff1f;1.2.Dubbo 架构2.Dubbo 快速入门2.1.Zookeeper 安装2.2.创建项目2.3.代码实现2.3.1.dubbo-service 模块2.3.2.dubbo-web 模块2.4.本地启动2.5.使用 Dubbo 实现 PRC2.5.1.修改 dubbo-service 模块2.5.2.修改 dubbo-web 模块2.5.3.启动 d…

可免费编辑 PDF 内容的 7 大 PDF 编辑工具

有时您可能希望编辑 PDF 文档中的敏感信息&#xff0c;例如财务帐号和 ID 号&#xff0c;以便在不泄露隐私的情况下共享 PDF。编辑 PDF 是从 PDF 中删除私有内容。使用PDF 编辑工具可以轻松完成编辑。市场上有这么多工具&#xff0c;您需要选择最好的一种。 7 大 PDF 编辑工具 …

data analysis and predict

data anlysis and predict 谢邀&#xff0c;本人正在崩溃和兴奋间反复横跳&#xff08;崩溃居多&#xff09;&#xff0c;anyway, 我心态超好的&#xff01;besides, 仅供个人学习查阅&#xff0c;不具任何参考价值&#xff01;&#xff01;&#xff01; &#xff08;小边不想努…

路由信息协议RIP

文章目录路由信息协议RIP一、Routing Information Protocol的定义二、RIP的基本工作过程三、“坏消息传播得慢”的问题四、总结路由信息协议RIP 一、Routing Information Protocol的定义 RIP是分布式的基于距离向量的路由选择协议 协议RIP的特点是&#xff1a; 仅和相邻路由…

Java数据结构(泛型)

1、集合框架 Java 集合框架Java Collection Framework &#xff0c;又被称为容器container &#xff0c;是定义在 java.util 包下的一组接口interfaces 和其实现类classes 。 其主要表现为将多个元素element 置于一个单元中&#xff0c;用于对这些元素进行快速、便捷的存储sto…

【XML了解】xml与hxml 标记语言学习

XML与HXML的区别 XML 被设计用来传输和存储数据&#xff0c;结构化、存储以及传输信息&#xff08;如&#xff1a;数据包&#xff09; XML 被设计用来传输和存储数据&#xff0c;其焦点是数据的内容 XML 标签没有被预定义, 需要自行定义标签 HTML 被设计用来表现和展示数据&…

数组常用方法总结 (7) :copyWithin / fill / reduce / reduceRight

copyWithin 将指定位置的元素复制到数组的其他位置。返回值为移动后数组。原始数组的内容会被改变&#xff0c;原始数组的长度不会改变。arr.copyWithin(index, startIndex, endIndex)第一个参数为&#xff0c;期望被复制的内容将要插入的位置。第二个参数为&#xff0c;数组中…

SpringBoot 参数接收只看这一篇文章就够了

好久没有写过接口了&#xff0c;最近在写一些基础接口&#xff0c;在写参数接口接收参数的时候居然想不起来&#xff0c;会有那么一丝丝的怀疑&#xff0c;虽然并不会影响编码&#xff0c;但是说明一个问题&#xff0c;没有系统的总结知识&#xff0c;没有温故知新&#xff0c;…

PMP真的有用吗?

作为一个考了PMP的前辈来说&#xff0c;是有用的。PMP 含金量&#xff0c;PMP有没有用&#xff0c;这类问题一直是大家关注的重点&#xff0c;知乎上几个相关问题热度也一直很高。友情提示一句&#xff1a;PMP 就是一个证书&#xff0c;能起到加分和门槛的作用&#xff0c;技术…

Diazo Biotin-PEG3-DBCO,二苯并环辛炔PEG3重氮生物素,无铜 Click Chemistry

Diazo Biotin-PEG3-DBCO反应原理&#xff1a;Diazo Biotin-PEG3-DBCO 是一种点击化学标记生物素&#xff0c;可通过无铜 Click Chemistry 与叠氮化物发生反应。重氮允许使用连二亚硫酸钠 (Na2S2O4) 从链霉亲和素中有效释放捕获的生物素化分子。点击化学生物素标记试剂包含各种点…

基于麻雀算法优化的深度极限学习机DLM的预测算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

基于SpringBoot的SSMP整合(业务层表现层)

基于SpringBoot的SSMP整合&#xff08;数据层&#xff09;https://blog.csdn.net/weixin_51882166/article/details/128693739?spm1001.2014.3001.5502 标准CRUD Service层接口定义与数据层接口定义具有较大差距。 定义Service接口&#xff1a; package com.example.ssmp_…

蓝桥杯STM32G431RBT6学习——LCD

蓝桥杯STM32G431RBT6学习——LCD 前言 作为在开发板上最显眼的LCD屏幕&#xff0c;自然而然也是每年的必考考点。国信长天开发板使用的是一块2.4寸&#xff08;240*320&#xff09;的TFT-LCD液晶屏&#xff0c;其引脚占用如下&#xff1a; 其中&#xff0c;CS为片选信号引脚…

【Netty】实现IM聊天室案例Demo

文章目录1、WebSocket链接建立2、实现用户上线功能3、私聊发送消息注意&#xff1a; 该文章不会详细介绍Netty相关概念和原理&#xff0c;主要目的是介绍如何快速构建聊天室Demo 不会在文章主体过多说明代码流程&#xff0c;文章中的代码已经配备了详细的注释 1、WebSocket链接…

网站建设 之 用js写wasm

为什么要这么做&#xff1f;编译js比解释js更快是必然的wasm是什么&#xff1f;我期望是一个二进制文件WebAssembly&#xff08;又名wasm&#xff09;是一种高效的&#xff0c;低级别的编程语言。 它让我们能够使用JavaScript以外的语言&#xff08;例如C&#xff0c;C &#x…