- 问题描述
给定一个数组,求该数组最长递增子序列的长度。 - 解决方案1(动态规划)
- dp[i]表示数组中以索引为i的元素结尾的最长递增子序列的长度
- 递推关系:求dp[i+1]时,应该遍历索引0~i的原数组,如果j位置的元素小于索引为i+1的元素,则dp[i+1]应该取dp[j]+1与dp[i+1]的较大值,如此直至循环结束。
- 返回值。应该遍历dp数组,返回其中最大值。
代码如下:
/**
* 给定一个数组,求其最长递增子序列的长度
* @param arr
* @return
*/
public static int maxIncreasingSequence(int[] arr){
if(arr == null)
return 0;
if(arr.length < 2)
return arr.length;
int[] dp = new int[arr.length];
dp[0] = 1;
for(int i = 1;i < arr.length;i ++){
for(int j = 0;j < i;j ++){
if(arr[i] > arr[j] )
dp[i] = Math.max(dp[i],dp[j]+1);
}
}
int res = 0;
for(int i = 0;i < dp.length;i ++)
res = Math.max(res,dp[i]);
return res;
}
- 解决方案2
比较难想到,最长递增子序列和一种叫做 patience game 的纸牌游戏有关,同时利用到了二分查找的思想,详细解释见动态规划设计之最长递增子序列这篇微信推送,解释的非常仔细。
public static int maxIncreasingSequence2(int[] arr){
if(arr == null)
return 0;
if(arr.length < 2)
return arr.length;
//每堆牌的最小值
int[] min = new int[arr.length];
int count = 0;
for(int i = 0;i < arr.length;i ++){
int left = 0,right = count;
while(left < right){
int mid = (left + right) / 2;
if(min[mid] < arr[i])
left = mid + 1;
else if(min[mid] > arr[i])
right = mid;
else
right = mid - 1;
//right = mid - 1;
}
if(left == count)
count ++;
min[left] = arr[i];
}
return count;
}