当前位置: 首页> 文旅> 旅游 > 专业制作视频的软件_乐陵310seo_全媒体运营师培训费用_周口seo推广

专业制作视频的软件_乐陵310seo_全媒体运营师培训费用_周口seo推广

时间:2025/7/13 6:17:54来源:https://blog.csdn.net/2302_76739243/article/details/146461087 浏览次数:0次
专业制作视频的软件_乐陵310seo_全媒体运营师培训费用_周口seo推广

前面两篇内容我们都是在做有关回溯问题的组合应用

今天的题目主题是:回溯法在切割问题的应用

题目一:分割回文串

问题描述

131. 分割回文串 - 力扣(LeetCode)

给你一个字符串 s,请你将 s 分割成一些 子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

示例 1:

输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]

示例 2:

输入:s = "a"
输出:[["a"]]

提示:

  • 1 <= s.length <= 16
  • s 仅由小写英文字母组成

解题步骤

在做这题之前我们需要明确回文串是什么东西👇

那么我们解决这个问题就可以分为分割字符串和判断回文串两个part

运用回溯法分割字符串其实和组合问题是类似的思路

我们需要按照字符串顺序,在所有可能位置砍上一刀,形成不同的字符串碎片

那么为了不错过任何一种可能,就需要按顺序遍历

下面就来尝试使用回溯三部曲!

1.确定函数返回值及参数

依旧使用backtracking这个名字,没有返回值的要求,参数呢传入我们需要使用的字符串s以及一个开始索引startindex即可

这个开始索引是不断变大的,意味着每次砍第一刀下去,第一个碎片的长度在慢慢变大,这也是我们有序分割的重要环节

void backtracking(string s,int startindex)

2.确定终止条件

按照最简单的思路,和之前的组合问题一样,我们会在叶子结点取到该过程的一个答案,再做个对应题目限制的判断,合适就加入result中, 

那么我们的分割也是这样,在叶子节点结束分割,把整个字符串剁碎了,

但需要注意的是,在叶子节点我们得到的不是碎片,而是虽然碎了但仍旧可以拼成完整s的组合体

就像你买了一只烤鸭,咔咔剁了几刀,你拿到手的是所有鸭子碎片而不是只有一个鸭屁股

那么在这种情况下,加入判断回文子串的代码好像有点不方便

所以我们改为在单层递归的时候做判断而不是在终止条件做判断

这样做同时也更省事了,如果你切了一刀发现这个不是回文串就没必要再切下去了

就好比切到鸭屁股的话扔掉就好了,没必要把鸭屁股也剁碎留着

还有一点需要明确的是分割完毕的表示方法,

在参数列表中我们不断传递的startindex实际上就对应我们砍下去的那一刀,

那么只要这个索引大于等于回文串长度就是切完了

if(startindex>=s.size()){

        result.push_back(path);

        return;

}

 3.确定单层遍历操作

还是同样的逻辑,最外层确定第一刀位置

切下来以后加入path中,再递归切第二刀...

递归结束后需要pop加入值,做一个回溯

除了以上切割操作,我们还需要加入判断回文串的代码

这一个部分为使效率最大化可以加在把碎片加入path的代码前

也就是说符合回文才加入path,否则直接return

判断回文串我们可以另设函数所以单层遍历操作应该如下:

for(int i=startindex;i<s.size();i++){

        if(isPalindrome(...){//这个函数等会再想!

                string str = s.substr(startindex,i-startindex+1);//当前碎片是【startindex,i】

                path.push_back(str);//是回文串!切下来放进path中!

        }else{

                continue;//不是就跳出!

        }

        backtracking(s,i+1);

        path.pop_back();

}       

补充:

s.substr(pos, len)

substr()是C++语言函数,主要功能是复制子字符串,要求从指定位置开始,并具有指定的长度。如果没有指定长度_Count或_Count+_Off超出了源字符串的长度,则子字符串将延续到源字符串的结尾。 

 ok那么回溯算法的步骤我们已经完成了,还剩下判断回文串的逻辑需要写

4.判断回文串

按照回文串的概念,我们只需要一个指针从头开始,一个指针从尾开始

不断同频比较两个字符是否相等就可以了

那么需要的参数就是这个字符串碎片

返回值设为bool类型

bool isPalindrome(string s,int start,int end){

       for(int i=start,j=end;i<j;i++,j--){

                if(s[i] !=s[j]){

                        return false;

                }

        }

        return true;

}

合并所有代码,并在主函数中传参调用即可!完整代码看下面👇! 

code

class Solution {
public:vector<string> path;vector<vector<string>> result;bool isPalindrome(string s,int start,int end){for(int i=start,j=end;i<j;i++,j--){if(s[i]!=s[j]){return false;}}return true;}void backtracking(string s,int startindex){if(startindex>=s.size()){result.push_back(path);return;}for(int i=startindex;i<s.size();i++){if(isPalindrome(s,startindex,i)){string str=s.substr(startindex,i-startindex+1);path.push_back(str);}else{continue;}backtracking(s,i+1);path.pop_back();}}vector<vector<string>> partition(string s) {backtracking(s,0);return result;}
};

题目二:复原IP地址

问题描述

93. 复原 IP 地址 - 力扣(LeetCode)

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

  • 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245""192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。

示例 1:

输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]

示例 2:

输入:s = "0000"
输出:["0.0.0.0"]

示例 3:

输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

提示:

  • 1 <= s.length <= 20
  • s 仅由数字组成

解题步骤

参照上一题,我一开始写了以下代码,

主要思路就是无情分割,直到最后,

在每一步分割中使用函数判断是否符合要求

合理就加入path,逐渐组成IP地址

最后在叶子节点处加入正确的IP到result中

但是发现在单层递归中很难处理,

所以我们需要改变一下整个回溯的过程,按照这个题目的特点,给出量身定制的方案

class Solution {

public:

    string path;

    vector<string> result;

    bool isOK(string str){

        if(str.empty() || str.size()>3 || str[0]=='0'){

            return false;

        }

        int num=stoi(str);

        return num>=0&&num<=255;

    }

    void backtracking(string s,int startindex){

        if(startindex>=s.size()){

            result.push_back(path);

            return;

        }

        for(int i=startindex;i<s.size();i++){

            string str=s.substr(startindex,i-startindex+1);

            if(isOK(str)){

                path+=str;

               //@#@¥¥#%#!@@¥#@%!@?????

            }else{

                break;

            }

            backtracking(s,i+1);

            path.pop_back();

        }

    }

    vector<string> restoreIpAddresses(string s) {

        if(s.size()<4 || s.size()>12){

            return result;

        }

        backtracking(s,0);

        return result;

    }

};

 再审审题!

IP地址是只能有4段的,每一段不超过3个数字,

所以这里我们需要把段数作为切割完成的标志,不能再用索引指到最后,

这样就相当于做数学证明题有条件没用上,那一般来说都是证不出来的!!!

那么和段数有关的还有IP地址中的 '.' (点),

为了一举两得(实现判断段数和加点)我们可以用点数来代表段数,

点数为3意味着段数为4嘛!

重新走一边回溯三部曲

1.确定函数返回值及参数

按照上面的思路,我们得加入段数作为参数,搭配startindex共同表示分割情况

startindex关乎下刀点,不能丢掉,把刀丢了还怎么切嘛!

void backtracking(string s,int startindex,int pointnum)

2.确定终止条件

上面已经捋清楚了:点数为3意味着段数为4

但是加入第三个点后我们还没有判断剩下部分,也就是第四段是否符合要求

所以这个最后一部分的合法性要放在这个终止条件中进行判断

合法后再加入到result中

if(pointnum==3){

        if(isValid...){//判断合法性等会再说!

                result.push_back(s);

        }

        return;      

}

 3.确定单层遍历操作

在单层遍历中我们需要往s中加点(题目说了可以通过在 s 中插入 '.' 来形成),修改pointnum,递归,回溯

最外层遍历依旧代表第一刀(或者说上一刀)的位置,

这样才能确保第二🔪是从剩下的部分切的

切下来一段就需要判断是否合法

如果合法,在s的这个位置后面加上点

再让pointnum+1

递归backtracking函数

pointnum回溯,

s回溯

如果不合法,那么直接结束

for(int i=startindex;i<s.size();i++){

        if(isValid...){

                s.insert(s.begin()+i+1,'.');//加点

                pointnum++;

                backtracking(s,i+2,pointnum);//加入点后要再后挪一位!

                pointnum--;

                s.erase(s.begin()+i+1);

        }

        else

                break;

}

4.编写判断合法性函数

作为一个判断类的函数,返回值肯定是bool类型,

参数是为了传入待判断的片段,所以依旧是s,start,end

在函数体中利用if 判断IP地址一段的数字区间是否在[0,255],每一段开头第一个是否为0,区间长度是否小于等于3,该片段是否为空

否就返回false,都没有踩雷就返回true

bool isValid(string& s,int start,int end){   

        if (start > end || end - start + 1 > 3) {

            return false; // 片段为空或长度超过3

        }

        if (s[start] == '0' && start != end) {

            return false; // 前导0不合法

        }

        string str = s.substr(start, end - start + 1);

        int num = stoi(str);

        return num >= 0 && num <= 255;

}        

 最后整合代码,传入对应参数,在主函数中调用即可,

此外,在主函数中还可以加入一个剪枝,

如果字符串长度明显不符合IP地址的长度就不用调用回溯算法了

if(s.size()<=0 || s.size()>12)

        return result;

完整代码在下方! 

code 

class Solution {
public:vector<string> result;bool isValid(string& s,int start,int end){if (start > end || end - start + 1 > 3) {return false; // 片段为空或长度超过3}if (s[start] == '0' && start != end) {return false; // 前导0不合法}string str = s.substr(start, end - start + 1);int num = stoi(str);return num >= 0 && num <= 255;}     void backtracking(string s,int startindex,int pointnum){if(pointnum==3){if(isValid(s,startindex,s.size()-1)){//最后一段!result.push_back(s);}return;}for(int i=startindex;i<s.size();i++){if(isValid(s,startindex,i)){s.insert(s.begin()+i+1,'.');//加点pointnum++;backtracking(s,i+2,pointnum);pointnum--;s.erase(s.begin()+i+1);}elsebreak;}}vector<string> restoreIpAddresses(string s) {if(s.size()<=0 || s.size()>12)return result;backtracking(s,0,0);return result;}
};

关键字:专业制作视频的软件_乐陵310seo_全媒体运营师培训费用_周口seo推广

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: