题解 | 最长上升子序列(三)

最长上升子序列(三)

https://www.nowcoder.com/practice/9cf027bf54714ad889d4f30ff0ae5481

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * retrun the longest increasing subsequence
     * @param arr int整型一维数组 the array
     * @return int整型一维数组
     */
    public int[] LIS (int[] arr) {
        // write code here
        if (arr == null || arr.length == 0) {
            return new int[0];
        }

        int n = arr.length;
        // maxLen[i] 记录以 arr[i] 结尾的最长递增子序列的长度
        int[] maxLen = new int[n];
        // tails 记录每个长度的递增子序列结尾的最小值
        int[] tails = new int[n];
        int len = 0; // 当前最长递增子序列的长度

        // 1. 遍历原数组,利用二分查找填充 tails 和 maxLen
        for (int i = 0; i < n; i++) {
            int left = 0, right = len - 1;
            // 二分查找第一个大于等于 arr[i] 的元素位置
            while (left <= right) {
                int mid = left + (right - left) / 2;
                if (tails[mid] < arr[i]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }

            // 将 arr[i] 放入 tails 数组
            tails[left] = arr[i];
            // 如果是在末尾追加,说明最大长度增加了
            if (left == len) {
                len++;
            }
            // 记录当前元素对应的 LIS 长度(索引从 0 开始,所以长度是 left + 1)
            maxLen[i] = left + 1;
        }

        // 2. 倒序遍历,还原字典序最小的序列
        int[] res = new int[len];
        int currLen = len;
        // 设一个初始安全最大值,题目范围最大 10^9,Integer.MAX_VALUE 足够大
        int lastVal = Integer.MAX_VALUE;

        for (int i = n - 1; i >= 0; i--) {
            // 如果长度匹配,并且当前值严格小于后面的值(保证递增)
            if (maxLen[i] == currLen && arr[i] < lastVal) {
                res[currLen - 1] = arr[i];
                lastVal = arr[i];
                currLen--;
            }
        }

        return res;
    }
}

全部评论

相关推荐

找工作勤劳小蜜蜂:矛盾是没有实习,就是没实战经验,公司不想要,公司不要,你就没有实习,你就进入死循环,另外你的项目不是社会现在有大量岗位存在行业用的,云存储人员早就饱和。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务