算法-删除元素后最大固定点数目-典型最长增长序列算法

题目

给你一个整数数组 nums

如果 nums[i] == i,则位置 i 被称为 固定点

允许你从数组中删除 任意 数量的元素(包括零个)。在每次删除后,剩余元素 向左移动,并且下标从 0 开始重新分配。

返回一个整数,表示在执行任意次数的删除操作后,可以获得的 最大 固定点数量。

示例 1:

输入: nums = 0,2,1

输出: 2

解释:

  • 删除 nums[1] = 2。数组变为 [0, 1]
  • 现在,nums[0] = 0nums[1] = 1,因此两个下标都是固定点。
  • 因此,答案为 2。

题解

思路学习:本题跟俄罗斯套娃信封问题的解题思路一致,解决本题核心思考:

要求i==numsi,当i增加的时候numsi也需要增加,也就是连续增长序列,也即本题求最长连续增长序列

当数组中numsi的元素x需要移动i-x步时,比x大的元素numsj=z需要的移动步数必须大于i-x步时才能让i,j同时成为固定点位,因为numsi移动的i-x步的时候,numsj也会移动的i-x步,如果numsj需要的移动步数小于numsi时,则两者不能同时成为固定点位。需要维护numi开始的最长增长序列长度和numsj开始的最长增长序列长度。

java 复制代码
class Solution {
    public int maxFixedPoints(int[] nums) {
        List<int[]> a = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {
            int x = nums[i];
            if (i >= x) {
                a.add(new int[]{x, i - x});
            }
        }
        return maxEnvelopes(a);
    }

    // 354. 俄罗斯套娃信封问题
    private int maxEnvelopes(List<int[]> envelopes) {
        //对位置排序,小的元素在前,大的元素在后
        envelopes.sort((a, b) -> {
            if (a[0] == b[0]) {
                return b[1] - a[1];
            }
            return a[0] - b[0];
        });

        List<Integer> g = new ArrayList<>();
        for (int[] e : envelopes) {
            int h = e[1];
            //最长增长序列模版思路:用二分在数组找对应的位置,然后更新元素值
            // 允许 LIS 相邻元素相等
            int j = upperBound(g, h); 
            if (j < g.size()) {
                g.set(j, h);
            } else {
                g.add(h);
            }
        }
        return g.size();
    }

    private int upperBound(List<Integer> g, int target) {
        int left = -1, right = g.size(); // 开区间 (left, right)
        while (left + 1 < right) { // 区间不为空
            // 循环不变量:
            // nums[right] > target
            // nums[left] <= target
            int mid = left + (right - left) / 2;
            if (g.get(mid) > target) {
                right = mid; // 范围缩小到 (left, mid)
            } else {
                left = mid; // 范围缩小到 (mid, right)
            }
        }
        return right;
    }
}
相关推荐
致Great3 小时前
DeepSeek Harness插件开发实战教程:我让它自己写了一个 arXiv 搜索插件
算法
罗西的思考7 小时前
【Agent OS / AIOS】AOHP 深度解读:当 OS 开始为 Agent 而设计
人工智能·算法·机器学习
民乐团扒谱机8 小时前
【微实验】组合优化matlab实战(马科维茨投资模型):在收益与风险之间,寻找最优的人生配比
大数据·人工智能·算法·机器学习·数学建模·matlab·组合优化
Nil2088 小时前
leetcode 160相交链表
算法·leetcode·链表
迷途之人不知返9 小时前
算法系列2:滑动窗口
算法
Herbert_hwt10 小时前
C语言零基础入门:循环控制与数据类型详解
c语言·数据结构·算法
晚风醉蝶11 小时前
1-6-插入排序-InsertionSort
java·数据结构·排序算法
Tyler_TXZ11 小时前
C++C语言之——二叉树
c语言·开发语言·数据结构·c++·二叉树
Tisfy11 小时前
LeetCode 3090.每个字符最多出现两次的最长子字符串:二重循环 / 滑动窗口
算法·leetcode·字符串·题解·模拟·双指针·滑动窗口
-dzk-11 小时前
【技巧】LC 136.只出现一次的数字
算法·异或