题目描述
首先定义上升字符串,对于任意的0<i<len(s),s[i]≥s[i−1],比如aaa,abc是,acbd不是
给n个上升字符串,选择任意个拼起来,问能拼出来的最长上升字符串长度?
思路
这道题首先想到利用动态规划的思路,动态规划的基本思想就是:
问题的最优解如果可以由子问题的最优解推导得到,则可以先求解子问题的最优解,在构造原问题的最优解;若子问题有较多的重复出现,则可以自底向上从最终子问题向原问题逐步求解。
因此这道题可以理解成两个问题:
- 在已知前n-1个单词的最长上升字符串组合的情况下,寻找第n个字符串和前n-1个字符串构成的最长上升字符串的最长上升字符串问题。
- 保证前n-1个字符串构成的最长上升字符串长度一定小于等于前n个字符串构成的最长上升字符串长度。
代码
首先解决字符串排序问题,要保证前n-1个字符串构成的最长上升字符串长度一定小于等于前n个字符串构成的最长上升字符串长度,需要让首字符小的字符串排在前面,另外要考虑"aaa"和“abb”比较时要让“aaa”排在前面。所以代码中除了使用快排对字符串数组进行排序外,还用bigger函数进行了比值判断。
其次寻找最长上升字符串的过程中使用了history数组来记录前n-1个字符串在n-1次求解过程中所能组成最长上升字符串的长度。
public class LongestAscString {
/**
* 按照首尾字符和长度排序,"aaaa"应排在"abc"之前
*/
public static boolean bigger(char[] a, char []b){
if (a[0] > b[0]){
// 首字母大返回true
return true;
}else if (a[0] < b[0]){
return false;
}else {
// 首字母相等则比较末尾
if (a[a.length-1] > b[b.length-1] ){
return true;
}else {
return false;
}
}
}
/**
* 对字符串数组进行快排
* @param s
* @return
*/
public static String[] sortFirst(String[] s, int low, int high){
if (low < high){
int start = low;
int stop = high;
String tmp = s[low];
char[] ctmp = tmp.toCharArray();
while (low < high){
char[] clow = s[low].toCharArray();
char[] chigh = s[high].toCharArray();
while (bigger(chigh,ctmp) && low < high){
high--;
chigh = s[high].toCharArray();
}
s[low] = s[high];
while (!bigger(clow,ctmp) && low < high){
low++;
clow = s[low].toCharArray();
}
s[high] = s[low];
}
s[low] = tmp;
sort(s, start, low-1);
sort(s, low+1, stop);
return s;
}else {
return s;
}
}
/**
* 找到每一单词前最长的ascstring
* @param s
* @return
*/
public static int longest(String[] s){
// 最大长度
int max = 0;
// 先按首字母排序
s = sortFirst(s, 0, s.length-1);
// 用于记录排序后每个单词前最长的ascString长度
int[] history = new int[s.length];
for (int i = 0; i < s.length; i++){
// i=0时需初始化history
if (s[i].toCharArray().length > history[i]){
history[i] = s[i].toCharArray().length;
if (s[i].toCharArray().length > max){
max = s[i].toCharArray().length;
}
}
for (int j = 0; j < i; j++){
char[] sj = s[j].toCharArray();
char[] si = s[i].toCharArray();
// 首尾字符符合规则且根据history判断是否有必要更新
if (sj[sj.length-1] <= si[0] && history[j]+si.length>history[i]){
// 更新max
if (history[j]+si.length > max){
max = history[j]+si.length;
}
history[i] = history[j]+si.length;
}
}
}
return max;
}
public static void main(String[] args){
String[] s = new String[]{"dddd", "aadd", "ffxz", "cv"};
for (String a : sortFirst(s, 0, s.length-1)){
System.out.println(a);
}
System.out.println(longest(s));
}
}