leetcode
leetcode 2301 ~ 2350
将数组清空

将数组清空

难度:

标签:

题目描述

You are given an integer array nums containing distinct numbers, and you can perform the following operations until the array is empty:

  • If the first element has the smallest value, remove it
  • Otherwise, put the first element at the end of the array.

Return an integer denoting the number of operations it takes to make nums empty.

 

Example 1:

Input: nums = [3,4,-1]
Output: 5
Operation Array
1 [4, -1, 3]
2 [-1, 3, 4]
3 [3, 4]
4 [4]
5 []

Example 2:

Input: nums = [1,2,4,3]
Output: 5
Operation Array
1 [2, 4, 3]
2 [4, 3]
3 [3, 4]
4 [4]
5 []

Example 3:

Input: nums = [1,2,3]
Output: 3
Operation Array
1 [2, 3]
2 [3]
3 []

 

Constraints:

  • 1 <= nums.length <= 105
  • -10<= nums[i] <= 109
  • All values in nums are distinct.

代码结果

运行时间: 135 ms, 内存: 27.7 MB


/* 思路: 通过Java Stream API,我们可以更简洁地实现这个操作。虽然Stream API不能直接改变集合,但我们可以使用流来获取最小值。然后,通过移除和添加元素来模拟操作。*/

import java.util.*;
import java.util.stream.*;

public class Solution {
    public int removeElements(int[] nums) {
        List<Integer> list = new ArrayList<>();
        for (int num : nums) list.add(num);
        int operations = 0;
        while (!list.isEmpty()) {
            int min = list.stream().min(Integer::compare).get(); // 获取最小值
            if (list.get(0) == min) {
                list.remove(0); // 删除最小值
            } else {
                list.add(list.remove(0)); // 移动第一个元素到末尾
            }
            operations++;
        }
        return operations;
    }
}

解释

方法:

题解利用了排序和索引来优化操作。首先,通过对数组元素的索引进行排序(基于它们的值),我们获得一个有序的索引列表,该列表直接指向数组中从最小值到最大值的元素。接下来,遍历这个有序索引列表,计算清空数组所需的总操作次数。对于每个元素,如果其索引小于前一个元素的索引(说明在原数组中,这个元素在前一个元素之前),则需要额外进行一轮将该元素移动到数组末尾的操作。计算这些额外操作的总次数加上数组长度即为答案。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
在算法中,你是如何确定将数组索引按照对应数值排序后的逻辑与原题目操作的对应关系的?
在数组操作中,按照数值排序的逻辑主要是为了确定操作的优先顺序,即我们希望优先处理数值较小的元素。这种排序方法可以帮助我们更系统地理解和模拟数组元素被逐一清除的过程。具体来说,通过排序,我们可以获得一个有序的处理顺序,这有助于我们计算出移动元素时的额外操作次数。这种方法类似于优先处理任务队列中优先级较高的任务,从而使整体操作更为高效。
🦆
题解中提到,如果当前元素的索引小于前一个元素的索引就需要额外操作,能否详细解释为什么这样的条件会导致需要额外的操作?
在按值排序的索引列表中,如果当前元素的索引小于前一个元素的索引,这表明在原始数组中,当前元素位于前一个元素之前。因此,当我们按排序后的顺序处理数组元素时,要移动当前元素到数组末尾去清除,就必须越过前面已处理的元素,这就需要额外的操作。这种情况需要额外操作是因为我们需要保持数组的其余部分的相对顺序,使得每次移动都能有效地将一个元素移到正确位置以便清除。
🦆
在计算额外操作次数时,为什么使用了`len(index) - i`这个表达式?这个表达式具体代表什么意义?
表达式`len(index) - i`表示从当前元素开始到数组末尾的元素数量。在这个算法中,如果发现当前元素的索引小于前一个元素的索引,意味着为了将当前元素移动到数组末尾,我们需要执行额外的操作次数,等于从当前元素位置到数组末尾的元素总数。这是因为每移动一次,当前元素都需要越过所有这些元素,以到达数组的末端。
🦆
排序后的索引列表中,如果有连续几个元素的索引是递减的,这种情况下的操作次数是怎样累计的?
如果排序后的索引列表中存在连续的递减元素索引,每当遇到这种情况时,每个这样的元素都需要额外的操作来移动到数组的末尾。具体的操作次数为这个元素到数组末端的元素总数,即`len(index) - 当前元素的位置i`。这些操作会累加,因为每个元素都独立需要被移动到末尾。因此,这种连续递减的索引会导致操作次数的显著增加,每个这样的元素都按照其到数组末尾的距离计算需要额外的操作次数。

相关问题