动态规划经典题目-最长单调递增子序列

一、题目描述

​ 最大单调子序列(Maximum Monotone Subsequence )-如果一个数列中第i个元素最少也和第i - 1个元素一样大,那么该序列单调递增。求字符串的一个最大单调递增子序列。

示例:

输入:s = "subsequence" 
输出:beee

二、解题思路

1. 定义状态

​ 设dp[i]表示字符串s的前i个字符的最大单调递增子序列的长度。

2. 定义状态转移方程

当s[i] >= s[k]时,有 d p [ i ] = m a x ( d p [ k ] ) + 1 dp[i] = max(dp[k]) + 1 dp[i]=max(dp[k])+1,其中 1 <= k < i

否则 d p [ i ] = 0 dp[i] = 0 dp[i]=0,其中1 <= k < i 。

总结为如下方程:

d p [ i ] = { m a x ( d p [ k ] ) + 1 , s [ i ] ≥ s [ k ] 1 , s [ i ] < s [ k ] dp[i] = \begin{cases} max(dp[k]) + 1,&s[i] \geq s[k] \\ 1 ,&s[i] < s[k] \end{cases} dp[i]={max(dp[k])+1,1,s[i]s[k]s[i]<s[k]

此状态方程理解起来很简单。

3. 初始化

​ 显然dp[0]初始化为0。

三、代码实现

/**
 * 最大单调子序列
 *
 *  @author hh
 *  @date 2021-5-16 20:52
 */
public class MaxMonotoneSubsequence {

    /**
     * 求字符串的最大单调子序列
     *
     * @param s 字符串
     * @return 最大单调子序列组成的字符串
     */
    public String maxMonotoneSubsequence(String s){
        int[] dp = new int[s.length() + 1];
        //记录最大单调子序列的数组索引
        int[] indexes = new int[s.length() + 1];
        //初始化dp[0]为0
        dp[0] = 0;
        indexes[0] = -1;
        for(int i = 1; i <= s.length(); i++){
            int parentIndex = 0;
            for(int k = 1; k < i; k++){
                if(s.charAt(i-1) >= s.charAt(k-1) && dp[i] <= dp[k]){
                    dp[i] = dp[k];
                    parentIndex = k;
                }
            }
            indexes[i] = parentIndex;
            dp[i] += 1;
        }
        return findPath(s,indexes, this.getMaxValueIndex(dp,Arrays.stream(dp).max().getAsInt())  );
    }

    public int getMaxValueIndex(int[] dp,int maxValue){
        for(int i = dp.length - 1; i >=0; i-- ){
            if(dp[i] == maxValue){
                return i;
            }
        }
        return 0;
    }

    /**
     * 构建一条最长路径
     *
     * @param s 源字符串
     * @param indexes 索引数组
     * @param maxDepth 最长数
     * @return 子序列字符串
     */
    public String findPath(String s,int[] indexes,int maxDepth){
        LinkedList<Character> characterList = new LinkedList<>();
        while (maxDepth != 0){
            characterList.addFirst(s.charAt(maxDepth - 1));
            maxDepth = indexes[maxDepth];
        }
        return characterList.stream().map(String::valueOf).collect(Collectors.joining());
    }

    public static void main(String[] args){
        String s = "subsequence";
        MaxMonotoneSubsequence maxMonotoneSubsequence = new MaxMonotoneSubsequence();
        System.out.println(maxMonotoneSubsequence.maxMonotoneSubsequence(s));
    }
}

四、执行结果

结果图片

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值