LeetCode 题解工作台

通过操作使数组长度最小

给你一个下标从 0 开始的整数数组 nums ,它只包含 正 整数。 你的任务是通过进行以下操作 任意次 (可以是 0 次) 最小化 nums 的长度: 在 nums 中选择 两个不同 的下标 i 和 j ,满足 nums[i] > 0 且 nums[j] > 0 。 将结果 nums[i] % n…

category

4

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

中等 · 贪心·invariant

bolt

答案摘要

我们不妨记数组 的最小的元素为 。 如果 只出现一次,那么我们将 与数组 的其他元素进行操作,可以将其他元素全部消去,最终剩下 一个元素,答案为 。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 贪心·invariant 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个下标从 0 开始的整数数组 nums ,它只包含  整数。

你的任务是通过进行以下操作 任意次 (可以是 0 次) 最小化 nums 的长度:

  • nums 中选择 两个不同 的下标 i 和 j ,满足 nums[i] > 0 且 nums[j] > 0 。
  • 将结果 nums[i] % nums[j] 插入 nums 的结尾。
  • nums 中下标为 i 和 j 的元素删除。

请你返回一个整数,它表示进行任意次操作以后 nums 的 最小长度 。

 

示例 1:

输入:nums = [1,4,3,1]
输出:1
解释:使数组长度最小的一种方法是:
操作 1 :选择下标 2 和 1 ,插入 nums[2] % nums[1] 到数组末尾,得到 [1,4,3,1,3] ,然后删除下标为 2 和 1 的元素。
nums 变为 [1,1,3] 。
操作 2 :选择下标 1 和 2 ,插入 nums[1] % nums[2] 到数组末尾,得到 [1,1,3,1] ,然后删除下标为 1 和 2 的元素。
nums 变为 [1,1] 。
操作 3 :选择下标 1 和 0 ,插入 nums[1] % nums[0] 到数组末尾,得到 [1,1,0] ,然后删除下标为 1 和 0 的元素。
nums 变为 [0] 。
nums 的长度无法进一步减小,所以答案为 1 。
1 是可以得到的最小长度。

示例 2:

输入:nums = [5,5,5,10,5]
输出:2
解释:使数组长度最小的一种方法是:
操作 1 :选择下标 0 和 3 ,插入 nums[0] % nums[3] 到数组末尾,得到 [5,5,5,10,5,5] ,然后删除下标为 0 和 3 的元素。
nums 变为 [5,5,5,5] 。
操作 2 :选择下标 2 和 3 ,插入 nums[2] % nums[3] 到数组末尾,得到 [5,5,5,5,0] ,然后删除下标为 2 和 3 的元素。
nums 变为 [5,5,0] 。
操作 3 :选择下标 0 和 1 ,插入 nums[0] % nums[1] 到数组末尾,得到 [5,5,0,0] ,然后删除下标为 0 和 1 的元素。
nums 变为 [0,0] 。
nums 的长度无法进一步减小,所以答案为 2 。
2 是可以得到的最小长度。

示例 3:

输入:nums = [2,3,4]
输出:1
解释:使数组长度最小的一种方法是:
操作 1 :选择下标 1 和 2 ,插入 nums[1] % nums[2] 到数组末尾,得到 [2,3,4,3] ,然后删除下标为 1 和 2 的元素。
nums 变为 [2,3] 。
操作 2 :选择下标 1 和 0 ,插入 nums[1] % nums[0] 到数组末尾,得到 [2,3,1] ,然后删除下标为 1 和 0 的元素。
nums 变为 [1] 。
nums 的长度无法进一步减小,所以答案为 1 。
1 是可以得到的最小长度。

 

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
lightbulb

解题思路

方法一:分情况讨论

我们不妨记数组 numsnums 的最小的元素为 mimi

如果 mimi 只出现一次,那么我们将 mimi 与数组 numsnums 的其他元素进行操作,可以将其他元素全部消去,最终剩下 mimi 一个元素,答案为 11

如果 mimi 出现多次,我们判断数组 numsnums 中的元素是否都是 mimi 的倍数。如果不是,即存在至少一个元素 xx,使得 0<xmodmi<mi0 \lt x \bmod mi \lt mi,说明我们可以通过操作,构造出一个小于 mimi 的元素,那么这个小于 mimi 的元素与其他元素进行操作,可以将其他元素全部消去,最终剩下这个小于 mimi 的元素,答案为 11;如果都是 mimi 的倍数,我们可以先借助 mimi,将所有大于 mimi 的元素消去,最终剩下的元素都是 mimi,个数为 cntcnt,两两配对,每两个元素进行一次操作,最终剩下 cnt/2\lceil cnt / 2 \rceil 个元素,答案为 cnt/2\lceil cnt / 2 \rceil

时间复杂度 O(n)O(n),其中 nn 是数组 numsnums 的长度。空间复杂度 O(1)O(1)

1
2
3
4
5
6
7
class Solution:
    def minimumArrayLength(self, nums: List[int]) -> int:
        mi = min(nums)
        if any(x % mi for x in nums):
            return 1
        return (nums.count(mi) + 1) // 2
speed

复杂度分析

指标
时间Depends on the final approach
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Look for a solid understanding of greedy strategies and their implementation in reducing array length.

  • question_mark

    Evaluate how well the candidate handles edge cases, such as arrays with repeated elements or when the modulus operation does not significantly reduce the array.

  • question_mark

    Assess the candidate's ability to justify the sequence of operations and whether they can explain the rationale behind choosing specific pairs for modulus.

warning

常见陷阱

外企场景
  • error

    Failing to account for the most optimal pairings that reduce the array length effectively.

  • error

    Overlooking edge cases where the array cannot be minimized further due to redundant modulus operations.

  • error

    Misunderstanding the operation's effect on the array, especially when it seems like the array length will not decrease significantly.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Allow only a limited number of operations and ask for the minimal achievable length after those operations.

  • arrow_right_alt

    Change the operation to insert nums[i] * nums[j] instead of modulus and test how that affects the minimal length.

  • arrow_right_alt

    Limit the number of times any element can be involved in an operation and ask for the minimum array length under that constraint.

help

常见问题

外企场景

通过操作使数组长度最小题解:贪心·invariant | LeetCode #3012 中等