• Lintcode--006(交叉字符串)


    Given three strings: s1, s2, s3, determine whether s3 is formed by the interleaving of s1 and s2.

    Example

    For s1 = "aabcc", s2 = "dbbca"

    • When s3 = "aadbbcbcac", return true.
    • When s3 = "aadbbbaccc", return false.
    Challenge

    O(n2) time or better.

    标签 

     动态规划  字符串处理

    解题:

    1. 错解:最初,自己通过思考想出了一个解决方案。就是从字符串s3中抽取顺序抽取出字符串s2的所有字符,将s3中剩下的字符与s2进行比较,如果相等,那么就返回true,否则返回false。依照这种思路,最终通过一些修改,也只能达到66%正确,很可能是方案覆盖不完整。比如测试用例:aa,ab,abaa,就过不了。当s1,s2同时匹配的时候,这里存在一个策略问题。

    代码:

    class Solution {
    public:
    /*
    * Determine whether s3 is formed by interleaving of s1 and s2.
    * @param s1, s2, s3: As description.
    * @return: true of false.
    /
    bool isInterleave(string s1, string s2, string s3) {
    // write your code here
    //第一步还是理解问题,什么是交错字符串,然后根据特点想出解决方法;
    
    */
    bool isInterleave(string s1, string s2, string s3) {
        int a=s1.size(),b=s2.size(),c=s3.size();
        int count=0;
        int num=-1;
        int m[c];
        string s;
        if(a==0){
            return s2==s3;
        }
        if(b==0){
            return s1==s3;
        }
    
        for(int i=0;i<c;i++){
            m[i]=1;
        }
        for(int i=0;i<a;i++){
            for(int j=0;j<c;j++){
                if(m[j]&&(s1[i]==s3[j])){
                    m[j]=0;
                    ++count;
                    break;
                }
            }
        }
        num=c-count;
        int k=-1;
        if((count==a)&&(num==b)){
    
            for(int i=0;i<b;i++){
                if(k==c-1){
                    break;
                }
                for(int j=0;j<c;j++){
                    if(m[j]&&(s2[i]==s3[j])){
                        num=num-1;
                        k=j;
                        break;
                    }
                }
            }
            if(num==0){
                return true;
            }
            else{
                return false;
            }
    
            /*for (int i=0;i<num;i++){
                for(int j=0;j<c;j++){
                    if(m[j]!=0){
                        s[i]=s3[j];
                    }
                }
            }
            return s.compare(s2);
            */
        }
        
        else{
            return false;
        }
    }
    };

    2. 正解:正解就是二维动态规划

    分析:两个字符串的问题,大部分都可以用matched[i][j]表示第一个字符串前i个字符第二个字符串前j个字符的匹配情况来解决。

    在这里,令动态规划矩阵为matched[l1][l2]表示s1取l1长度(最后一个字母的pos是l1-1),s2取l2长度(最后一个字母的pos是l2-1),是否能匹配s3的l1+12长度。

    那么,我们有:
    matched[l1][l2] = s1[l1-1] == s3[l1+l2-1] && matched[l1-1][l2] || s2[l2 - 1] == s3[l1+l2-1] && matched[l1][l2-1]

    解释:如果对于第三个字符串的前l1+l2个元素  和 第一个字符串的前l1个元素和第二个字符串的前l2个元素能满足要求的话,那么就有两种情况:

             (1)第三个字符串的最后一个元素s3[l1+l2-1],要么等于第一个字符串的最后一个元素s1[l1-1],并且matched[l1-1][l2]也满足要求。

             (2)第三个字符串的最后一个元素s3[l1+l2-1],要么等于第二个字符串的最后一个元素s2[l2 - 1],并且matched[l1][l2-1]也满足要求。

    这就是动态规划,递归的思想。

    代码如下:

    折腾了很久,还是有问题:

    自己根据动态规划写的:

     达到80% 正确,追究原因,因为定义的bool型的二维数组有问题;

    class Solution {
    public:
        /**
         * Determine whether s3 is formed by interleaving of s1 and s2.
         * @param s1, s2, s3: As description.
         * @return: true of false.
         */
        bool isInterleave(string s1, string s2, string s3) {
            // write your code here
            // 先写出最基本的条件;
            
            if(s3.length()!=s1.length()+s2.length()){
                return false;
            }
            
            bool matched[s1.length()+1][s2.length()+1];//布尔类型初始值是0,也就是false;
          
            matched[0][0]=true;
            for(int j=0;j<s2.length();j++){ //这里也有点问题,要严格按照递归来编码。
                if(s3.substr(0,j)==s2.substr(0,j)){
                    matched[0][j+1]=true;
                }
            }
            for(int i=0;i<s1.length();i++){ //这里也有点问题,要严格按照递归来编码。
                if(s3.substr(0,i)==s1.substr(0,i)){
                    matched[i+1][0]=true;
                }
            }
            
            for(int i=1;i<s1.length()+1;i++){
                for(int j=1;j<s2.length()+1;j++){
                    if((s3[i+j-1]==s1[i-1]&&matched[i-1][j])||(s3[i+j-1]==s2[j-1]&&matched[i][j-1]))
                    {
                        matched[i][j]=true;
                    }
         
                }
            }
            return matched[s1.length()][s2.length()];
        }
    };

    别人正确的:C++

    class Solution {
    public:
        /**
         * Determine whether s3 is formed by interleaving of s1 and s2.
         * @param s1, s2, s3: As description.
         * @return: true of false.
         */
        bool isInterleave(string s1, string s2, string s3) {
            // write your code here
            if(s3.length()!=s1.length()+s2.length())
                return false;
            if(s1.length()==0)
                return s2==s3;
            if(s2.length()==0)
                return s1==s3;
            vector<vector<bool> > dp(s1.length()+1,vector<bool>(s2.length()+1,false));
            dp[0][0] = true;
            for(int i=1;i<=s1.length();i++)
                dp[i][0] = dp[i-1][0]&&(s3[i-1]==s1[i-1]);
            for(int i=1;i<=s2.length();i++)
                dp[0][i] = dp[0][i-1]&&(s3[i-1]==s2[i-1]);
            for(int i=1;i<=s1.length();i++)
            {
                for(int j=1;j<=s2.length();j++)
                {
                    int t = i+j;
                    if(s1[i-1]==s3[t-1])
                        dp[i][j] = dp[i][j]||dp[i-1][j];
                    if(s2[j-1]==s3[t-1])
                        dp[i][j] = dp[i][j]||dp[i][j-1];
                }
            }
            return dp[s1.length()][s2.length()];
        }
    };

     别人正确的:java

    public class Solution {
        /**
         * Determine whether s3 is formed by interleaving of s1 and s2.
         * @param s1, s2, s3: As description.
         * @return: true or false.
         */
        public boolean isInterleave(String s1, String s2, String s3) {
            // write your code here
            if(s1.length() + s2.length() != s3.length())
                return false;
            // if(s1.equals("")&& s2.equals(s3))
            //     return true;
            // if(s2.equals("")&&s1.equals(s3))
            //     return true;
            boolean[][] matched= new boolean[s1.length()+1][s2.length()+1];//在java中布尔型的数组可行;
            matched[0][0]= true;
            for(int i1=1;i1<= s1.length(); i1++){
                if(s3.charAt(i1-1) == s1.charAt(i1-1))
                    matched[i1][0] = true;
            }
            for(int i2= 1;i2<= s2.length();i2++){
                if(s3.charAt(i2-1) == s2.charAt(i2-1))
                    matched[0][i2] = true;
            }
            for(int i1=1;i1<=s1.length(); i1++){
                char c1 = s1.charAt(i1-1);
                for(int i2 = 1;i2<= s2.length();i2++){
                    int i3 = i1+ i2;
                    char c2 = s2.charAt(i2- 1);
                    char c3 = s3.charAt(i3 -1);
                    if(c1 == c3)
                        matched[i1][i2] =matched[i1][i2] || matched[i1-1][i2];
                    if( c2== c3)
                        matched[i1][i2] = matched[i1][i2] || matched[i1][i2-1];
                        
                }
            }
            return matched[s1.length()][s2.length()];
        }
    };

     最后更正类型定义后:

    class Solution {
    public:
        /**
         * Determine whether s3 is formed by interleaving of s1 and s2.
         * @param s1, s2, s3: As description.
         * @return: true of false.
         */
        bool isInterleave(string s1, string s2, string s3) {
            // write your code here
            // 先写出最基本的条件;
            
            if(s3.length()!=s1.length()+s2.length()){
                return false;
            }
            
            vector<vector<bool> > matched(s1.length()+1,vector<bool>(s2.length()+1,false));//为何如此定义要清楚!!
          
            matched[0][0]=true;
            for(int j=0;j<s2.length();j++){
                if(s3[j]==s2[j]){
                    matched[0][j+1]=matched[0][j];
                }
            }
            for(int i=0;i<s1.length();i++){
                if(s3[i]==s1[i]){
                    matched[i+1][0]=matched[i][0];
                }
            }
            
            for(int i=1;i<s1.length()+1;i++){
                for(int j=1;j<s2.length()+1;j++){
                    if((s3[i+j-1]==s1[i-1]&&matched[i-1][j])||(s3[i+j-1]==s2[j-1]&&matched[i][j-1]))
                    {
                        matched[i][j]=true;
                    }
         
                }
            }
            return matched[s1.length()][s2.length()];
        }
    };

    代码有毒,折腾了一天。= =!

    总结:

    1)递归能写出比较清晰简单的代码,但是有比较高的时间复杂度;

    2)在递归不满足条件的情况下,动态规划是个比较好的选择;

    3)一般来说,独立变量的个数决定动态规划的维度,例如l1和l2独立变化,所以用了二维动态规划。

  • 相关阅读:
    javascript的全局变量和局部变量
    Google Analytics统计代码GA.JS
    display和visible的区别
    div+css实现带三角箭头提示框
    css兼容IE8的一个简便方法 [转]
    20个值得关注最新的jQuery Plugins
    分享40多个新鲜的jQuery图片和内容幻灯插件
    JQuery插件让图片旋转任意角度且代码极其简单
    Android UI dp sp
    MaxScript用二进制读取方式获取Max文件版本
  • 原文地址:https://www.cnblogs.com/Allen-rg/p/5803493.html
Copyright © 2020-2023  润新知