求字符串中最常升序子串的长度
从字符串中按顺序挑选出若干字符(不一定相邻)组成一个新串,称为“子串”。如果子串中相邻的字符或者相等,或者后一个比前一个大,则称为“升序子串”。编程求出输入字符串的最长升序子串的长度。
观察不难发现此问题可以归类为动态规划问题,具有最有子结构性质,写出状态转移方程即可:
len[0]=1;(最小为1)
len[i] = max{ len[j] } + 1 (j<i && str.charAt(j)<=str.charAt(i))
1 package com; 2 3 import java.util.Arrays; 4 5 public class LIS { 6 7 public static void main(String[] args) { 8 for (String s : args) { 9 lisLength(s); 10 } 11 } 12 13 public static void lisLength(String str) { 14 int[] len = new int[str.length()]; 15 len[0] = 1; 16 for (int i = 1; i < len.length; i++) { 17 int max = 1; 18 boolean change = false; 19 for (int j = 0; j < i; j++) { 20 if (len[j] >= max && str.charAt(j) <= str.charAt(i)) { 21 max = len[j]; 22 change = true; 23 } 24 } 25 len[i] = change ? max + 1 : 1; 26 } 27 System.out.print(Arrays.toString(len)); 28 } 29 }
运行参数:abcdecbadgh aaaa ababab dcba
运行结果:[1, 2, 3, 4, 5, 4, 3, 2, 5, 6, 7][1, 2, 3, 4][1, 2, 2, 3, 3, 4][1, 1, 1, 1]
以上为4个字符串case输出的结果,每个数组中最大的数即为该字符串的最长升序子串的长度,为方便理解程序运行过程全部打印输出。
时间复杂度O(n*n)。
扩展:
一道笔试题目:
在一个数组中删除最少数目的元素是其剩余元素先严格单调递增后严格单调递减(假设如果数组本身是严格单调的也符合条件)
例如:9,5,6,7,5,6,5,3,1
可删除9和5(第二个)即可:5,6,7,6,5,3,1
输出结果为删除元素个数:2
分析:问题可拆分为两部分,先求最长递增,再求最长递减,最长递减可以通过逆置转化为最长递增问题,问题的本质就变为求最长递增序列,即转化为以上问题,读者可自行解决此问题。