最长递增子序列的动态规划的求解

1. 问题描述:求解最长递增子序列的长度

输入:第一行输入的是数组的长度 

第二行开始输入的是数组中的元素

输出:最长递增子序列的长度

输入 4 2 3 1 5 6 

输出 4 (因为 2 3 5 6组成了最长递增子序列)

2. ① 对于这种求解最优解的经典问题,我们一般是采用动态规划来进行求解,其中动态规划的核心是找出dp公式或者状态转移方程

之前我们使用动态规划去解决一般是创建一维数组或者二维数组来构建出dp表,利用之前的历史上dp表中的值进行相关的处理求解出这个过程中的几个最大值,最小值,相加减来得出dp表的当前元素的值,所以我们会想,先创建一个一维数组,因为数组中选择的元素的范围在进行变化,所以dp表表示的值为截取到当前范围内最长的递增子序列是多少,但是发现填dp表的当前的值的时候发现我们是不能够确定当前的字符与之前的哪些字符去比较,我们是不能够确定将当前的字符该容纳到哪个字符序列才可以得到当前dp的当前的值,可能不容纳进这些字符序列可能得到当前可以选择的范围内最长递增子序列的长度,所以这些都是不能够确定,这个时候是不能够推导出dp公式或者状态转移方程的,所以这个思路是写不出代码的

② 这道题目是比较经典的,有人想出了其它的dp解法,其中的思路是比较难想出来的,但是我们可以通过借鉴其中的思路与代码来帮助我们理解dp解法

思路是:dp[i]表示的意思是必须包含以dp[i]结尾的最长递增子序列,在字符串中选择一个开始位置,表示的是以当前字符结尾的最长递增子序列的字符,依次去扫描这个字符之前的字符,假如发现当前字符大于之前的字符那么比较当前的最长子序列的长度与当前dp[i] + 1的值的大小来更新当前最长递增子序列的长度,当扫描完当前字符i之前的字符那么这个时候说明找到了以当前字符结尾的最长递增子序列的长度,把这个值赋值给dp[i]

需要注意的是最后还需要扫描一下dp数组,看一下哪一个dp[i]最大,因为我们不知道以哪个字符结尾的字符序列为最长的递增子序列,所以需要扫描一下,最后找到dp[i]的最大值返回,这是与之前的dp数组不同的一个点,以前是返回dp数组的最后一个元素就可以了,因为最后一个元素就是我们需要求解的最优解

3. 但是使用这种方法来解决时间复杂度有点高,为O(n ^ 2),与暴力破解的时间复杂度差不多

4. 具体的代码如下:

import java.util.Scanner;
import static java.lang.Math.max;
public class Main {
	//测试数据: 6 4 2 3 1 5 6 输出4
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int arr[] = new int[n];
		for(int i = 0; i < n; i++){
			arr[i] = sc.nextInt();
		}
		System.out.println(solution(arr));
		sc.close();
	}

	private static int solution(int[] arr){
		int dp[] = new int[arr.length];
		dp[0] = 1;
		for(int i = 1; i < arr.length; i++){
			int cnt = 1;
			for(int j = i - 1; j >= 0; j--){
				if(arr[j] < arr[i]){
					cnt = max(cnt, dp[j] + 1) ;
				}
			}
			dp[i] = cnt;
		}
		int maxV = 0;
		for(int i = 0; i < arr.length; i++){
			maxV = max(maxV, dp[i]);
		}
		return maxV;
	}
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值