分割问题举例,以给定的输入字符串str=“aabbacdd”为例,将str分割成一些子串,使每个子串都是回文子串,输出所有符合的子串。注意:子串的长度不定,说明你可以任意的分割。
处理这个问题,除了使用穷举的思路,在逻辑上也没有更好的思路了。因此分割问题也是回溯算法的典型。将图中的流程进行总结。需要res保存结果,path记录分割片段。对于每一层来说,需要一个startIndex变量记录分割起点,终点在startIndex右侧任意取定。这一层的子串确定后,判定子串是否符合要求。如符合,则从下一个位置处递归开始取下一个子串。
注意:回溯的过程如果能够用树图来做的话是最直观的。
vector<vector<string>> res;
vector<string> path;
bool isPalindrome(string s){
int left=0,right=s.size()-1;
while(left<=right){
if(s[left]!=s[right]){return false;}
}
return true;
}
void BackTrack(string s, int startIndex){
//终止条件,使startIndex==s.size(),才能够保证最后一个字符也计算在内,左闭右开写法
if(startIndex==s.size()) {res.push_back(path); return ;}
for(int i=startIndex;i<s.size();++i){
//剪一个枝
string s1=s.substr(startIndex, i-startIndex+1);
if(!isPalindrome(s1)){continue;}
path.push_back(s1); //startIndex所指已经是下一个字符
BackTrack(s, i+1);
path.pop_back();
}
}
复原ip地址问题。给定一组字符串str="10012116",输出所有可能的ip地址。
ip地址的格式为类似“192.168.1.12”,由4段数字+3个“.”构成,每段数字属于(0,255),且不能含有前导0,即“091”。但是“0”可以。这个过程也是穷举的,因此适合用回溯来做。用树图表示这个过程。如下。
//
vector<string> path;
vector<string> res;
bool isValid(string s){
//s可能为"0","00","000"
if(s.size()==1){return (s>="0" && s<="9")? true : false;}
if(s.size()==2){return s[0]!="0" ? true : false;}
if(s.size()==3){
if(s[0]=="0")return false;
int num=0;
for(int i=2;i>=0;--i){num+=(s[i]-"0")*pow(10,2-i);}
return num<=255;
}
//s有更多的位数
return false;
}
void IPRecovery(string str, int startIndex){
if(path.size()==3){
//path有3个时,从startIndex剩余的都是第四个字段了
if(!isValid(str.substr(startIndex, str.size()-startIndex))){return ;}
//所有能递归到终止条件的IP段都是正确的
//处理IP
string ip;
for(int i=0;i<path.size();++i){
ip+=path[i];
ip+=".";
}
ip+=str.substr(startIndex, str.size()-startIndex);
res.push_back(path);
return;
}
for(int i=startIndex;i<str.size();++i){
string s=str.sub(startIndex, i-startIndex+1);
if(s.size()>3)break;
if(!isValid(s)){return;}
path.push_back(s);
IPRecovery(str, i+1);
path.pop_back();
}
}
子集问题举例。
排列问题举例。
N皇后问题。
最后,举一个数独的问题。