zoukankan      html  css  js  c++  java
  • 两道子序列经典题目

    力扣1143:最长公共子序列

    思路:这是一道经典题,dp[i][j]表示第一个字符串[0,i-1]和第二个字符串[0,j-1]之间公共的子序列个数,每次多比较一个,dp[i][j]可以由dp[i-1][j-1]、dp[i][j-1]、dp[i-1][j]得到。

    class Solution {
        public int longestCommonSubsequence(String s1, String s2) {
            int len1=s1.length();
            int len2=s2.length();
            int[][] dp=new int[len1+1][len2+1];
            //i和j从1开始,防止-1时越界
            for(int i=1;i<=len1;i++)
            {
                for(int j=1;j<=len2;j++)
                {
    
                    if(s1.charAt(i-1)==s2.charAt(j-1))
                        dp[i][j]=dp[i-1][j-1]+1;
                    
    
                    else
                        dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                }
    
            }
            return dp[len1][len2];
        }
    }
    力扣1143

    牛客练习赛70B

    题意:求最短子串长度,要求包含"puleyaknoi"子序列。

    思路:子序列的字符用一个前驱数组维护,指定子序列的上一个字符是什么,这里10个字符没有重复,一维就够了。对子序列的字符每次同步前驱字符的位置,找到子序列的起点。不可以直接记录子序列起点的位置,可能会被最近更新的起点位置覆盖。

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<math.h>
    #include<string>
    #include<map>
    #include<queue>
    #include<stack>
    #include<set>
    #include<sys/types.h>
    #include<unistd.h>
    #define ll long long
    #define inf 0x3f3f3f3f
    using namespace std;
    
    
    char s[100005];
    int num[30];///模式串
    int dp[30];///
    char a[]={"puleyaknoi"};
    int pre[30];///模式串字符的前驱字符
    
    int main()
    {
        int lena=strlen(a);
        for(int i=0;i<lena;i++)
        {
            num[ a[i]-'a' ]=1;
            if( i!=0 )///第一个字符没有前驱
                pre[ a[i]-'a' ]=a[i-1]-'a';
        }
    
        int t;
        scanf("%d",&t);
        while(t--)
        {
            memset(dp,-1,sizeof(dp));///防止起点是0相冲,dp[i]记录字符i作为子序列的起点的位置
            scanf("%s",s);
            int lens=strlen(s);
            int ans=inf;
            for(int i=0;i<lens;i++)
            {
                int x=s[i]-'a';
                if( num[x]==0 )///不是喜欢的字符
                    continue;
                if( s[i]=='p' )///第一个字符,做一下标记,持续更新,后面遇到的字符也会更新
                {
                    dp['p'-'a']=i;
                }
                else
                {
                    ///当前字符x的前驱存在,才可以往后走
                    if(dp[ pre[x] ]!=-1 )
                        dp[ x ]=dp[ pre[x] ];///和前驱同一个起点,根据前驱找到所在子序列的起点,而不是直接指向起点,可能会被最近的新的起点覆盖
                }
                if( s[i]=='i' && dp[ x ]!=-1 )///10个够了,并且i字符有前驱,一直连到p
                    ans=min(ans,i-dp[x]+1);
    
            }
            if(ans==inf)
                printf("-1
    ");
            else
                printf("%d
    ",ans);
        }
        return 0;
    }

    思路扩展:子序列可以出现多次相同字符,则dp数组多开一维,dp[x][j]=dp[pre[x][j].c][pre[x][j].d],dp[x][j]表示当前字母x与模式串中第j个x字母匹配时,最近的起始位置。pre[x][j].c表示模式串中第j个x字母的前一个字母,pre[x][j].d表示模式串中第j个x字母的前一个字母是第几次出现。

  • 相关阅读:
    隆重推出PowerDesinger 12.1.0.1913破解补丁
    Glowcode 6.0 破解手记,.Net IL技术
    爬虫如何抓取到Asp.Net中__doPostBack获取新页面的数据
    谁是股市上的最大受益者
    带强名的.net程序反向工程后汇编中的问题总结
    让所有的实体店成为网店的体验店
    推出网站大鱼搜索
    利用搜索引擎技术抢注域名
    在程序中显示PDF文件不依赖于Arcobat Reader的PDF阅读器开发
    用开源Carrot2的后缀树算法做Web文本聚类
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/13733250.html
Copyright © 2011-2022 走看看