https://www.nowcoder.com/practice/6d9d69e3898f45169a441632b325c7b4?tpId=37&tqId=21247&tPage=2&rp=&ru=/ta/huawei&qru=/ta/huawei/question-ranking
https://blog.csdn.net/u013309870/article/details/62037674
描述
给定一个整型数组,取出最小数量的数字,使得剩下的数组,呈现递增的趋势,求最长的子串长度
输入
5 6 7 1 2 8
输出
4(即 5 6 7 8)
思路
动态规划
- 先求出原数组各个值对应的递增次序
- 5 6 7 1 2 8 原数组
- 1 2 3 1 2 4 递增次序
- 递增次序什么意思呢?
- 就比如上面的5 6 7 是一个递增子串,那么对应的次序就是1 2
- 后面的1 2又是一个递增子串,次序又变成了1 2 3
- 最后一个8 既可以是5 6 7 的子串,又可以是 1 2的子串,这里就需要比较7对应的次序和2对应的次序哪个大,显然7对应的次序是3要大一些,所以8的次序就是4
- 递增次序也可理解为当前数的最长递增子串长度
- 如何求各个数的递增序列?
- 声明一个int[] dp,原数组为int[] nums,保存原数组中各个数对应的最长递增子串长度(也就是上面的递增次序),全都赋值1(所有的次序都是从1开始累加)
- 遍历原数组nums[i],找到dp[0]到dp[i-1]之间的最大值dp[j],并且要满足nums[j]<nums[i],于是dp[i] = dp[j]+1
代码
public static int[] findUpSubstr(int[] nums){
int[] dp = new int[nums.length];
dp[0] = 1;
for(int i=1;i<dp.length;i++){
dp[i] = 1;
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
//必须要和当前的值比较,如果直接赋值dp[j]+1会导致后面满足nums[j]<nums[i]的数覆盖
//这一步变相的保存了dp[0]到dp[i-1]之间的最大值dp[j]
dp[i] = Math.max(dp[i],dp[j]+1);
//dp[i] = dp[j]+1;
}
}
}
return dp;
}
这是上面两个连接的结合,加上了输出最后的递增序列
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int num = sc.nextInt();
int[] nums = new int[num];
for(int i=0;i<num;i++){
nums[i] = sc.nextInt();
}
int[] upDp = findUpSubstr(nums);
//输出最后的递增序列
//getUpAry(nums,upDp);
int[] lowDp = findLowSubstr(nums);
int length=0;
for(int i=0;i<nums.length;i++){
length = Math.max(length,upDp[i]+lowDp[i]);
}
System.out.println(nums.length-length+1);
}
}
public static int[] findUpSubstr(int[] nums){
int[] dp = new int[nums.length];
dp[0] = 1;
for(int i=1;i<dp.length;i++){
dp[i] = 1;
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
//必须要和当前的值比较,如果直接赋值dp[j]+1会导致后面满足nums[j]<nums[i]的数覆盖
dp[i] = Math.max(dp[i],dp[j]+1);
//dp[i] = dp[j]+1;
}
}
}
return dp;
}
public static int[] findLowSubstr(int[] nums){
int[] dp = new int[nums.length];
dp[dp.length-1] = 1;
for(int i=dp.length-2;i>=0;i--){
dp[i] = 1;
for(int j=dp.length-1;j>i;j--){
if(nums[j]<nums[i]){
//必须要和当前的值比较,如果直接赋值dp[j]+1会导致后面满足nums[j]<nums[i]的数覆盖
dp[i] = Math.max(dp[i],dp[j]+1);
//dp[i] = dp[j]+1;
}
}
}
return dp;
}
public static void getUpAry(int[] nums,int[] dp){
int index=0,len=0;
//找到递增序列中的最后一个数的索引 index
for(int i=0;i<nums.length;i++){
if(len<dp[i]){
len = dp[i];
index = i;
}
}
//存放递增队列
int[] ary = new int[len];
//ary的索引
int k = 0;
ary[k++] = nums[index];
//倒序查找 保证dp[i+1] = dp[i]+1并且nums[i+1]>nums[i]
//index表示上一个满足条件的索引
for(int i=index-1;i>0;i--){
if(dp[index] == dp[i]+1 && nums[index]>nums[i]){
ary[k++] = nums[i];
index = i;
}
}
for(int i=ary.length-1;i>=0;i--){
System.out.print(ary[i]+" ");
}
}
}