回文分区(如何弄清楚如何使用DFS)

Palindrome Partitioning (how to figure out how to use DFS)

本文关键字:何使用 DFS 弄清楚 分区 回文      更新时间:2023-10-16

我的一般问题是如何弄清楚如何使用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];
    }
};

你到底在问什么?你有正确的工作代码和你的非工作代码,这没有什么不同。

我想我可以指出您的代码的几个问题 - 可能对您有所帮助:

  1. palindrome()函数中,您应该将s[i]s[len-1-i]进行比较,而不仅仅是if中的s[len-i],因为在前一种情况下,您将比较第一个元素(具有索引 0(与不存在的元素(索引 len(。这可能是helper()卡住的原因。

  2. 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;
 
 }
}