代码随想录第28天 | 93.复原IP地址 、 78.子集 、 90.子集II

一、前言:

参考文献:代码随想录

今天的主题内容是回溯算法,这一章的干货很多,我需要慢慢的品味,不单单只是表象,还需要研究深层原理。

二、复原IP地址

1、思路:

(1)首先还是确定返回值和参数:

void backtracking(string &s, int startIndex, int pointSum)

这里比往常多了一个pointSum,这个是来判断是否符合ip格式的一个标志,也就是记录这个s中存在多少个".";

(2)终止条件如下:

// pointsum是用来判断这个字符串中存在多少个"."如果有了三个,就说明满足IP格式了
        if (pointSum == 3) {
            if (isValud(s, startIndex, s.size() - 1)) {
            // 这里还有一个条件就是判断最后的一段是否符合IP要求
                result.push_back(s);
            }
            return;
        } 

这里首先要判断是否有三个”.“,存在之后,再判断最后的那一段是否符合IP的格式,然后才能插入,如果不符合那就直接return回溯了。

(3)单层递归逻辑:

for (int i = startIndex; i < s.size(); i++) {
            if (isValud(s, startIndex, i)) {
                s.insert(s.begin() + i + 1, '.'); // 插入"."
                pointSum++;
                backtracking(s, i + 2, pointSum); // 这里是 i+2 此逻辑是因为加了"."需要多加一个1
                // 回溯
                pointSum--;
                s.erase(s.begin() + i + 1); // 删除"."
            } else {
                break;
            }
        }

看起来并不复杂,但是,难疑点比较多。首先就是先判断当前的这个切片处是否符合IP格式,然后再进行插入逗点,pointSum再做记录,然后就可以开始递归了,这里的是 i+2的,因为这个时候插入了逗点,所以需要后移一位,接着就是回溯了。

(4)主函数中存在一个小小的剪枝操作,如下:

if (s.size() < 4 || s.size() > 12) return result;

(5)判断是否为ip的函数为:

    bool isValud(string &s, int start, int end) {
        if (start > end) {
            return false;
        }
        // 头号字符不能为0(只有一位时可以)
        if (s[start] == '0' && start != end) {
            return false;
        }
        // 小于等于255
        int num = 0;
        for (int i = start; i <= end; i++) {
            // 不为合法数字也排除
            if (s[i] > '9' || s[i] < '0') {
                return false;
            }
            num = num * 10 + (s[i] - '0');
            if (num > 255) {
                return false;
            }
        }
        return true;
    }

这里的细节也比多:

1、start和end的比较;

2、头数字不为0,且不是只有一个数字;

3、和小于等于255;

2、整体代码如下:

class Solution {
private:
    // 判断是否为合法IP
    bool isValud(string &s, int start, int end) {
        if (start > end) {
            return false;
        }
        // 头号字符不能为0(只有一位时可以)
        if (s[start] == '0' && start != end) {
            return false;
        }
        // 小于等于255
        int num = 0;
        for (int i = start; i <= end; i++) {
            // 不为合法数字也排除
            if (s[i] > '9' || s[i] < '0') {
                return false;
            }
            num = num * 10 + (s[i] - '0');
            if (num > 255) {
                return false;
            }
        }
        return true;
    }

    vector<string> result;
    void backtracking(string &s, int startIndex, int pointSum) { 
        // pointsum是用来判断这个字符串中存在多少个"."如果有了三个,就说明满足IP格式了
        if (pointSum == 3) {
            if (isValud(s, startIndex, s.size() - 1)) {
            // 这里还有一个条件就是判断最后的一段是否符合IP要求
                result.push_back(s);
            }
            return;
        } 
        // 单层递归逻辑
        for (int i = startIndex; i < s.size(); i++) {
            if (isValud(s, startIndex, i)) {
                s.insert(s.begin() + i + 1, '.'); // 插入"."
                pointSum++;
                backtracking(s, i + 2, pointSum); // 这里是 i+2 此逻辑是因为加了"."需要多加一个1
                // 回溯
                pointSum--;
                s.erase(s.begin() + i + 1); // 删除"."
            } else {
                break;
            }
        }
    }
public:
    vector<string> restoreIpAddresses(string s) {
        if (s.size() < 4 || s.size() > 12) return result; // 算是剪枝了
        backtracking(s, 0 , 0);
        return result;
    }
};

 三、子集

1、思路:

(1)返回值和终止条件并没有什么改变:

void backtracking(vector<int> &nums, startIndex)

(2)终止条件(这个条件可有可不有,因为在return时以及到了叶子节点处,循环自然就不去了,就不用手动终止了):

if (startIndex >= nums.size()) return;

(3)单层递归逻辑:

for (int i = startIndex; i < nums.size(); i++) {
            // 插入元素
            path.push_back(nums[i]);
            // 递归
            backtracking(nums, i + 1);
            // 回溯
            path.pop_back();
        }

还是插入,递归,回溯。。。

(4)最重要的就是收集path,在每次递归开始时就可以收集子集了;

2、整体代码如下:

class Solution {
private:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(vector<int>& nums, int startIndex) {
        // 收集结果,每递归一次就可以收集一次结果
        result.push_back(path);
        // 终止条件,可写可不写,因为到了最后的叶子节点,自然会终止的
        if (startIndex >= nums.size()) return;

        for (int i = startIndex; i < nums.size(); i++) {
            // 插入元素
            path.push_back(nums[i]);
            // 递归
            backtracking(nums, i + 1);
            // 回溯
            path.pop_back();
        }
        return;
    }
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        backtracking(nums, 0);
        return result;
    }
};

 四、子集||

1、思路:

这个题目和上一题加上组合总和|||综合,这里也需要添加一个used来判断是否使用了这个元素,如果使用了那就可以继续遍历,说明在树枝上,但是如前面一个元素相同,但是没有被使用,说明在数层上面,就需要跳过这个数字了,避免重复。

图解如下:

 

 

这里就不一步步分析了;

2、整体代码如下:

class Solution {
private:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(vector<int>& nums, int startIndex, vector<bool> &used) {
        result.push_back(path);
        for (int i = startIndex; i < nums.size(); i++) {
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;
            }
            path.push_back(nums[i]);
            used[i] = true;
            backtracking(nums, i + 1, used);
            used[i] = false;
            path.pop_back();
        }
        return;
    }
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<bool> used(nums.size(), false);
        sort(nums.begin(), nums.end());
        backtracking(nums, 0, used);
        return result;
    }
};

今日学习时间:2小时

leave message:

Her behavior is well-accorded with the expectations of her parents.

她的行为与父母的期望相符。 

 

 

 

 

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

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

相关文章

反射的学习

反射的作用&#xff1a; 1.获取一个类里面的所有信息&#xff0c;获取到之后&#xff0c;在执行其他的业务逻辑 2.结合配置文件&#xff0c;动态的创建对象并调用方法

OpenHarmony实战:轻量级系统之启动恢复子系统移植

启动恢复子系统负责在内核启动之后到应用启动之前的系统关键进程和服务的启动过程的功能。 移植指导 针对轻量系统主要提供了各服务和功能的启动入口标识。在SAMGR启动时&#xff0c;会调用bootstrap标识的入口函数&#xff0c;并启动系统服务。 适配完成后&#xff0c;调用…

Node.js------Express

◆ 能够使用 express.static( ) 快 速 托 管 静 态 资 源◆ 能够使用 express 路 由 精 简 项 目 结 构◆ 能够使用常见的 express 中间件◆ 能够使用 express 创建API接口◆ 能够在 express 中启用cors跨域资源共享 一.初识Express 1.Express 简介 官方给出的概念&#xff…

Micron FY24 Q2业绩强劲,凭内存实现翻盘

根据TechInsights数据显示&#xff0c;美光科技24财年第二季度业绩强劲&#xff0c;公司通过技术创新和产能优化&#xff0c;成功抓住了AI服务器和其他高性能应用带来的市场需求增长机遇。尽管短期内面临供应紧张的问题&#xff0c;但美光通过加大研发投入和产能转换力度&#…

Grafana实时监控minio的极简方法

背景 想监控一下minio的部分信息. 使用过程中需要关注的内容挺多的. 只看简单的node感觉已经不够了. 所以想监控易一下. ERLANG 复制 全屏 方式和方法 minio其实集成了prometheus 支持的监控指标 只需要在配置文件中放开就可以了. 虽然可以使用mc 的命令 create beartoken 但…

顺序表的创建

本期我们主要讨论动态顺序表 这个内容可以分为三个部分 1.创建头文件进行函数声明 2.创建源文件进行函数定义 3.创建主文件进行测试 我们先来看看头文件里的函数声明&#xff1a; 函数声明&#xff1a; 头文件中包括<stdlib.h>库函数用于进行动态内存管理&#xff0…

Qt + VS2017 创建一个简单的图片加载应用程序

简介&#xff1a; 本文介绍了如何使用Qt创建一个简单的图片加载应用程序。该应用程序可以打开图片文件并在界面上显示选定的图片&#xff0c;并保存用户上次选择的图片路径。 1. 创建项目&#xff1a; 首先&#xff0c;在VS中创建一个新的Qt Widgets应用程序项目&#xff0c;并…

亚信安慧AntDB:激荡数据浪潮,塑造智能新纪元

亚信安慧AntDB一直秉承着“技术生态”的理念&#xff0c;不断进行技术创新和功能增强&#xff0c;以保持与先进数据库系统的竞争力。作为一款致力于提升数据库处理性能和稳定性的系统&#xff0c;AntDB在技术上始终保持敏锐的洞察力&#xff0c;不断汲取国内外先进技术的精华&a…

Acwing.1371 货币系统(完全背包问题)

题目 给定 V种货币&#xff08;单位&#xff1a;元&#xff09;&#xff0c;每种货币使用的次数不限。 不同种类的货币&#xff0c;面值可能是相同的。 现在&#xff0c;要你用这 V种货币凑出 N元钱&#xff0c;请问共有多少种不同的凑法。 输入格式 第一行包含两个整数 V…

C#常见Winform窗体效果

目录 1&#xff0c;窗体闪烁。 2&#xff0c;透明非矩形的窗体。 3&#xff0c;窗口显示&#xff0c;退出呈现平滑效果。 4&#xff0c;窗体不在任务栏中显示&#xff1a; 1&#xff0c;窗体闪烁。 /// <summary>/// 窗体闪烁/// </summary>/// <param na…

提质增效|大型汽车制造业运维精细化管理建设实战

项目背景 某大型汽车制造企业随着数字化技术的深入应用&#xff0c;对运维在“质量与效率”方面的精细化管理有了更高的要求。借助云智慧运维指标体系实现了 IT 架构的智能化与可视化&#xff0c;高效解决系统显性问题&#xff0c;积极处理系统隐性问题&#xff0c;提升系统稳…

AttributeError: ‘TestBrowser‘ object has no attribute ‘driver‘

求助大佬&#xff01;&#xff01; 求助大佬&#xff01;&#xff01; 求助大佬&#xff01;&#xff01; AttributeError: TestBrowser object has no attribute driver 代码&#xff1a; test_browser.py from time import sleepfrom appium import webdriverclass Test…

【xinference】(8):在autodl上,使用xinference部署qwen1.5大模型,速度特别快,同时还支持函数调用,测试成功!

1&#xff0c;关于xinference Xorbits Inference (Xinference) 是一个开源平台&#xff0c;用于简化各种 AI 模型的运行和集成。借助 Xinference&#xff0c;您可以使用任何开源 LLM、嵌入模型和多模态模型在云端或本地环境中运行推理&#xff0c;并创建强大的 AI 应用。 Xor…

ChatGPT常用提示词,各行各业如何使用ChatGPT

常规交互提示词&#xff1a; 定义与解释&#xff1a; 请解释XXX术语的含义。阐述一下YYY的概念。 问答模式&#xff1a; 谁是发明了WWW的人&#xff1f;请告诉我太阳系内最大的行星是哪个&#xff1f; 创作类任务&#xff1a; 为我写一首诗&#xff0c;主题是春天的早晨。创作一…

手搓Docker-Image-Creator(DIC)工具(04):DIC的代码实现

此系列的前 3 篇主要是介绍了 Docker 的应用、Docker 编排文件 Dockerfile 的常用命令、以及 Docker 镜像的构建过程等都进行简单介绍。尤其在第 3 篇&#xff0c;讲述了 Docker 运行时、安装用等资源&#xff0c;并在文末提出了存在的不足和改进的方向&#xff0c;本篇就直接从…

安卓Android 架构模式及UI布局设计

文章目录 一、Android UI 简介1.1 在手机UI设计中&#xff0c;坚持的原则是什么1.2 安卓中的架构模式1.2.1 MVC (Model-View-Controller)设计模式优缺点 1.2.2 MVP(Model-View-Presenter)设计模式MVP与MVC关系&#xff1a; 1.2.3 MVVM(Model—View—ViewModel ) 设计模式1.2.4 …

Go项目结构整洁实现|GitHub 3.5k

一、前言 hi&#xff0c;大家好&#xff0c;这里是白泽。今天给大家分享一个GitHub &#x1f31f; 3.5k 的 Go项目&#xff1a;go-backend-clean-arch https://github.com/amitshekhariitbhu/go-backend-clean-architecture 这个项目是一位老外写的&#xff0c;通过一个 HTT…

【MySQL】DML的表操作详解:添加数据&修改数据&删除数据(可cv例题语句)

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C Linux的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

FastAPI Web框架教程 第6章 表单和上传文件

6-1 什么是Form表单 需求场景 很多网站都支持上传文件&#xff0c;比如说&#xff1a;注册时上传头像&#xff1b;填写问卷时上传附件等等。 那么FastAPI是如何来解决文件上传的需求呢&#xff1f; 其实&#xff0c;这个需求不是FastAPI要解决的问题&#xff0c;这是很常见…

阿赵UE学习笔记——23、动画蒙太奇

阿赵UE学习笔记目录   大家好&#xff0c;我是阿赵。   继续学习虚幻引擎的使用方法。上一篇介绍了动画合成功能&#xff0c;这次介绍的动画蒙太奇&#xff0c;和动画合成有很多类似的东西&#xff0c;但本质上却又不同。   蒙太奇是法语“剪接”的意思。所以动画蒙太奇&…