leetcode
leetcode 1751 ~ 1800
使数组连续的最少操作数

使数组连续的最少操作数

难度:

标签:

题目描述

代码结果

运行时间: 124 ms, 内存: 34.2 MB


// 思路:
// 1. 使用Java Stream对输入数组进行排序
// 2. 遍历排序后的数组,计算连续缺失的元素数量
// 3. 返回缺失的元素数量,即为最少操作次数

import java.util.Arrays;

public class Solution {
    public int minOperations(int[] nums) {
        nums = Arrays.stream(nums).sorted().toArray();
        int n = nums.length;
        int minOps = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            int end = nums[i] + n - 1;
            int count = (int) Arrays.stream(nums).filter(num -> num <= end).count();
            minOps = Math.min(minOps, n - count);
        }
        return minOps;
    }
}

解释

方法:

首先,将数组转换为集合并排序,以去除重复元素并获得所有唯一元素的有序列表。接着,使用滑动窗口的方法来找到最长的连续子数组,其长度最接近原数组长度。滑动窗口通过维护一个起点和一个终点来工作,开始时两者都在数组的起始位置。然后逐步向右移动终点,若当前窗口内的最大值与最小值之差大于或等于原数组的长度,则将起点右移,以尝试缩小窗口。操作的目标是使得窗口的大小尽可能接近原数组的长度。最后,由于需要将原数组变为连续数组,所以最少操作次数即为原数组的长度减去滑动窗口中得到的最大窗口长度。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在这种解法中需要将数组转换为集合并进行排序?
将数组转换为集合的目的是去除数组中的重复元素,因为重复的元素在寻找最长连续子数组时不会提供额外的帮助,且会导致统计上的误差。排序则是为了方便后续通过比较元素的差值来快速判断元素间是否连续,同时也便于使用滑动窗口技术来寻找最长的连续子序列。
🦆
在滑动窗口算法中,如何确定何时右移窗口的起点left?
在滑动窗口算法中,窗口的起点left被右移的条件是当前窗口内的元素(从起点left到终点i的元素)已不能构成连续序列。具体来说,当窗口内的最大值与最小值之差大于或等于数组长度n时,说明窗口内不能只通过增加元素就能构成连续数组,因此需要通过移动起点left来尝试缩小这一差值,使窗口内的元素可能构成连续序列。
🦆
滑动窗口的最大长度是如何被计算出来的,具体是如何从代码中反映这一点的?
滑动窗口的最大长度是通过遍历去重并排序后的数组,同时调整窗口的起点和终点来计算的。在代码中,这一点体现在通过不断移动终点i(for循环的迭代变量),并在必要时调整起点left(if语句内的条件判断和操作),来尝试找到最大的滑动窗口长度。最终,最大的滑动窗口长度计算为`m - left`,其中m是去重排序后数组的长度。
🦆
代码中`if a[i] - a[left] >= n: left += 1`这一行是基于什么逻辑?为什么选择这样的条件来移动左窗口?
代码中的这一行逻辑是基于需要保持窗口内元素可以构成连续序列的考虑。当窗口内的最大元素和最小元素之间的差大于或等于n时,窗口内元素的数量已经不可能通过简单地添加缺失的元素来达到n个连续的整数(这意味着窗口内存在过大的间隙)。因此,需要通过移动窗口的左边界left来尝试减小这个差值,目的是缩小窗口直到窗口内的元素可以构成一个几乎完整的连续序列。这样做可以使得最终的操作次数(添加或移动元素)最小化。

相关问题