代码随想录算法训练营第二十七天 | LeetCode 93. 复原 IP 地址、78. 子集、90. 子集 II

news2024/11/15 13:59:33

代码随想录算法训练营第二十七天 | LeetCode 93. 复原 IP 地址、78. 子集、90. 子集 II

文章链接:复原IP地址        子集        子集II

视频链接:复原IP地址        子集        子集II

目录

代码随想录算法训练营第二十七天 | LeetCode 93. 复原 IP 地址、78. 子集、90. 子集 II

1. LeetCode 93. 复原 IP 地址

1.1 思路

1.2 代码

2. LeetCode 78. 子集

2.1 思路

2.2 代码

3. LeetCode 90. 子集 II

3.1 思路

3.2 代码


 

1. LeetCode 93. 复原 IP 地址

1.1 思路

  1. 解释一下题目给出的一个“0”开头的合法 IP 地址,意思是如果是“0”开头了那这部分就只能是个 0,不能是“0235”这种。
  2. 首先定义个全局变量 result 里面放的是合法的字符串,是全部的答案
  3. 回溯函数的参数和返回值:返回值 void,参数首先是字符串 s,然后是 startIndex 是控制进入下一层递归时,从剩下的字符串中切割,就是告诉我们下一层递归从哪里开始切割,控制的是起始位置,再是 pointSum,因为我们要在字符串中加入 " . ",要加入才能放入 result 中,我们需要 3 个这个点。在代码中 startIndex 代表的就是我们的切割分割线,因为在我们进入下一层递归中时,startIndex 控制的就是从剩下的字符串中开始查找
  4. 终止条件:如果 pointSum==3,就要终止了,因为 IP 地址要三个点就行了,这个点就决定了树的深度,其实就是 3 层。这里注意下我们加入点的时候,是对加点位置的前面的字符串进行合法性判断,因为是 3 个点,但我们有 4 个子串,因此在终止条件中我们还需要对最后一段进行合法性判断,然后才能加入到 result 中。合法性判断的函数是 isValid。由上面的 startIndex 表示切割线的位置说明,isValid(s,startIndex,s.length()-1),分别表示字符串,起始位置,终止位置,如果为 true 就加入到 result 中,然后 return 就行
  5. 单层搜索的逻辑:for(int i=startIndex;i<s.length();i++),这个 for循环就是我们取数然后分割的过程,就要进行合法性判断,如果不合法就没必要往下遍历了。因此 if(isValid(s, startIndex, i)),其中 [startIndex, i] 这个就是子串的区间,本层中 startIndex 是固定的,但 i 是不断后移的,因此没毛病。如果合法,要先加入点,s=substring(start, i+1)+"."+substring(i+1) ,这里的 substring 函数是左闭右开的区间,因此要加 1,如果只传入一个参数就是这个位置往后的元素都要取出,然后 pointSum++。接着就向下一层递归 backtracking(s, i+2, pointSum),这里为什么是加 2 而不是加 1,因为我们加了个点了,所以要跳 2 个位置。然后就是回溯,我们要把之前插入的点删去,s=s.substring(0, i+1)+substring(i+2),这里就是跳过了那个点,然后 pointSum--,因为我们要继续往右搜索,因此加入的点要删去才能去右搜索
  6. 合法性判断:返回值 boolean,参数字符串 s,起始位置 start,结束位置 end,如果 start>end 就 false;如果第一个位置是 字符 '0'并且这个第一个位置不是终止位置,就 false;然后进入循环遍历,for(int i=start; i<=end; i++)这里要<=,因为 end 就是最后一个位置。然后如果字符串的 i 位置是>9 或者<0 的字符就 false,其实就是判断是否为 0 到 9 的数字;然后求整个子串是否在 0 到 255 之间,就 num=num*10+(s.charAt(i)-'0'),如果 num>255 就 false。以上均不发生就为 true。
  7. 提一下 s.charAt(i)-'0' 这步,其实就是字符的 ASCII 码值相减,比如是字符 ‘1’-‘0’,那么得到的结果就是真正的数字 1,字符 '0' 的 ASCII 码值是 48,字符 '1' 则是 49。

1.2 代码

//
class Solution {
    List<String> result = new ArrayList<>();

    public List<String> restoreIpAddresses(String s) {
        if (s.length() > 12) return result; // 算是剪枝了
        backTrack(s, 0, 0);
        return result;
    }

    // startIndex: 搜索的起始位置, pointNum:添加逗点的数量
    private void backTrack(String s, int startIndex, int pointNum) {
        if (pointNum == 3) {// 逗点数量为3时,分隔结束
            // 判断第四段⼦字符串是否合法,如果合法就放进result中
            if (isValid(s,startIndex,s.length()-1)) {
                result.add(s);
            }
            return;
        }
        for (int i = startIndex; i < s.length(); i++) {
            if (isValid(s, startIndex, i)) {
                s = s.substring(0, i + 1) + "." + s.substring(i + 1);    //在str的后⾯插⼊⼀个逗点
                pointNum++;
                backTrack(s, i + 2, pointNum);// 插⼊逗点之后下⼀个⼦串的起始位置为i+2
                pointNum--;// 回溯
                s = s.substring(0, i + 1) + s.substring(i + 2);// 回溯删掉逗点
            } else {
                break;
            }
        }
    }

    // 判断字符串s在左闭⼜闭区间[start, end]所组成的数字是否合法
    private Boolean isValid(String s, int start, int end) {
        if (start > end) {
            return false;
        }
        if (s.charAt(start) == '0' && start != end) { // 0开头的数字不合法
            return false;
        }
        int num = 0;
        for (int i = start; i <= end; i++) {
            if (s.charAt(i) > '9' || s.charAt(i) < '0') { // 遇到⾮数字字符不合法
                return false;
            }
            num = num * 10 + (s.charAt(i) - '0');
            if (num > 255) { // 如果⼤于255了不合法
                return false;
            }
        }
        return true;
    }
}

2. LeetCode 78. 子集

2.1 思路

  1. 这题要求的是集合里的所有子集,就是像数学集合里的一样,有 3 个元素,那就有 2^3 = 8 个子集。而且这里求的是组合,[1,2] 和 [2,1] 是一样的,所以本题依然要用 startIndex 来控制收集剩余集合时的起始位置。这题和上面的题区别在于收获结果的地方是很大差别的
  2. 这题比较大的区别就在于我们是要收集每个节点的结果,这个节点就是一层递归,每进入一层递归就把当前本层递归的单个结果放入 result 中
  3. 定义两个全局变量,result 放全部结果,path 放单个结果
  4. 回溯函数的参数和返回值:返回值 void,参数 nums,startIndex 来控制当前这个递归层从哪里开始往后取,也就是控制起始位置
  5. 终止条件:如果 startIndex>=nums.length 就是到了叶子节点的位置了,就 return
  6. 单层搜索的逻辑:for(int i= startIndex; i<nums.length; i++),然后 path.add(nums[i]),然后就是递归的过程,backtracking(nums, i+1),然后是回溯的过程,path.removeLast()去掉最后的元素然后继续往右搜索。
  7. 而我们收获结果的地方就是在这个回溯函数的第一行,就直接 result.add(path) 这样子,为什么放这里?因为我们递归进入时就要把当前的 path 放入 result 里,如果放在了终止条件下,那最后一个元素放入后进入递归就直接 return 了,就少了最后一个 path 子集

2.2 代码

//
class Solution {
    List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
    LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
    public List<List<Integer>> subsets(int[] nums) {
        subsetsHelper(nums, 0);
        return result;
    }

    private void subsetsHelper(int[] nums, int startIndex){
        result.add(new ArrayList<>(path));//「遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合」。
        if (startIndex >= nums.length){ //终止条件可不加
            return;
        }
        for (int i = startIndex; i < nums.length; i++){
            path.add(nums[i]);
            subsetsHelper(nums, i + 1);
            path.removeLast();
        }
    }
}

3. LeetCode 90. 子集 II

3.1 思路

  1. 这集给的数组的元素是有重复元素的,这是和上题的区别,而且要求不能有重复子集,例如是不能出现 2 次 [1,2]。本题是结合了40. 组合总和 II和78. 子集。这题需要对回溯算法进行去重操作
  2. 我们需要一个 used 数组来标记哪个元素我们是否用过,true 为用过。我们用这种去重的操作方式需要先给题目的 nums 数组排序,因为我们要让相邻的元素挨在一起,因为这题同理要做的是树层去重。而且我们需要用 startIndex 来控制我们要在剩下的元素里取数,不然就会出现 [1,2],[2,1] 这种情况。而树枝上不用去重,因为我们已经用了 startIndex 控制了起始位置,用的元素其实不是同一个元素,如果相同其实只是数值相同。而我们的树形结构上的所有节点都是我们的结果,也就决定了把 path 加入 result 的位置是放在回溯函数的首行。回溯函数进去后的时候就是一个节点,取数的过程是在 for循环里
  3. 定义全局变量 result 全部结果、path 单个结果、used 标记是否用过
  4. 回溯函数的参数和返回值:返回值 void,参数是 nums 数组,startIndex 控制起始位置
  5. 终止条件:startIndex>=nums.length 就 return
  6. 单层搜索的逻辑:首行先 result.add(path),因为我们进入回溯函数后就证明这个节点已经是取好数的了。取数的过程就是 for(int i=startIndex; i<nums.length; i++)我们剪枝的过程是放在 for循环开始的,如果(i>0&&nums[i-1]==nums[i]&&!used[i-1])避免i-1为负数,首先要求i>0,然后是如果前后两个元素相等了就不能再取了,不然就重复了,然后下一个条件是前一个元素不能用过,这里是为了往下递归时,举例,取了一个1后,还能取多个1,这里的多个1不是同一个1,只是数值相同,这个条件不是为了树层去重的,而是为了取数找到结果。如果符合条件就是发现重复了就continue跳过此次循环,继续往后取。
  7. 然后就是继续收集元素的过程path.add(数组[i]);used[i]=true;然后就递归的过程backtracking(nums, i+1)。然后就是回溯的过程,path.removeLast()去除最后一个元素也就是刚刚加入的元素,这样才能往树的右边搜索,used[i]=false。这里又变为false是为了往右搜索,逻辑和第一层往右搜索的原因是一样的

3.2 代码

//
class Solution {
   List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
   LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
   boolean[] used;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        if (nums.length == 0){
            result.add(path);
            return result;
        }
        Arrays.sort(nums);
        used = new boolean[nums.length];
        subsetsWithDupHelper(nums, 0);
        return result;
    }
    
    private void subsetsWithDupHelper(int[] nums, int startIndex){
        result.add(new ArrayList<>(path));
        if (startIndex >= nums.length){
            return;
        }
        for (int i = startIndex; i < nums.length; i++){
            if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]){
                continue;
            }
            path.add(nums[i]);
            used[i] = true;
            subsetsWithDupHelper(nums, i + 1);
            path.removeLast();
            used[i] = false;
        }
    }
}

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

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

相关文章

【vue3】传送组件、Teleport

把test里的内容传送到test2 //test1.vue <template><div>test1<Teleport v-if"flag" to".aa">test1的内容</Teleport></div></template><script setup langts>import { ref,reactive,onMounted } from vueconst…

[云原生1] Docker网络模式的详细介绍

1. Docker 网络 1.1 Docker 网络实现原理 Docker使用Linux桥接&#xff0c;在宿主机虚拟一个Docker容器网桥(docker0)&#xff0c; Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址&#xff0c;称为Container-IP&#xff0c; 同时Docker网桥是每个容器的默认…

D-Link确认数据泄露:员工成为钓鱼攻击受害者

最近&#xff0c;台湾网络设备制造商D-Link确认了一起数据泄露事件&#xff0c;该事件导致公司员工成为钓鱼攻击的受害者。虽然公司表示泄露的数据属于“低敏感度和半公开信息”&#xff0c;但仍引发了公众的关注。让我们来看看事件的详细情况。 导语 近期&#xff0c;台湾网络…

博客系统中的加盐算法

目录 一、为什么要对密码进行加盐加密&#xff1f; 1、明文 2、传统的 MD5 二、加盐加密 1、加盐算法实现思路 2、加盐算法解密思路 3、加盐算法代码实现 三、使用 Spring Security 加盐 1、引入 Spring Security 框架 2、排除 Spring Security 的自动加载 3、调用 S…

python学习7

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

【虹科干货】如何构建弹性、高可用的微服务?

基于微服务的应用程序可实现战略性数字转型和云迁移计划&#xff0c;对于开发团队来说&#xff0c;这种架构十分重要。那么&#xff0c;如何来构建弹性、高可用的微服务呢&#xff1f;Redis Enterprise给出了一个完美的方案。 文况速览&#xff1a; - 什么是微服务架构&#…

介绍argparse的使用【Python标准库】

文章目录 简介argparse标准库的核心功能介绍Python代码示例参考 简介 argparse 模块是Python标准库中的一个模块&#xff0c;用于处理命令行参数解析。它的主要作用是帮助开发者创建命令行界面&#xff0c;允许用户指定运行脚本时的参数&#xff0c;从而定制脚本的行为。本篇博…

1019hw

登录窗口头文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QToolBar> #include <QMenuBar> #include <QPushButton> #include <QStatusBar> #include <QLabel> #include <QDockWidget>//浮动窗口…

2023年中国城市交通数智化发展趋势分析:城市交通数智化渗透率将达到31.0% [图]

城市交通数智化是指将自动化技术、信息技术、通信技术、数字化和智能化技术综合应用于城市交通管理领域&#xff0c;建立实时、准确、高效的城市交通管理体系&#xff0c;提升城市交通管理能力和通行效率。城市交通数智化主要应用场景包括在城市道路、交叉口、隧道、快速路、交…

React TypeScript安装npm第三方包时,些包并不是 TypeScript 编写的

npm install types/包名称 例如&#xff1a;npm install types/jquery 学习链接

C1N短网址 | 核心专利(2) - 防止程序脚本访问短链接

1. 短链接介绍 短链接是一种缩短了URL长度的链接&#xff0c;通常由网址缩短服务提供商生成。短链接可以将长URL缩短为更短的URL&#xff0c;使其更易于分享和传播。短链接通常由一些字母、数字和特殊字符组成&#xff0c;可以通过点击或复制粘贴来访问原始的长URL。短链接在社…

Spring Security认证流程分析(6)

1、认证流程分析 Spring Security中默认的一套登录流程是非常完善并且严谨的。但是项目需求非常多样化, 很多时候&#xff0c;我们可能还需要对Spring Secinity登录流程进行定制&#xff0c;定制的前提是开发者先深刻理解Spring Security登录流程&#xff0c;然后在此基础之上…

竞赛 深度学习交通车辆流量分析 - 目标检测与跟踪 - python opencv

文章目录 0 前言1 课题背景2 实现效果3 DeepSORT车辆跟踪3.1 Deep SORT多目标跟踪算法3.2 算法流程 4 YOLOV5算法4.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…

Halcon 中查看算子和函数的执行时间

1、在Halcol主窗口的底栏中的第一个图标显示算子或函数的执行时间&#xff0c;如下图&#xff1a; 2、在Halcon的菜单栏中选择【窗口】&#xff0c;在下拉框中选择【打开输出控制台】&#xff0c;进行查看算子或函数的执行时间&#xff0c;如下图&#xff1a;

「神奇的锚点定位:探索UniApp中实现滚动定位效果,与1024程序员节同欢,解析技术之美」

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 文章简介 &#x1f4d8; 文章背景 &#…

小程序中如何使用自定义组件应用及搭建个人中心布局

一&#xff0c;自定义组件 从小程序基础库版本 1.6.3 开始&#xff0c;小程序支持简洁的组件化编程。所有自定义组件相关特性都需要基础库版本 1.6.3 或更高。 开发者可以将页面内的功能模块抽象成自定义组件&#xff0c;以便在不同的页面中重复使用&#xff1b;也可以将复杂的…

【Godot引擎开发】简单基础,外加一个小游戏DEMO

博主&#xff1a;_LJaXi 专栏&#xff1a; Godot | 横版游戏开发 Godot 物体规律移动内置虚函数浮点计算浮点数计算数组APIInput单例与自定义单例节点NodeSprite2DArea2DCollisionShape2DKinematicBody2DRigidBody2D Pong游戏场景安排玩家1玩家2小球记分系统文件概要 下面是介绍…

软件工程与计算总结(二十一)软件维护与演化

一.软件维护 1.软件可修改性和软件维护 产品交付给用户并投入运营之后&#xff0c;接下来的工作被看做软件维护。 因为软件不存在“磨损”的情况&#xff0c;所以与其他工程学科相比&#xff0c;软件维护只需要完成少量的使用帮助、故障解决等工作——但并不意味着维护是简单…

IOday8

#include <head.h>//要发送数据的结构体类型 struct msgbuf {long mtype; /* 消息类型*/char mtext[1024]; /* 正文数据 */}; //宏定义正文大小 #define SIZE sizeof(struct msgbuf)-sizeof(long) int main(int argc, const char *argv[]) {key_t key;if((keyft…

oracle-AWR报告生成方法

AWR报告生成方法 1. 以oracle用户登陆服务器 2. 进入到要保存awr报告的目录 3. 以sysdba身份连接数据库 sqlplus / as sysdba4. 执行生成AWR报告命令 ?/rdbms/admin/awrrpt.sql5. 选择AWR报告的文件格式 6. 选择生成多少天的AWR报告 7. 选择报告的快照起始和结束ID 8. 输入生…