【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. 整体思路

核心问题

我们需要从数组 nums移除最少 的元素,使得剩余的子数组满足:
max ⁡ ( sub ) ≤ min ⁡ ( sub ) × k \max(\text{sub}) \le \min(\text{sub}) \times k max(sub)≤min(sub)×k

这个问题等价于:找到最长的子序列(或子数组),满足最大值不超过最小值的 k k k 倍

因为我们想移除的越少越好,所以就是要保留的越多越好。

算法逻辑:排序 + 滑动窗口

  1. 排序

    • 首先将数组 nums 从小到大排序。
    • 排序后,对于任意一段连续的子数组 nums[i...j],其最小值必然是 nums[i],最大值必然是 nums[j](或 nums[j-1],取决于窗口定义)。
    • 这使得我们可以在 O ( 1 ) O(1) O(1) 时间内确定任意区间的极值。
  2. 滑动窗口(双指针)

    • 我们枚举每一个元素 nums[i] 作为保留序列的最小值
    • 然后我们需要找到一个最大的范围 (即最大的 j),使得该范围内所有元素都满足 ≤ n u m s [ i ] × k \le nums[i] \times k ≤nums[i]×k。
    • 由于数组已排序,nums[j] 是单调递增的。当 i 向右移动(最小值变大)时,满足条件的上限(最大值)只可能变大或不变,因此 j 指针不需要回退。这就是典型的滑动窗口模式。
    • 对于每个 ij 向右延伸直到不满足条件。
    • 此时,窗口大小 j - i 就是以 nums[i] 为最小值时能保留的最长序列长度。
    • 维护全局最大保留长度 maxKeep
  3. 计算结果

    • 最小移除数量 = 总长度 n - 最大保留数量 maxKeep

2. 完整代码

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

class Solution {
    // 函数目标:求最小移除数量,使得剩余元素中 max <= min * k
    public int minRemoval(int[] nums, int k) {
        // 1. 排序
        // 这是使用滑动窗口的前提,确保最小值在左,最大值在右
        Arrays.sort(nums);
        
        int maxKeep = 0; // 记录能保留的最大元素个数
        int n = nums.length;
        int j = 0; // 滑动窗口的右边界 (exclusive 或 inclusive 取决于逻辑)
        
        // 2. 遍历每个元素作为窗口的左边界 (即保留序列的最小值)
        for (int i = 0; i < n; i++) {
            // 滑动右边界 j
            // 条件:只要 nums[j] 不超过 nums[i] 的 k 倍,就可以纳入窗口
            // 使用 (long) 转换防止乘法溢出 int 范围
            while (j < n && nums[j] <= (long) nums[i] * k) {
                j++;
            }
            // 此时,窗口范围是 [i, j-1]
            // nums[j] 是第一个不满足条件的数 (或者 j==n)
            // 所以保留的元素个数为 j - i
            maxKeep = Math.max(maxKeep, j - i);
        }
        
        // 3. 返回需要移除的元素个数
        // 总数 - 最多能保留的个数
        return n - maxKeep;
    }
}

3. 时空复杂度

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

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

  • 排序Arrays.sort 是主导操作,耗时 O ( N log ⁡ N ) O(N \log N) O(NlogN)。
  • 滑动窗口
    • 外层循环 i 从 0 到 N − 1 N-1 N−1。
    • 内层 while 循环中的 j 也是从 0 增加到 N N N。j 指针从不回退。
    • 因此,双指针遍历的总操作次数是 2 N 2N 2N,即 O ( N ) O(N) O(N)。
  • 总计 : O ( N log ⁡ N ) + O ( N ) = O ( N log ⁡ N ) O(N \log N) + O(N) = O(N \log N) O(NlogN)+O(N)=O(NlogN)。

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

  • 计算依据
    • 除了常数个变量,主要的额外空间消耗来自于排序的栈空间。
  • 结论 : O ( log ⁡ N ) O(\log N) O(logN)。
相关推荐
波波0072 小时前
每日一题:.NET 的 GC是如何分代工作的?
算法·.net·gc
风暴之零2 小时前
变点检测算法PELT
算法
深鱼~2 小时前
视觉算法性能翻倍:ops-cv经典算子的昇腾适配指南
算法·cann
李斯啦果2 小时前
【PTA】L1-019 谁先倒
数据结构·算法
梵刹古音2 小时前
【C语言】 指针基础与定义
c语言·开发语言·算法
啊阿狸不会拉杆2 小时前
《机器学习导论》第 5 章-多元方法
人工智能·python·算法·机器学习·numpy·matplotlib·多元方法
R1nG8633 小时前
CANN资源泄漏检测工具源码深度解读 实战设备内存泄漏排查
数据库·算法·cann
_OP_CHEN3 小时前
【算法基础篇】(五十六)容斥原理指南:从集合计数到算法实战,解决组合数学的 “重叠难题”!
算法·蓝桥杯·c/c++·组合数学·容斥原理·算法竞赛·acm/icpc
TracyCoder1233 小时前
LeetCode Hot100(27/100)——94. 二叉树的中序遍历
算法·leetcode