Facebook Pixel

3080. Mark Elements on Array by Performing Queries


Problem Description

You are provided with a 0-indexed array nums of size n, containing positive integers. Additionally, there's a 2D array queries of size m, where each query is represented as queries[i] = [index_i, k_i].

Initially, all elements of the nums array are considered unmarked.

For each query, execute the following steps:

  1. Mark the element at index_i if it is not marked already.
  2. Subsequently, mark k_i unmarked elements in the array having the smallest values. If there are ties in values, prefer the elements with smaller indices. In cases where fewer than k_i unmarked elements remain, mark all that are available.

The goal is to return an array answer of size m, where answer[i] is the sum of unmarked elements in the array after performing the i-th query.

Intuition

To solve this problem, the idea is to efficiently manage and track the marking process while updating the sum of unmarked elements.

  1. Pre-computation of Sum: Begin by calculating the total sum s of the nums array. This allows for efficient updates whenever elements are marked and removed from the sum.

  2. Tracking Marked Status: Use a list mark to track which elements in nums have been marked. This helps in determining which elements contribute to the remaining sum after each query.

  3. Sorting for Efficiency: Convert nums into an array of tuples arr, where each tuple contains the value and its corresponding index. Sorting arr by value (and by index if values are equal) facilitates the process of identifying the k_i smallest unmarked elements efficiently with each query.

  4. Simulating the Queries: For each query [index, k]:

    • First, mark the element at the provided index if it isn't already marked, and subtract its value from the total sum.
    • Next, iterate through the sorted array arr to mark the k_i smallest unmarked elements, updating the sum and managing the marked status as elements are processed.

By following this efficient method, each query's impact is observed through small, incremental adjustments of the sum, and an answer is prepared in a straightforward manner.

Learn more about Sorting and Heap (Priority Queue) patterns.

Solution Approach

The solution employs a systematic approach to handle the marking of elements and tracking the sum of unmarked elements efficiently. Let's break down the implementation:

  1. Calculate Initial Sum: Start by computing the total sum s of the array nums. This sum will be adjusted as elements are marked through the queries.

  2. Mark Tracking: Initialize a list mark of the same length as nums, with all values set to False. This list helps in identifying which elements are marked as queries are processed.

  3. Preparation of a Sorted Array: Construct an array arr with tuples (x, i) for each element in nums, where x is the value and i is the index. Sort arr by the values first, and by the indices second if the values are the same. This sorted array allows quick retrieval of the smallest unmarked values.

  4. Processing Each Query:

    • For each query [index, k], first check if the element at index is unmarked:
      • If unmarked, mark it and deduct its value from s.
    • Next, use the sorted array arr to find and mark the k smallest unmarked elements:
      • Iterate over arr, marking elements, deducting their values from s, and adjusting k until either k elements are marked or no unmarked elements remain.
    • After processing each query, append the current value of s to the result list ans.
  5. Return Result: After all queries have been processed, return the list ans which contains the sum of unmarked elements after each query.

The above approach efficiently manages the task by leveraging sorting and an auxiliary data structure to keep track of marked status, providing an optimized solution to the problem.

Ready to land your dream job?

Unlock your dream job with a 2-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's consider a small example to illustrate the solution approach:

Suppose we have the array nums = [5, 3, 8, 1, 7] and the queries given by queries = [[1, 2], [3, 1]].

To solve using the described approach:

  1. Calculate Initial Sum: The total sum of nums is s = 5 + 3 + 8 + 1 + 7 = 24.

  2. Mark Tracking: Initialize a mark list as [False, False, False, False, False], indicating no elements are marked yet.

  3. Preparation of a Sorted Array: Prepare arr as [(1, 3), (3, 1), (5, 0), (7, 4), (8, 2)]. This is sorted by value and index.

  4. Processing Each Query:

    • First Query [1, 2]:

      • The element at index 1 in nums is 3, which is unmarked. Mark it and update s to 24 - 3 = 21.
      • From arr, mark the 2 smallest unmarked elements:
        • Start with (1, 3), marking index 3, update s = 21 - 1 = 20.
        • Next, mark (5, 0), update s = 20 - 5 = 15.
      • After processing this query, append 15 to ans.
    • Second Query [3, 1]:

      • The element at index 3 in nums (value 1) is already marked; no update required for s.
      • Mark the 1 smallest unmarked element using arr:
        • Pick (7, 4), marking index 4, update s = 15 - 7 = 8.
      • After completing this query, append 8 to ans.
  5. Return Result: After all queries are complete, ans = [15, 8], which represents the sum of unmarked elements after each query.

Solution Implementation

1from typing import List
2
3class Solution:
4    def unmarkedSumArray(self, nums: List[int], queries: List[List[int]]) -> List[int]:
5        n = len(nums)
6        total_sum = sum(nums)  # Compute the sum of all elements in nums.
7        marked = [False] * n  # Initialize a list to keep track of marked elements.
8        # Create a sorted list of tuples containing elements from nums and their indices.
9        # This helps in efficiently accessing the smallest unmarked elements.
10        sorted_nums = sorted((value, idx) for idx, value in enumerate(nums))
11      
12        pointer = 0  # Initialize a pointer for traversing sorted elements.
13        results = []  # List to store the result of each query.
14      
15        # Iterate over each query consisting of index and k value.
16        for index, k in queries:
17            # If the element at 'index' isn't marked, mark it and subtract its value from total_sum.
18            if not marked[index]:
19                marked[index] = True
20                total_sum -= nums[index]
21          
22            # Process as many smallest unmarked elements as indicated by 'k'.
23            # Pointer ensures no element is processed more than once unnecessarily.
24            while k > 0 and pointer < n:
25                # Check if the current element in sorted order is unmarked.
26                if not marked[sorted_nums[pointer][1]]:
27                    # Mark it and subtract its value from total_sum.
28                    marked[sorted_nums[pointer][1]] = True
29                    total_sum -= sorted_nums[pointer][0]
30                    k -= 1  # Decrement k as one unmarked element is processed.
31              
32                pointer += 1  # Move to the next element in sorted order.
33          
34            # Append the current unmarked sum to results.
35            results.append(total_sum)
36      
37        return results
38
1import java.util.Arrays;
2
3class Solution {
4    public long[] unmarkedSumArray(int[] nums, int[][] queries) {
5        int n = nums.length; // Length of the nums array
6        long totalSum = Arrays.stream(nums).asLongStream().sum(); // Calculate total sum of nums array
7        boolean[] marked = new boolean[n]; // Array to track marked indices
8        int[][] indexedNums = new int[n][2]; // Array to hold nums with their indices
9      
10        // Populate indexedNums with values and their original indices
11        for (int i = 0; i < n; ++i) {
12            indexedNums[i] = new int[] {nums[i], i};
13        }
14      
15        // Sort indexedNums based on values, then indices
16        Arrays.sort(indexedNums, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
17      
18        int m = queries.length; // Number of queries
19        long[] results = new long[m]; // Array to store results of each query
20      
21        // Process each query
22        for (int i = 0, sortedIndex = 0; i < m; ++i) {
23            int index = queries[i][0]; // Index specified in the query
24            int k = queries[i][1]; // Number of elements to mark
25          
26            // Mark the specified index if not already marked
27            if (!marked[index]) {
28                marked[index] = true;
29                totalSum -= nums[index]; // Subtract marked value from total sum
30            }
31          
32            // Mark the next k unmarked smallest elements
33            for (; k > 0 && sortedIndex < n; ++sortedIndex) {
34                int currentIndex = indexedNums[sortedIndex][1];
35                if (!marked[currentIndex]) {
36                    marked[currentIndex] = true;
37                    totalSum -= indexedNums[sortedIndex][0]; // Subtract marked value from total sum
38                    --k; // Decrease k as one element is marked
39                }
40            }
41          
42            results[i] = totalSum; // Store current unmarked sum in results
43        }
44      
45        return results; // Return the results for each query
46    }
47}
48
1#include <vector>
2#include <algorithm>
3#include <numeric>
4
5using namespace std;
6
7class Solution {
8public:
9    vector<long long> unmarkedSumArray(vector<int>& nums, vector<vector<int>>& queries) {
10        int n = nums.size();
11      
12        // Calculate the total sum of numbers in the array `nums`
13        long long totalSum = accumulate(nums.begin(), nums.end(), 0LL);
14      
15        // Marker vector to check if an element has been unmarked
16        vector<bool> marked(n, false);
17      
18        // Array to hold each number and its index for sorting purposes
19        vector<pair<int, int>> indexedNums;
20        for (int i = 0; i < n; ++i) {
21            indexedNums.emplace_back(nums[i], i);
22        }
23      
24        // Sort `indexedNums` based on the values (first element of pairs)
25        sort(indexedNums.begin(), indexedNums.end());
26
27        // Result vector to store the sum for each query
28        vector<long long> result;
29      
30        int m = queries.size();
31        int j = 0;
32      
33        // Process each query
34        for (int i = 0; i < m; ++i) {
35            int index = queries[i][0];
36            int k = queries[i][1];
37          
38            // If the number at `index` has not been marked before, mark it and subtract from totalSum
39            if (!marked[index]) {
40                marked[index] = true;
41                totalSum -= nums[index];
42            }
43
44            // Mark `k` smallest unmarked numbers and subtract them from totalSum
45            while (k > 0 && j < n) {
46                if (!marked[indexedNums[j].second]) {
47                    marked[indexedNums[j].second] = true;
48                    totalSum -= indexedNums[j].first;
49                    --k;
50                }
51                ++j;
52            }
53
54            // Collect the modified totalSum for the current query
55            result.push_back(totalSum);
56        }
57      
58        return result;
59    }
60};
61
1function unmarkedSumArray(nums: number[], queries: number[][]): number[] {
2    const n = nums.length; // Length of the input numbers array
3    let totalSum = nums.reduce((acc, x) => acc + x, 0); // Calculate the total sum of the array
4    const mark: boolean[] = Array(n).fill(false); // Boolean array to keep track of marked indices
5    const indexedNums = nums.map((value, index) => [value, index]); // Pair each number with its index
6    indexedNums.sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0])); // Sort by value, and by index if values are equal
7
8    let j = 0; // Initialize pointer for sorted array
9    const results: number[] = []; // Array to hold results of queries
10
11    for (let [index, k] of queries) {
12        // If the element at 'index' is not already marked, mark it and subtract its value
13        if (!mark[index]) {
14            mark[index] = true;
15            totalSum -= nums[index];
16        }
17      
18        // Process 'k' elements from sorted indexed array
19        for (; k > 0 && j < n; ++j) {
20            if (!mark[indexedNums[j][1]]) {
21                mark[indexedNums[j][1]] = true;
22                totalSum -= indexedNums[j][0];
23                --k;
24            }
25        }
26
27        // Store the current unmarked sum
28        results.push(totalSum);
29    }
30
31    return results; // Return the results array with answers to all queries
32}
33

Time and Space Complexity

The time complexity of the code is O(n \times \log n). This is due to the sorting operation sorted((x, i) for i, x in enumerate(nums)) that sorts the nums array based on values, which takes O(n \times \log n) time. The rest of the operations in the function (the loops and checks) operate at most in linear time related to the length of nums and queries.

The space complexity of the code is O(n). This is because of the additional data structures used: mark, arr, and ans. The list mark is of length n, arr is also an array of n elements, and ans will store results for each query, leading to an overall space usage proportional to n.

Learn more about how to find time and space complexity quickly.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

A heap is a ...?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!


Load More