回文分区(如何弄清楚如何使用DFS)
Palindrome Partitioning (how to figure out how to use DFS)
我的一般问题是如何弄清楚如何使用DFS。这似乎是我知识的薄弱部分。我的想法很模糊,但当问题发生变化时经常卡住。这给我带来了很多困惑。
对于这个问题,我陷入了如何使用递归编写DFS的困扰。给定一个字符串s
,分区s
使得分区的每个子字符串都是回文。
返回所有可能的回文分区s
。
例如,给定s = "aab"
,
返回
[
["aa","b"],
["a","a","b"]
]
我的第一次尝试卡在帮助程序函数的循环中。然后通过互联网搜索,我发现bool palindrome(string s)
可以写成不同的签名。
bool palindrome(string &s, int start, int end)
这导致了正确的解决方案。
这是我最初尝试的代码:
class Solution {
public:
bool palindrome(string s)
{
int len = s.size();
for (int i=0;i<len/2; i++)
{
if (s[i]!=s[len-i])
return false;
}
return true;
}
void helper( int i, string s, vector<string> &p, vector<vector<string>> &ret)
{
int slen = s.size();
if (i==slen-1&&flag)
{
ret.push_back(p);
}
for (int k=i; k<slen; k++)
{
if (palindrome(s.substr(0,k)))
{
p.push_back(s.substr(0,k)); //Got stuck
}
}
i++;
}
vector<vector<string>> partition(string s) {
vector<vector<string>> ret;
int len=s.size();
if (len==0) return ret;
vector<string> p;
helper(0,s,p,ret);
return ret;
}
};
正确的一个:
class Solution {
public:
bool palindrome(string &s, int start, int end)
{
while(start<end)
{
if (s[start]!=s[end])
return false;
start++;
end--;
}
return true;
}
void helper( int start, string &s, vector<string> &p, vector<vector<string>> &ret)
{
int slen = s.size();
if (start==slen)
{
ret.push_back(p);
return;
}
for (int i=start; i<s.size(); i++)
{
if (palindrome(s, start, i))
{
p.push_back(s.substr(start,i-start+1));
helper(i+1,s,p,ret);
p.pop_back();
}
}
}
vector<vector<string>> partition(string s) {
vector<vector<string>> ret;
int len=s.size();
if (len==0) return ret;
vector<string> p;
helper(0,s,p,ret);
return ret;
}
};
编辑2014年12月4日:我看到了一些使用动态编程的方法,但无法完全理解代码。
尤其是。 isPalin[i][j] = (s[i] == s[j]) && ((j - i < 2) || isPalin[i+1][j-1]);
为什么j-I<2
而不是j-I<1
?
class Solution {
public:
vector<vector<string>> partition(string s) {
int len = s.size();
vector<vector<string>> subPalins[len+1];
subPalins[0] = vector<vector<string>>();
subPalins[0].push_back(vector<string>());
bool isPalin[len][len];
for (int i=len-1; i>=0; i--)
{
for (int j=i; j<len; j++)
{
isPalin[i][j] = (s[i]==s[j])&&((j-i<2)||isPalin[i+1][j-1]);
}
}
for (int i=1; i<=len;i++)
{
subPalins[i]=vector<vector<string>>();
for (int j=0; j<i; j++)
{
string rightStr=s.substr(j,i-j);
if (isPalin[j][i-1])
{
vector<vector<string>> prepar=subPalins[j];
for (int t=0; t<prepar.size(); t++)
{
prepar[t].push_back(rightStr);
subPalins[i].push_back(prepar[t]);
}
}
}
}
return subPalins[len];
}
};
你到底在问什么?你有正确的工作代码和你的非工作代码,这没有什么不同。
我想我可以指出您的代码的几个问题 - 可能对您有所帮助:
-
在
palindrome()
函数中,您应该将s[i]
与s[len-1-i]
进行比较,而不仅仅是if
中的s[len-i]
,因为在前一种情况下,您将比较第一个元素(具有索引 0(与不存在的元素(索引len
(。这可能是helper()
卡住的原因。 -
在
helper()
函数中flag
未初始化。在for
循环中,结束条件应该是k<slen-1
而不是k<slen
,因为在后一种情况下,您将省略检查包含字符串终端符号的子字符串。此外,在helper()
结束时增加i
是没有意义的。最后,缩进在helper()
函数中很混乱。
不确定为什么使用 DFS - 图形的含义是什么,这里的顶点和边是什么?至于递归在这里是如何工作的:在helper()
函数中,你开始检查长度增加的子字符串是否是回文。如果找到回文,则将其放入p
向量(表示您当前的分区(,并尝试通过递归调用helper()
将字符串的其余部分分解为回文。如果您成功了(即,如果整个字符串完全划分为回文(,您将p
向量(当前分区(的内容放入ret
(所有找到的分区的集合(中,然后清除p
以准备下一个分区的分析(清除p
是通过递归调用helper()
之后pop_back()
调用来实现的(。另一方面,如果您未能将字符串完全分解为回文,则p
也会被清除,但不将其内容转移到ret
(这是因为对最后一段字符串的递归调用 - 不是回文 - 返回而不调用helper()
以获取最终符号,因此不会发生p
推入ret
(。因此,您最终会在ret
中拥有所有可能的回文分区。
嗨~这是我使用 DFS + 回溯的代码。
class Solution
{
public:
bool isPalindrome (string s) {
int i = 0, j = s.length() - 1;
while(i <= j && s[i] == s[j]) {
i++;
j--;
}
return (j < i);
}
void my_partition(string s, vector<vector<string> > &final_result, vector<string> &every_result ) {
if (s.length() ==0)
final_result.push_back(every_result);
for (int i =1; i <= s.length();++i) {
string left = s.substr(0,i);
string right = s.substr(i);
if (isPalindrome(left)) {
every_result.push_back(left);
my_partition(right, final_result, every_result);
every_result.pop_back();
}
}
}
vector<vector<string>> partition(string s) {
vector<vector<string> > final_result;
vector<string> every_result;
my_partition(s, final_result, every_result);
return final_result;
}
};
我已经使用回溯完成了回文分区。这里使用了深度优先搜索,想法是拆分给定的字符串,使前缀是一个回文。现在向量中的 push 前缀探索离开该前缀的字符串,然后最终弹出最后一个插入的元素,花时间回溯是形式上的,选择元素,在没有它的情况下探索并取消选择它。
enter code here
#include<iostream>
#include<vector>
#include<string>
using namespace std;
bool ispalidrome(string x ,int start ,int end){
while(end>=start){
if(x[end]!=x[start]){
return false;
}
start++;
end--;
}
return true;
}
void sub_palidrome(string A,int size,int start,vector<string>&small, vector < vector < string > >&big ){
if(start==size){
big.push_back(small);
return;
}
for(int i=start;i<size;i++){
if( ispalidrome(A,start,i) ){
small.push_back(A.substr(start,i-start+1));
sub_palidrome(A,size,i+1,small,big);
small.pop_back();
}
}
}
vector<vector<string> > partition(string A) {
int size=A.length();
int start=0;
vector <string>small;
vector < vector < string > >big;
sub_palidrome(A,size,start,small,big);
return big;
}
int main(){
vector<vector<string> > sol= partition("aab");
for(int i=0;i<sol.size();i++){
for(int j=0;j<sol[i].size();j++){
cout<<sol[i][j]<<" ";
}
cout<<endl;
}
}
- 在C++中使用双 DFS 查找树的直径
- 矢量堆栈对 |使用 dfs 的树中的最长路径
- 使用指针和引用,无法弄清楚为什么DFS无限重复
- 使用 DFS 在图形中查找最低成本
- 使用非递归 DFS 检测有向图中的周期
- 使用 ranges-v3 实现 DFS
- 使用BFS/DFS解决编程任务
- 使用 DFS 枚举子集
- 图形:如何使用 DFS 检测无向图中的周期
- 使用 bgl 使用 dfs 构建搜索树
- 使用 LLVM 的 libc++ 时,__1 符号从何而来?
- 在std::cout之后使用std::cin时,换行符从何而来
- 实现迷宫树以在DFS,BFS中使用
- 如何使用 dfs O(n) 打印图形的 MaxPath
- 回文分区(如何弄清楚如何使用DFS)
- 使用 DFS 进行拓扑排序
- 为什么以及在何处在C++中使用引用和指针
- 使用DFS进行海报打印
- 基例如何影响使用递归函数的哪些行
- 使用DFS检查无向图中的循环