leetcode
leetcode 2201 ~ 2250
执行操作后的最大 MEX

执行操作后的最大 MEX

难度:

标签:

题目描述

You are given a 0-indexed integer array nums and an integer value.

In one operation, you can add or subtract value from any element of nums.

  • For example, if nums = [1,2,3] and value = 2, you can choose to subtract value from nums[0] to make nums = [-1,2,3].

The MEX (minimum excluded) of an array is the smallest missing non-negative integer in it.

  • For example, the MEX of [-1,2,3] is 0 while the MEX of [1,0,3] is 2.

Return the maximum MEX of nums after applying the mentioned operation any number of times.

 

Example 1:

Input: nums = [1,-10,7,13,6,8], value = 5
Output: 4
Explanation: One can achieve this result by applying the following operations:
- Add value to nums[1] twice to make nums = [1,0,7,13,6,8]
- Subtract value from nums[2] once to make nums = [1,0,2,13,6,8]
- Subtract value from nums[3] twice to make nums = [1,0,2,3,6,8]
The MEX of nums is 4. It can be shown that 4 is the maximum MEX we can achieve.

Example 2:

Input: nums = [1,-10,7,13,6,8], value = 7
Output: 2
Explanation: One can achieve this result by applying the following operation:
- subtract value from nums[2] once to make nums = [1,-10,0,13,6,8]
The MEX of nums is 2. It can be shown that 2 is the maximum MEX we can achieve.

 

Constraints:

  • 1 <= nums.length, value <= 105
  • -109 <= nums[i] <= 109

代码结果

运行时间: 77 ms, 内存: 28.4 MB


/*
 * 思路:
 * 1. 使用 Java Stream API 计算每个元素的模 value 的值。
 * 2. 使用 Collectors.toSet() 将这些模值收集到一个 set 中。
 * 3. 使用 IntStream.range 迭代 0 到 value-1,找到第一个不存在的模值。
 */
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class MaxMEXStream {
    public int findMaxMEX(int[] nums, int value) {
        Set<Integer> modSet = IntStream.of(nums)
                .map(num -> ((num % value) + value) % value) // 保证模数为正
                .boxed()
                .collect(Collectors.toSet());
        return IntStream.range(0, value)
                .filter(i -> !modSet.contains(i))
                .findFirst()
                .orElse(value); // 如果 0 到 value-1 都存在,最大 MEX 为 value
    }
}

解释

方法:

题解的核心思路是利用模运算来分组处理数组中的元素。由于任何元素都可以通过加减给定的值value来改变,因此可以观察到,对于任何数字x,x%value的结果是有限的,从0到value-1。因此,可以利用这个性质来求解最小的非出现整数(MEX)。首先,通过遍历数组nums,使用哈希表(这里使用collections.Counter)来记录每个可能的余数值出现的次数。然后,找到拥有最小计数的余数,这样可以确保在对nums进行操作后,能够得到最大的MEX值。最后,根据这个余数和它的计数,可以计算出MEX。这种方法有效地利用了模运算的性质来简化问题,避免了直接寻找缺失的最小非负整数这一复杂过程。

时间复杂度:

O(n + value)

空间复杂度:

O(value)

代码细节讲解

🦆
题解中提到将nums中的每个元素对value取模来计数,为什么取模操作能有效地帮助解决找到最大MEX的问题?
取模操作将元素按照对value的余数进行分类,这样每个类别中的元素可以通过加减value的倍数自由地变换到任何其他同余的数。这意味着,对于每个余数类别,我们可以通过适当的加减操作,生成从该余数开始的、间隔为value的数列。因此,对每个余数类别进行计数,可以帮助我们了解在进行加减操作后哪些数值是可达的,从而确定哪些数值是不可达的,这样我们就可以找到最小的不可达数,即MEX。
🦆
在计算MEX时,为什么选择最小计数的余数来确定MEX,而不是直接查找未出现的最小非负整数?
选择最小计数的余数来计算MEX是为了确保在对nums中的元素进行可能的操作后,能够生成尽可能大的不在数组中的非负整数。通过识别出现次数最少的余数,我们可以确定这个余数类别是最容易达到其上限(即通过连续加value无法生成更多新整数的点)的类别。这样,我们可以使用该余数和它的计数来计算出最大的MEX,而直接搜索未出现的最小非负整数则无法考虑到通过操作能够实现的数值变化,无法确保找到的是最大的MEX。
🦆
题解中提到通过增加value的倍数来调整MEX,具体是如何通过这种方式确保得到正确的MEX值的?
通过增加value的倍数来调整MEX的核心在于,任何数x加上或减去value的倍数,仍然保持相同的模value结果。这意味着在给定模value的余数情况下,我们可以通过增加相应余数的倍数,连续地生成一系列特定余数的数。例如,如果某个余数计数最小,则我们可以从这个余数开始,连续地加上value,生成一系列新的数,直到达到一个数,这个数通过加value无法从nums中任何其他数生成。这个过程允许我们找到最大的不可达数,即MEX。因此,识别最小计数的余数并计算基于这个余数的连续数列的上限,为我们提供了一个方法来确保我们计算的MEX是准确和最大的。

相关问题