关于寻找两个字符串中最长子序列的问题

首先先来介绍一下最长子序列是什么
按照我的理解,最大子序列首先是两个串中相同的字符组成的,在两个字符串中,相同的字符可以不连续,但是必须字符的下标在字符串中是一次递增的。
举个简单的例子:
String “abdcegs”;
String “wbcasq”;
在这两个串中子序列有“as”,“bcs‘’
最大子序列为“bcs”

这种题我一共遇到两个解法,现在分享出来

第一种解法:递归解决

解法思路:
首先判断两个字符串的第一个字符是否相等
如果相等,则求两个去掉第一个字符的的子序列+1;
如果不相等,则求(去掉第一个字符的第一个字符串与第二个字符串的子序列)和(第一个字符串与去掉第一个字符的第二个字符串的子序列)

代码实现(java)

   public static int f(String s1, String s2) {

        if(s1.length()==0||s2.length()==0) 
            return 0;

        if(s1.charAt(0)==s2.charAt(0))
            return f(s1.substring(1),s2.substring(1))+1;
        else
            return Math.max(f(s1.substring(1),s2),f(s1,s2.substring(1)));
    }

解法二:动态规划
解法思路:
实现步骤

注意:每次字符相同时,需要判断 矩阵[当前位置y轴-1][当前位置x轴-1]的最大值+1;

代码实现(java)

    public static int f(String s1, String s2) {
        int[][] s=new int[s1.length()+1][];
        for(int i=0;i<s.length;i++){
            s[i]=new int[s2.length()+1];
        }//初始化二维数值

        for(int i=1;i<s.length;i++){
            for(int m=1;m<s[i].length;m++){
                if(s1.charAt(i-1)==s2.charAt(m-1)){
                    s[i][m]=f1(s,i,m)+1;
                }
            }
        }
       return f1(s,s.length,s[0].length);
    }
    public static int f1(int[][] s,int n,int m){//找出矩阵[n-1][m-1]的最大值;
        int  max=0;//记录最大值
        for(int j=0;j<n;j++){
            for(int k=0;k<m;k++){
                if(max<s[j][k]){
                    max=s[j][k];
                }
            }
        }
        return max;
    }

矩阵图

对于第二种解决思路的优化:
当前第二种解决思路,每次判断字符相等后,又要进入两层循环去找最大值。
可以将两层循环改为一层
解决方案
定义一个数组i[ ];数组i[ ]是存放对应横下标位置每次改变的值
代码实现(java)

    public static int f(String s1, String s2) {
        int[][] s=new int[s1.length()+1][];
        for(int i=0;i<s.length;i++){
            s[i]=new int[s2.length()+1];
        }//初始化二维数值
        int[] c=new int[s2.length()+1];//!改变的地方

        for(int i=1;i<s.length;i++){
            for(int m=1;m<s[i].length;m++){
                if(s1.charAt(i-1)==s2.charAt(m-1)){
                    s[i][m]=f1(c,m)+1;//!改变的地方
                    if(c[m]<s[i][m]){//!改变的地方
                        c[m]=s[i][m];
                    }
                }
            }
        }
       return f1(c,s[0].length);
    }
    public static int f1(int[] s,int m){//找出数组c[m-1]的最大值    ! !改变的地方
        int  max=0;//记录最大值
        for(int j=0;j<m;j++){//!改变的地方
                if(max<s[j]){
                    max=s[j];
                }
        }
        return max;
    }

矩阵图与上面一样

对以上算法再进行优化
去f1( )函数
思路:当判断字符不等后与(横坐标-1)和(纵坐标-1)的最大值相等
这样每次相等时,坐标(x,y)的值= 坐标(x-1,j-1)的值+1

public static int f(String s1, String s2) {
        int[][] s=new int[s1.length()+1][];
        for(int i=0;i<s.length;i++){
            s[i]=new int[s2.length()+1];
        }//初始化二维数值


        for(int i=1;i<s.length;i++){
            for(int m=1;m<s[i].length;m++){
                if(s1.charAt(i-1)==s2.charAt(m-1)){
                    s[i][m]=s[i-1][m-1]+1;//!改变的地方
                }else{//!改变的地方
                    int max=Math.max(s[i][m-1], s[i-1][m]);
                    s[i][m]=max;
                }
            }
        }
       return s[s.length-1][s[0].length-1];//改变的地方
    }

矩阵图

以上就是我的所有见解,望斧正。
如果有志同道合的朋友可以一起来讨论聊天。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值