leetcode
leetcode 2751 ~ 2800
执行操作标记数组中的元素

执行操作标记数组中的元素

难度:

标签:

题目描述

You are given a 0-indexed array nums of size n consisting of positive integers.

You are also given a 2D array queries of size m where queries[i] = [indexi, ki].

Initially all elements of the array are unmarked.

You need to apply m queries on the array in order, where on the ith query you do the following:

  • Mark the element at index indexi if it is not already marked.
  • Then mark ki unmarked elements in the array with the smallest values. If multiple such elements exist, mark the ones with the smallest indices. And if less than ki unmarked elements exist, then mark all of them.

Return an array answer of size m where answer[i] is the sum of unmarked elements in the array after the ith query.

 

Example 1:

Input: nums = [1,2,2,1,2,3,1], queries = [[1,2],[3,3],[4,2]]

Output: [8,3,0]

Explanation:

We do the following queries on the array:

  • Mark the element at index 1, and 2 of the smallest unmarked elements with the smallest indices if they exist, the marked elements now are nums = [1,2,2,1,2,3,1]. The sum of unmarked elements is 2 + 2 + 3 + 1 = 8.
  • Mark the element at index 3, since it is already marked we skip it. Then we mark 3 of the smallest unmarked elements with the smallest indices, the marked elements now are nums = [1,2,2,1,2,3,1]. The sum of unmarked elements is 3.
  • Mark the element at index 4, since it is already marked we skip it. Then we mark 2 of the smallest unmarked elements with the smallest indices if they exist, the marked elements now are nums = [1,2,2,1,2,3,1]. The sum of unmarked elements is 0.

Example 2:

Input: nums = [1,4,2,3], queries = [[0,1]]

Output: [7]

Explanation: We do one query which is mark the element at index 0 and mark the smallest element among unmarked elements. The marked elements will be nums = [1,4,2,3], and the sum of unmarked elements is 4 + 3 = 7.

 

Constraints:

  • n == nums.length
  • m == queries.length
  • 1 <= m <= n <= 105
  • 1 <= nums[i] <= 105
  • queries[i].length == 2
  • 0 <= indexi, ki <= n - 1

代码结果

运行时间: 257 ms, 内存: 38.0 MB


/*
 * 思路:
 * 1. 使用Java Stream API进行集合操作和筛选。
 * 2. 每次操作后标记相应元素并计算未标记元素的和。
 */

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

public class SolutionStream {
    public int[] minOperations(int[] nums, int[][] queries) {
        int n = nums.length;
        int m = queries.length;
        boolean[] marked = new boolean[n];
        int[] answer = new int[m];
        int unmarkedSum = Arrays.stream(nums).sum();
        
        for (int i = 0; i < m; i++) {
            int index = queries[i][0];
            int k = queries[i][1];
            if (!marked[index]) {
                marked[index] = true;
                unmarkedSum -= nums[index];
            }
            
            // 找到最小的k个未标记元素并标记
            List<Integer> unmarkedElements = IntStream.range(0, n)
                    .filter(j -> !marked[j])
                    .mapToObj(j -> nums[j])
                    .sorted()
                    .limit(k)
                    .collect(Collectors.toList());
            for (int val : unmarkedElements) {
                for (int j = 0; j < n; j++) {
                    if (!marked[j] && nums[j] == val) {
                        marked[j] = true;
                        unmarkedSum -= nums[j];
                        break;
                    }
                }
            }
            answer[i] = unmarkedSum;
        }
        return answer;
    }
}

解释

方法:

题解首先通过sum函数计算整个nums数组的总和s,然后创建一个索引数组ids,根据nums中元素的值进行稳定排序。这样,ids数组的每个位置保存的是原nums数组中元素从小到大排序的索引。接着,题解定义一个变量j来跟踪未标记的最小元素的位置。对于每个查询,题解首先从总和s中减去指定索引的元素值(即标记该元素),然后尝试标记k个未标记的最小元素,通过索引数组ids来找到这些元素。如果元素已经被标记(即值为0),则忽略。每次操作后,将当前未标记元素的和s添加到结果列表ans中。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
在题解中,如何确保`ids`数组中的索引确实是按`nums`数组中的值稳定排序的,而非只是普通排序?
在题解中,`ids`数组是通过`sorted(range(n), key=lambda i: nums[i])`产生的。这里,`range(n)`生成一个与`nums`数组索引对应的序列,`key=lambda i: nums[i]`指定排序依据为`nums`数组中索引`i`对应的值。Python的`sorted`函数默认实现的是稳定排序,即如果两个元素具有相同的排序键(在本例中为`nums[i]`),它们在排序后的数组中的相对位置与在原数组中的相对位置相同。因此,`ids`数组确保了元素的稳定排序。
🦆
题解提到的`每次操作后,将当前未标记元素的和s添加到结果列表ans中`,若在操作中间`nums[i]`已经被标记,如何处理这种情况?
题解中处理这种情况的逻辑位于`if nums[i]:`条件判断内。当进行到某次查询操作时,如果发现`nums[i]`的值为0,说明该元素已经被之前的操作标记过,因此,程序将不再从`s`中减去`nums[i]`的值(因为已经是0),直接继续检查下一个元素。这确保了只有未标记的元素才会影响`s`的值,并且准确反映了每次操作后未标记元素的总和。
🦆
题解中的`while j < n and k`循环是否考虑了所有元素已标记但`k`仍大于0的情况,这时应如何处理?
题解中的`while j < n and k`循环确实处理了所有元素可能已经标记的情况。循环中,`j`遍历`ids`数组(按元素值排序的索引数组),并检查`nums[i]`是否已被标记(`nums[i]`不为0)。如果在循环执行过程中`j`达到`n`(即检查完所有元素)但`k`仍然大于0,循环将自然结束,因为没有更多元素可供标记。此时,`s`已经是剩余未标记元素的总和,直接添加到`ans`列表即可,不需要额外操作。

相关问题