Leetcode 943. Find the Shortest Superstring

Given an array A of strings, find any smallest string that contains each string in A as a substring.

We may assume that no string in A is substring of another string in A.

Example 1:

Input: [“alex”,“loves”,“leetcode”]
Output: “alexlovesleetcode”
Explanation: All permutations of “alex”,“loves”,“leetcode” would also be accepted.

Example 2:

Input: [“catg”,“ctaagt”,“gcta”,“ttca”,“atgcatc”]
Output: “gctaagttcatgcatc”

Note:

1 <= A.length <= 12
1 <= A[i].length <= 20

给定一个字符串组,找出一个最小长度的串,要求字符串组中所有的字符串都是这个串的子串。

但是除了一般的DFS,因为数据量小,是可以存储所有情况的,因此也可以选择DP解决。
定义DP[i][j]:在包含序列 i 的情况下,以第 j 个字符串结尾,最小长度的串。
其中 i 表示一二进制码,该二进制码的第 k 位若为 1 ,则表示 字符串组中第 k 个字符串已为串的子串;若为 0 ,则表示 字符串组中第 k 个字符串不能在串中找到。
借助于位运算,便可以实现查找第 k 位是否已经加入到序列 i 中 以及 在序列 i 中插入第 k 位使其转移到新的序列状态。
在这里插入图片描述


class Solution {
private:
    map<pair<int,int>,int> mapping;
public:
    string shortestSuperstring(vector<string>& A) {
        int N=A.size();
        vector<vector<short> > dp(1<<N,vector<short>(N,0x3f3f3f3f));
        vector<vector<short> > parent(1<<N,vector<short>(N,-1));
        for(int i=0;i<N;i++)
            dp[1<<i][i]=A[i].size();;
        
        for(register int mark=0;mark < (1<<N);mark++){
            
            for(register int i=0;i<N;i++){
                
                //if i have existed in this subsequence already
                if((mark>>i) & 1 > 0){//if exist
                    int parentMark=mark ^ (1<<i);
                    if(parentMark==0)   //meaningless
                        continue;
                    
                    for(int j=0;j<N;j++){
                        
                        //if i have existed in this subsequence already
                        if((parentMark>>j) & 1 > 0){
                            int pos=overlap(A,j,i);
                            int length=A[i].size()-pos;
                            //salck operation
                            if(dp[mark][i] > dp[parentMark][j]+length){
                                dp[mark][i]=dp[parentMark][j]+length;
                                parent[parentMark][i]=j;
                            }
                            
                        }
                        
                    }
                    
                }
                
            }
        }
        
        //find the min status
        short index=0;
        for(register int i=0;i<N;i++)
            if(dp[(1<<N)-1][i] < dp[(1<<N)-1][index])
                index=i;
        
        stack<char> store;
        for(int i=A[index].size()-1;i>=0;i--)
            store.push(A[index][i]);
        int num=1;
        int lastIndex=index;
        int nowIndex,nowMark=(1<<N)-1;
        while(num<N){
            
            nowMark=nowMark ^ (1<<lastIndex);
            nowIndex=parent[nowMark][lastIndex];
            if(nowIndex==-1)
                cout<<"overstack"<<endl;
            int pos=overlap(A,nowIndex,lastIndex);
            for(int i=A[nowIndex].size()-pos-1;i>=0;i--)
                store.push(A[nowIndex][i]);
            
            lastIndex=nowIndex;
            num++;
        }
        
        //get ans string
        string ans;
        while(!store.empty()){
            ans+=store.top();
            store.pop();
        }
        return ans;
    }
    int overlap(vector<string>& A,int matched,int match){         //return the first not matched element position
        pair<int,int> temp=make_pair(matched,match);
        if(mapping.find(temp)!=mapping.end())
            return mapping[temp];
        int minLen=min(A[matched].size(),A[match].size());
        for(int len=minLen;len>0;len--){
            int i=A[matched].size()-1;
            int j=len-1;
            bool sym=true;
            int num=len;
            while(num){
                if(A[match][j]!=A[matched][i]){
                    sym=false;
                    break;
                }
                j--,i--;
                num--;
            }
            if(sym)
                return mapping[temp]=len;
        }
        return mapping[temp]=0;
    }
};

Note:

  1. 左移 与 右移 运算优先级较低
    计算时加括号提升优先级

  2. 在查找时,不可用 异或运算 来代替 与运算
    在这里插入图片描述
    根据上图可知,在执行 左移 操作后,并不能通过 异或运算来判断第k个字符串是否已经加入序列

字符转的各种转换函数库,用这个库,字符串的各种转换再也不头疼 //-------------字符串转数字-------------- int CString_numberStr_2_int(CString str); int stdString_2_int(std::string str);//std string 字符串转int int std_hexString_2_int(std::string str);//std string 字符串转int double CString_2_double(CString in); double stdString_2_double(std::string str);//std string 字符串转double unsigned int hexString_2_u32(std::string str); //-------------数字转字符串-------------- CString CString_int_2_numberStr(int n); CString CString_int_2_numberStr6(int n); std::string stdString_int_2_numberStr(int a); CString double_2_number_CString(double n); std::string double_2_number_String(double a); CString GetCurrWorkingDir(); //获得当前工作路径,不含最后一个字符“\” CString ascii_2_cstring(int ascii);// 把ascii字符转换成对应的字符,返回cstring类型 //-------------字符串转字符串-------------- std::string CString_2_stdString(CString str); CString stdString_2_CString(std::string str); void CString_2_charP(CString str,char *q); //cstring change to ansi string //-------------判断字符串类型-------------- bool is_a_double_type_string(CString str); //-------------字符串复杂操作-------------- int break_string(std::string instr, std::string subStr, vector<std::string>* subs); //以subStr为标记切割instr为多个单词,存储于subs std::string super_CString::getTimeString(bool fgf);//获得表示当前时间的字符串,fgf表示是否需要分隔符 std::string super_CString::getDateTimeString(bool fgf);//获得表示当前时间和日期的字符串,fgf表示是否需要分隔符 std::string getDateString(bool fgf); //获得表示当前日期的字符串,fgf表示是否需要分隔符 std::string string_trim_LR_space(std::string str);//去除字符串前后的空白字符 std::string string_trim_L_space(std::string str);//去除字符串左边的空白字符 std::string string_trim_R_space(std::string str);//去除字符串右边的空白字符 //-------------GUI相关-------------- CString get_CEdit_text(CEdit* edit); //-------------文件、路径相关-------------- CString calc_CurrWorkingDir_filename(CString str);//返回程序运行的当前路径+filename CString calc_work_full_filename(CString filename,CString path);//path为路径,如果path为空返回程序运行的当前路径+filename,否则返回path+filename。 std::string GetCurrWorkingDir_stdString(); std::string calc_CurrWorkingDir_filename(std::string str); std::string calc_work_full_filename(std::string filename,std::string path);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值