记一道lc扩展题

145 阅读2分钟

300. 最长递增子序列

这道题是lc的原题,字节面试官在这个基础上做了扩展, 原题描述是

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

  示例 1:

输入:nums = [10,9,2,5,3,7,101,18] 输出:4 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。 示例 2:

输入:nums = [0,1,0,3,2,3] 输出:4 示例 3:

输入:nums = [7,7,7,7,7,7,7] 输出:1

原题要求返回长度,但面试官要求返回最长递增子序列数组

思路肯定是动态规划, 定义dp[i] 为以i结尾的数组的最长递增子序列 但是怎么根据动态规划的dp数据和原数据找到最长上升子序列呢

一个思路是 维护一个 Map,key是数字,value是list表示最长子序列,转移状态时维护map;

后来想了下也不用维护一个额外的空间了

观察第一个例子 原数组

[10,9,2,5,3,7,101,18]

对应的dp数组为

[1,1,1,2,2,3,4,4]

观察到 只要找到 对应dp的序列为 4,3,2,1的 有一点 贪心算法的思想

我只要找到比我上一个小的值,我就贪心的的把当前值设置到返回值里边

看下最后的代码

public int[] lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length];
        int res = 0;
        Arrays.fill(dp, 1);
        for(int i = 0; i < nums.length; i++) {
            for(int j = 0; j < i; j++) {
                if(nums[j] < nums[i]){
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            res = Math.max(res, dp[i]);
        }
        int[] resArr = new int[res];
        int index = resArr.length-1;
        for(int i=nums.length-1;i>=0;i--){
            if(index==resArr.length-1&&dp[i]==res){
                resArr[index] = nums[i];
                index--;
                res--;
                continue;
            }
            if(index<resArr.length-1&&dp[i]==res&&nums[i]<resArr[index+1]){
                resArr[index] = nums[i];
                index--;
                res--;
            }
        }
        return resArr;
    }
    @Test
    public void test(){
        for (int i : lengthOfLIS(new int[]{10,9,2,5,3,7,101,18})) {
            System.out.println(i);
        }
    }

总结一下,动态规划很喜欢考,而且可能会基于原题做一些扩展,考察代码能力和思路

另一道题 343. 整数拆分

那同样的。要求反回,具体是哪些数的乘积最大

输入: n = 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36

返回 一个list [3,3,4]; 怎么处理? hash映射解题

public List<Integer> integerBreak(int n) {
    int[] dp = new int[n+1];
    dp[2] = 1;
    Map<Integer,List<Integer>> map = new HashMap<>();
    map.put(2,new ArrayList<Integer>(){{add(1);add(1);}});
    for(int i=3;i<=n;i++){
        for(int j=1;j<i;j++){
            dp[i] = Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
            if(dp[i]==j*(i-j)){
                List<Integer> list = new ArrayList<>();
                list.add(j);
                list.add(i-j);
                map.put(i,list);
            }
            if(dp[i]==j*dp[i-j]){
                List<Integer> list = map.get(i - j);
                List<Integer> newList = new ArrayList<>();
                newList.addAll(list);
                newList.add(j);
                map.put(i,newList);
            }
        }
    }
    return map.get(n);
}