【LeetCode 每日一题】3634. 使数组平衡的最少移除数目——(解法二)排序 + 二分查找

Problem: 3634. 使数组平衡的最少移除数目

文章目录

  • [1. 整体思路](#1. 整体思路)
  • [2. 完整代码](#2. 完整代码)
  • [3. 时空复杂度](#3. 时空复杂度)
      • [时间复杂度: O ( N log ⁡ N ) O(N \log N) O(NlogN)](#时间复杂度: O ( N log ⁡ N ) O(N \log N) O(NlogN))
      • [空间复杂度: O ( log ⁡ N ) O(\log N) O(logN)](#空间复杂度: O ( log ⁡ N ) O(\log N) O(logN))

1. 整体思路

核心问题

同样是求保留最长子序列,使得序列中最大值不超过最小值的 k k k 倍。

算法逻辑

  1. 排序:依然首先对数组进行排序。

  2. 枚举 + 二分查找

    • 遍历数组中的每个元素 nums[i],将其视为保留序列的最小值
    • 我们需要找到数组中满足 val <= nums[i] * k最大元素的位置(或者第一个大于该值的元素位置)。
    • 由于数组是有序的,查找这个位置可以使用 二分查找 (Binary Search)
    • 查找目标 :我们想找第一个严格大于 nums[i] * k 的数的位置。
      • Arrays.binarySearch 的行为是:如果找到,返回索引;如果没找到,返回 -(插入点) - 1。其中插入点是第一个大于搜索值的位置。
      • 代码中的搜索目标设为 nums[i] * k + 1,意图是寻找第一个 ≥ \ge ≥ 这个值的元素位置。或者更准确地说,是寻找值的分界线。
      • 实际上,更直接的逻辑是找 upper_bound(第一个大于 nums[i] * k 的位置)。
  3. 细节解析

    • 优化判断if ((long) nums[i] * k <= nums[n - 1])
      • 如果 nums[i] * k 甚至比数组最大的元素还大(或相等),说明从 i 开始直到数组末尾的所有元素都满足条件,此时不需要二分,j 直接取 n 即可。
      • 否则,我们需要用二分查找确定具体的截止位置 j
    • 二分处理
      • j = Arrays.binarySearch(nums, nums[i] * k + 1):这里试图查找 nums[i]*k + 1
      • 如果数组中没有这个值(大概率),j 会返回负数。
      • j < 0 ? -j - 1 : j:将负数返回值转换为插入点索引。这个索引正好是第一个大于 (或等于,如果刚好存在 val+1nums[i] * k 的位置。这个位置作为右边界(exclusive)是正确的。
      • 注意binarySearch 查找的是精确值。如果用 target + 1,逻辑上有点取巧。更严谨的做法是自己写一个 upperBound 函数查找 nums[i] * k。不过在整数域上,找 > val 和找 ≥ val + 1 是等价的。

2. 完整代码

java 复制代码
import java.util.Arrays;

class Solution {
    public int minRemoval(int[] nums, int k) {
        // 1. 排序
        Arrays.sort(nums);
        
        int maxKeep = 0;
        int n = nums.length;
        
        // 2. 枚举每个元素作为最小值
        for (int i = 0; i < n; i++) {
            // 默认右边界为数组末尾 (exclusive)
            int j = n;
            
            // 目标上限值
            long limit = (long) nums[i] * k;
            
            // 优化:如果当前最小值乘以 k 已经覆盖了整个数组的最大值,
            // 那么从 i 到 n-1 都满足条件,不需要二分。
            // 否则,需要二分查找截止位置。
            if (limit < nums[n - 1]) {
                // 我们要找第一个大于 limit 的数的位置
                // 在整数中,这等价于查找第一个 >= limit + 1 的数的位置
                // 这种做法有个潜在风险:如果 limit + 1 溢出 int 范围,binarySearch 会抛错或行为异常
                // 但这里 binarySearch 接受的是 int key,如果 limit 很大这里需要小心强转问题
                // 假设题目数据范围在 int 内
                int target = (int)limit + 1; // 潜在的溢出点,如果 nums[i]*k 很大
                
                // 使用 Java 内置二分查找
                j = Arrays.binarySearch(nums, target);
                
                // binarySearch 返回值处理:
                // 如果找到,返回非负索引。
                // 如果没找到,返回 (-(insertion point) - 1)。
                // 插入点即为第一个大于 target 的元素位置,或者是数组长度。
                // 我们需要的正是这个插入点作为右边界。
                if (j < 0) {
                    j = -j - 1; 
                } 
                // 如果 j >= 0,说明数组里刚好有 target (limit + 1)
                // 那么 j 指向该元素,作为 exclusive 边界,它左边的元素都 < target,即 <= limit
                // 也是正确的。
            }
            
            // 更新最大保留长度
            maxKeep = Math.max(maxKeep, j - i);
        }
        
        return n - maxKeep;
    }
}

3. 时空复杂度

假设数组 nums 的长度为 N N N。

时间复杂度: O ( N log ⁡ N ) O(N \log N) O(NlogN)

  • 排序 : O ( N log ⁡ N ) O(N \log N) O(NlogN)。
  • 遍历 + 二分
    • 外层循环 N N N 次。
    • 内层二分查找耗时 O ( log ⁡ N ) O(\log N) O(logN)。
    • 这部分总耗时 O ( N log ⁡ N ) O(N \log N) O(NlogN)。
  • 对比双指针
    • 双指针(上一版)是 O ( N log ⁡ N + N ) O(N \log N + N) O(NlogN+N)。
    • 二分版是 O ( N log ⁡ N + N log ⁡ N ) O(N \log N + N \log N) O(NlogN+NlogN)。
    • 虽然大 O 相同,但双指针在第二阶段是 O ( N ) O(N) O(N),通常更快。二分法在常数上略大。

空间复杂度: O ( log ⁡ N ) O(\log N) O(logN)

  • 计算依据
    • 主要消耗来自排序的栈空间。
  • 结论 : O ( log ⁡ N ) O(\log N) O(logN)。
相关推荐
熬夜有啥好7 小时前
数据结构——排序与查找
数据结构
wangluoqi7 小时前
26.2.6练习总结
数据结构·算法
Yvonne爱编码7 小时前
链表高频 6 题精讲 | 从入门到熟练掌握链表操作
java·数据结构·链表
Q741_1477 小时前
C++ 优先级队列 大小堆 模拟 力扣 703. 数据流中的第 K 大元素 每日一题
c++·算法·leetcode·优先级队列·
木井巳7 小时前
【递归算法】二叉搜索树中第K小的元素
java·算法·leetcode·深度优先·剪枝
铉铉这波能秀7 小时前
LeetCode Hot100 中 enumerate 函数的妙用(2026.2月版)
数据结构·python·算法·leetcode·职场和发展·开发
墨有6667 小时前
哈希表从入门到实现,一篇吃透!
数据结构·算法·哈希算法
We་ct7 小时前
LeetCode 228. 汇总区间:解题思路+代码详解
前端·算法·leetcode·typescript
AIpanda8887 小时前
如何借助AI销冠系统提升数字员工在销售中的成效?
算法