【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)。
相关推荐
NAGNIP8 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
颜酱17 小时前
单调栈:从模板到实战
javascript·后端·算法
CoovallyAIHub20 小时前
仿生学突破:SILD模型如何让无人机在电力线迷宫中发现“隐形威胁”
深度学习·算法·计算机视觉
CoovallyAIHub20 小时前
从春晚机器人到零样本革命:YOLO26-Pose姿态估计实战指南
深度学习·算法·计算机视觉
CoovallyAIHub20 小时前
Le-DETR:省80%预训练数据,这个实时检测Transformer刷新SOTA|Georgia Tech & 北交大
深度学习·算法·计算机视觉
CoovallyAIHub20 小时前
强化学习凭什么比监督学习更聪明?RL的“聪明”并非来自算法,而是因为它学会了“挑食”
深度学习·算法·计算机视觉
CoovallyAIHub21 小时前
YOLO-IOD深度解析:打破实时增量目标检测的三重知识冲突
深度学习·算法·计算机视觉
NAGNIP1 天前
轻松搞懂全连接神经网络结构!
人工智能·算法·面试
NAGNIP1 天前
一文搞懂激活函数!
算法·面试
董董灿是个攻城狮1 天前
AI 视觉连载7:传统 CV 之高斯滤波实战
算法