【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)。
相关推荐
暮冬-  Gentle°1 天前
C++中的命令模式实战
开发语言·c++·算法
卷福同学1 天前
【养虾日记】Openclaw操作浏览器自动化发文
人工智能·后端·算法
春日见1 天前
如何入门端到端自动驾驶?
linux·人工智能·算法·机器学习·自动驾驶
图图的点云库1 天前
高斯滤波实现算法
c++·算法·最小二乘法
一叶落4381 天前
题目:15. 三数之和
c语言·数据结构·算法·leetcode
老鱼说AI1 天前
CUDA架构与高性能程序设计:异构数据并行计算
开发语言·c++·人工智能·算法·架构·cuda
罗湖老棍子1 天前
【例 1】数列操作(信息学奥赛一本通- P1535)
数据结构·算法·树状数组·单点修改 区间查询
big_rabbit05021 天前
[算法][力扣222]完全二叉树的节点个数
数据结构·算法·leetcode
张李浩1 天前
Leetcode 15三题之和
算法·leetcode·职场和发展
2301_793804691 天前
C++中的适配器模式变体
开发语言·c++·算法