代码之家  ›  专栏  ›  技术社区  ›  user22847357

如何输出字典中最小的一个最短的超弦?

  •  0
  • user22847357  · 技术社区  · 2 年前

    问题是: 给定n个字符串si,找出最短的字符串S,使得每个si都是S中的子字符串。 当有多个可能的答案时,输出应该是字典中最小的一个。

    例如:测试用例:{qgw、qsopd、qwrw、wckumn} 答案应该是“qgwckumbqsopdqwrw”,但我的代码输出是“qGWqsopdjwrwckumn”。 我认为问题在于solve函数没有考虑所有可能的prev字符串。 请帮我找出应该在哪里修改代码,非常感谢!

    以下是我的代码:

    class Solution {
        vector<vector<string>> req;
        string merge(string &a, string &b) 
        {
            int n=a.size(), m=b.size(), len=1, idx=0;
            while(len<=min(n, m))
            {   if(a!=""&&b!=""){
                    if(a!=b&&b.find(a)!= string::npos)
                    {   a="";
                    }
                    else if(a.substr(n-len)==b.substr(0, len))
                    {
                        idx=len;
                    }
                }
    
                len++;
            }
            
            string res=b.substr(idx); // idx is distance to non-overlap and res is the non-overlap str
            return res;
        }
    
        string solve(vector<string> &words, int prev, int mask, int n, vector<vector<string>> &dp)
        //prev:parent word, mask:track which word has been selected 
        {   
            if(dp[prev][mask]!="") return dp[prev][mask];// check if the dp is empty
            string res="";
            int minLen=INT_MAX;
            for(int i=0; i<n; i++)
            {
                if(mask&(1<<i)) continue; //check if the i th word has been used
                string temp=req[prev][i]+solve(words, i, mask|(1<<i), n, dp);
                int temp_size=temp.size();
                if(temp_size<minLen) 
                {
                    minLen=temp.size();
                    res=temp;
                }
            }
    
            return dp[prev][mask]=res;
        }
    
    public:
        string shortestSuperstring(vector<string>& words)
        {
            int n=words.size();
            sort(words.begin(), words.end());
    
            req.resize(n, vector<string> (n, ""));
            vector<vector<string>> dp(n, vector<string> ((1<<(n+1)), ""));
            for(int i=0; i<n; i++)
            {
                for(int j=0; j<n; j++)
                {
                    if(i==j) continue;
                    req[i][j]=merge(words[i], words[j]);
                }
            }
    
            string ans="";
            int minLen=INT_MAX;
            int mask=0;
            for(int i=0; i<n; i++)
            {
                string temp=words[i]+solve(words, i, mask|(1<<i), n, dp);
                cout<<"temp: "<<temp<<"\n";
                int temp_size=temp.size();
                if(temp_size<minLen) 
                {
                    minLen=temp.size();
                    ans=temp;
                }
    
            }
            return ans;
        }
    };
    
    1 回复  |  直到 2 年前
        1
  •  2
  •   Kozydot    2 年前

    现有代码中的主要问题是,当存在多种可能性时,它没有考虑到字典中最小的要求。它只考虑字符串长度。

    您可以对代码进行一些修改以解决此问题:

    1. 更改您的 merge 函数返回一对整数: 重叠部分的长度和第二字符串的索引。 这将允许您跟踪词典编纂顺序。
    2. 在您的 solve 函数,比较时 temp_size 具有 minLen , 当长度相等时,还要考虑字典顺序。 您可以通过在 声明如下:
    if(temp_size < minLen || (temp_size == minLen && temp < res)) 
    {
        minLen = temp_size;
        res = temp;
    }
    
    1. 在您的 shortestSuperstring 函数,类似地添加辅助 考虑词典编纂顺序的条件:
    if(temp_size < minLen || (temp_size == minLen && temp < ans)) 
    {
        minLen = temp_size;
        ans = temp;
    }