动态规划解决最长上升子序列LIS避坑
LIS最长上升子序列
虽然这个问题归类于动态规划,而且也已经被网上炒来炒去,但是当我第一次看到这个需求,分析来分析去还是没有很好的思路,特意研究了好一阵子,决定还是记录下来,把思路和总结刻下来,不能再同一个地方摔了又摔!
//
动态规划就是每一步都选择最优的,最后结果肯定也是最优的
//
首先需求是这样的:
求数组的最大上升子序列长度,如{1,3,2,4,5}最大上升子序列为1,2,4,5或1,3,4,5。长度为4。
    给定的一个无序数组,找出其中不断上升的数组序列。由于一个无序数组的最大上升子序列可能会有很多个,如果要把这个序列(们)找出来,问题会更加困难一点,暂且只说找出最大长度,这样答案就唯一了。
- 直男癌思路——穷举 -
这个想法是最容易想到的,就是用脚趾头想出的思路。
把所有情况都罗列出来,必定会找到最终答案,这种情况如果数组很大的话,可能就需要银河计算机了。这个方法可不可取视数组情况来定吧。
————
————
- 进阶——找到当前最长的,之前的就放弃 -
从前往后找每个下标位置的元素是取还是舍。
这是没问题的,但是会发现这是一个一对多的检索方式,如果分支足够多的,这个方法可以让你入手一台外星人配置的电脑。
- 换一个方向从后往前找 -
既然从前往后找,会出现很多分支,会浪费很多资源,那么就从后往前找。
    
找以当前元素为最后一个元素时的子序列长度。这样情况就会简单多了,每次遍历都把该长度记录下来,最后遍历一下这个记录长度的数组,找出最大值就可以了。
- 代码实现 -
package com.mine;import java.util.Arrays;public class Lis{public static void main( String[] args ){int[] arr = {1,3,2,4,5};int len = lengthOfArray(arr);System.out.println("result:"+len);}// 对数组长度为0和1的特殊情况进行处理private static int lengthOfArray(int[] arr) {Integer x = checkLength(arr);if (x != null) return x;/* 定义存储当前长度的数组其实我之前想把这里定义为集合这样后边找最大值可以调用max函数但是我的jdk是1.8的,List.of是用不了,鱼和熊掌不可兼得了*/int[] dps = new int[arr.length];Arrays.fill(dps, 1); // 将所有位置初始化为1// 遍历原数组对dps赋值setValueOfDpi(arr, dps);// 遍历dps,查找最大值下标int max = 1;for (int i = 0; i < dps.length; i++) {if (dps[i] > max){max = dps[i];}}return max;}// 这里应该算是核心代码private static void setValueOfDpi(int[] arr, int[] dps) {for (int i = 1; i < arr.length; i++) {for (int j = 0; j < i; j++) {// 这两个条件理解了// 整个问题就好解决了if (arr[j] < arr[i] && dps[j] + 1 > dps[i]){dps[i] = dps[j] + 1;}}}}/** 对数组的长度判断0和1的情况* @param arr* @return*/private static Integer checkLength(int[] arr) {if (arr.length == 0){return 0;}if (arr.length == 1){return 1;}return null;}}
- 总结 -
很多时候看问题会无可避免走进死胡同,牛角尖钻痛了,不妨怀疑下自己,换个方向换个思路,没准就能豁然开朗(话是这么说,要真能时时刻刻做到,我也不至于这么菜了)
————
我一开始也是想从前往后,想一次就找出最终结果,但是暴增的分支让我很头秃,好在面向百度编程,还是让我转过来了,不然我的牛角尖要把墙顶坏了。
动态规划贪心法远不止这些,冰山一角先扣一块下来试试味道先。
啥也不说了,奉上一碗鸡汤,请笑纳!
不要关注我,我会很懒
中指长按二维码领取辣条一包
