Facebook Pixel

3086. Minimum Moves to Pick K Ones

Problem Description

You are given a binary array nums of length n, a positive integer k, and a non-negative integer maxChanges.

Alice plays a game where she needs to collect exactly k ones from the array using the minimum number of moves.

Game Rules:

  1. Alice starts by choosing any index aliceIndex in the range [0, n-1] to stand at
  2. If nums[aliceIndex] == 1, Alice immediately picks up that one (setting nums[aliceIndex] = 0) without using any moves

Available Actions (each counts as one move):

  • Action 1: Select any index j ≠ aliceIndex where nums[j] == 0 and change it to 1. This action can be performed at most maxChanges times.
  • Action 2: Select two adjacent indices x and y (where |x - y| == 1) such that nums[x] == 1 and nums[y] == 0, then swap their values. If after swapping y == aliceIndex, Alice automatically picks up the one at position y (setting it back to 0).

The goal is to find the minimum number of moves Alice needs to collect exactly k ones.

Example Strategy:

  • Alice can use Action 1 to create ones at convenient locations (limited by maxChanges)
  • Alice can use Action 2 to slide existing ones toward her position through adjacent swaps
  • The challenge is finding the optimal starting position and combination of actions to minimize total moves

The problem requires determining the best starting position for Alice and the optimal sequence of actions to collect k ones with the fewest moves possible.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that we should try every possible starting position for Alice and find the one that minimizes the total moves.

For any starting position i, we can think about the most efficient order to collect ones:

  1. Free pickup: If there's already a one at position i, we get it for free (0 moves).

  2. Adjacent ones: The next cheapest ones to collect are those immediately adjacent to Alice (at positions i-1 and i+1). Each of these only costs 1 move since we can directly swap them to Alice's position.

  3. Creating ones nearby: After grabbing adjacent ones, we should consider using Action 1 (creating new ones from zeros). The optimal strategy is to create these ones at positions i-1 or i+1 (if they're currently 0), then immediately swap them to position i. This costs 2 moves per one collected (1 move to create, 1 move to swap).

  4. Distant ones: Only after exhausting our maxChanges should we consider moving ones from farther away. Moving a one from distance d costs d moves (we need d swaps to bring it to Alice).

The crucial realization is that for distant ones, we want to minimize the total distance traveled. This means we should collect the closest ones first. We can use binary search to find the minimum radius around position i that contains enough ones to reach our target k.

To efficiently calculate the cost of moving distant ones, we use prefix sums:

  • cnt[i]: count of ones up to position i
  • s[i]: sum of positions of all ones up to position i

The cost to move all ones in range [l, r] to position i is:

  • For ones to the left of i: count * i - sum_of_positions
  • For ones to the right of i: sum_of_positions - count * i

By trying all starting positions and applying this greedy strategy at each position, we can find the global minimum number of moves needed.

Learn more about Greedy, Prefix Sum and Sliding Window patterns.

Solution Approach

The solution implements the greedy strategy with prefix sums and binary search for efficiency.

Step 1: Build Prefix Arrays

cnt = [0] * (n + 1)  # cnt[i] = count of ones in nums[0:i]
s = [0] * (n + 1)    # s[i] = sum of positions of ones in nums[0:i]

We use 1-based indexing for easier calculation. For each position i, we track:

  • cnt[i]: total number of ones up to position i
  • s[i]: sum of all positions where ones appear up to position i

Step 2: Enumerate Each Starting Position For each possible starting position i (1 to n):

  1. Pick up the free one if nums[i-1] == 1:

    • Set need = k - x where x is 1 if there's a one at position i, else 0
    • Cost: 0 moves
  2. Collect adjacent ones (positions i-1 and i+1):

    for j in (i - 1, i + 1):
        if need > 0 and 1 <= j <= n and nums[j - 1] == 1:
            need -= 1
            t += 1  # Each adjacent one costs 1 move
  3. Use Action 1 to create ones:

    c = min(need, maxChanges)
    need -= c
    t += c * 2  # Each created one costs 2 moves (create + swap)

    We create at most min(need, maxChanges) ones and place them optimally at adjacent positions.

  4. If still need more ones, use binary search to find the minimum radius:

    l, r = 2, max(i - 1, n - i)
    while l <= r:
        mid = (l + r) >> 1
    • Search for the smallest distance mid such that intervals [i-mid, i-2] and [i+2, i+mid] contain at least need remaining ones
    • Calculate ranges excluding adjacent positions (already processed):
      • Left range: [max(1, i-mid), max(0, i-2)]
      • Right range: [min(n+1, i+2), min(n, i+mid)]
  5. Calculate the cost using prefix sums:

    c1 = cnt[r1] - cnt[l1 - 1]  # Count of ones on the left
    c2 = cnt[r2] - cnt[l2 - 1]  # Count of ones on the right
    
    if c1 + c2 >= need:
        t1 = c1 * i - (s[r1] - s[l1 - 1])  # Cost for left ones
        t2 = s[r2] - s[l2 - 1] - c2 * i    # Cost for right ones
    • For ones to the left of i: each one at position j costs i - j moves
    • For ones to the right of i: each one at position j costs j - i moves
    • Total cost = sum of distances = count * i - sum_of_positions (left) + sum_of_positions - count * i (right)

Step 3: Track Minimum After calculating the cost for each starting position, we keep track of the minimum:

ans = min(ans, t + t1 + t2)

The algorithm returns the minimum number of moves across all possible starting positions.

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

Let's walk through a concrete example to illustrate the solution approach.

Example: nums = [1, 0, 0, 1, 0, 1], k = 2, maxChanges = 1

We need to collect exactly 2 ones using the minimum number of moves.

Step 1: Build Prefix Arrays

  • Original array (1-indexed): [1, 0, 0, 1, 0, 1]
  • Ones are at positions: 1, 4, 6
  • cnt = [0, 1, 1, 1, 2, 2, 3] (cumulative count of ones)
  • s = [0, 1, 1, 1, 5, 5, 11] (cumulative sum of positions with ones)

Step 2: Try Each Starting Position

Let's examine starting position i = 4 (index 3 in 0-based):

  1. Free pickup: nums[3] = 1, so Alice gets 1 one for free

    • need = k - 1 = 2 - 1 = 1
    • Cost so far: 0 moves
  2. Check adjacent positions (i-1=3 and i+1=5):

    • Position 3: nums[2] = 0 (no one here)
    • Position 5: nums[4] = 0 (no one here)
    • Still need: 1 one
    • Cost so far: 0 moves
  3. Use Action 1 (create ones):

    • Can create min(need, maxChanges) = min(1, 1) = 1 one
    • Create a one at position 3 or 5, then swap to position 4
    • need = 1 - 1 = 0
    • Cost: 0 + 1×2 = 2 moves total
  4. Binary search for distant ones: Not needed since need = 0

Total cost for starting at position 4: 2 moves

Let's also try starting position i = 1:

  1. Free pickup: nums[0] = 1, get 1 one for free

    • need = 2 - 1 = 1
    • Cost: 0 moves
  2. Check adjacent positions (only i+1=2 since i-1=0 is out of bounds):

    • Position 2: nums[1] = 0 (no one here)
    • Still need: 1 one
    • Cost: 0 moves
  3. Use Action 1:

    • Create min(1, 1) = 1 one at position 2
    • Swap to position 1
    • need = 1 - 1 = 0
    • Cost: 0 + 1×2 = 2 moves

Total cost for starting at position 1: 2 moves

Let's try starting position i = 2 (where there's no initial one):

  1. Free pickup: nums[1] = 0, no free one

    • need = 2
    • Cost: 0 moves
  2. Check adjacent positions (i-1=1 and i+1=3):

    • Position 1: nums[0] = 1 - can swap this one!
    • need = 2 - 1 = 1
    • Cost: 0 + 1 = 1 move
    • Position 3: nums[2] = 0 (no one here)
  3. Use Action 1:

    • Create min(1, 1) = 1 one
    • need = 1 - 1 = 0
    • Cost: 1 + 1×2 = 3 moves

Total cost for starting at position 2: 3 moves

Step 3: Find Minimum After checking all positions, the minimum is 2 moves (achieved at positions 1 and 4).

The algorithm correctly identifies that starting at a position with an existing one and using our single maxChanges to create and collect another one nearby is optimal for this example.

Solution Implementation

1class Solution:
2    def minimumMoves(self, nums: List[int], k: int, maxChanges: int) -> int:
3        n = len(nums)
4      
5        # Prefix arrays for count and weighted sum
6        # cnt[i] = count of 1s in nums[0:i]
7        # weighted_sum[i] = sum of (index+1) * value for nums[0:i]
8        cnt = [0] * (n + 1)
9        weighted_sum = [0] * (n + 1)
10      
11        for i, val in enumerate(nums, 1):
12            cnt[i] = cnt[i - 1] + val
13            weighted_sum[i] = weighted_sum[i - 1] + i * val
14      
15        min_moves = float('inf')
16      
17        # Try each position as the collection point
18        for i, val in enumerate(nums, 1):
19            moves = 0
20            remaining_needed = k - val  # How many more 1s we need after taking current position
21          
22            # First, try to collect from immediate neighbors (cost = 1 move each)
23            for neighbor_pos in (i - 1, i + 1):
24                if remaining_needed > 0 and 1 <= neighbor_pos <= n and nums[neighbor_pos - 1] == 1:
25                    remaining_needed -= 1
26                    moves += 1
27          
28            # Use maxChanges to create 1s and immediately collect them (cost = 2 moves each)
29            changes_to_use = min(remaining_needed, maxChanges)
30            remaining_needed -= changes_to_use
31            moves += changes_to_use * 2
32          
33            # If we've collected enough, update answer
34            if remaining_needed <= 0:
35                min_moves = min(min_moves, moves)
36                continue
37          
38            # Binary search for the minimum radius to collect remaining_needed 1s
39            left, right = 2, max(i - 1, n - i)
40          
41            while left <= right:
42                mid_radius = (left + right) >> 1
43              
44                # Define ranges for collecting (excluding immediate neighbors already considered)
45                left_range_start = max(1, i - mid_radius)
46                left_range_end = max(0, i - 2)
47                right_range_start = min(n + 1, i + 2)
48                right_range_end = min(n, i + mid_radius)
49              
50                # Count 1s in left and right ranges
51                left_count = cnt[left_range_end] - cnt[left_range_start - 1]
52                right_count = cnt[right_range_end] - cnt[right_range_start - 1]
53              
54                if left_count + right_count >= remaining_needed:
55                    # Calculate cost to move 1s from left range to position i
56                    left_cost = left_count * i - (weighted_sum[left_range_end] - weighted_sum[left_range_start - 1])
57                    # Calculate cost to move 1s from right range to position i
58                    right_cost = weighted_sum[right_range_end] - weighted_sum[right_range_start - 1] - right_count * i
59                  
60                    min_moves = min(min_moves, moves + left_cost + right_cost)
61                    right = mid_radius - 1  # Try smaller radius
62                else:
63                    left = mid_radius + 1  # Need larger radius
64      
65        return min_moves
66
1class Solution {
2    public long minimumMoves(int[] nums, int k, int maxChanges) {
3        int n = nums.length;
4      
5        // Prefix sum arrays for optimization
6        // prefixCount[i] = count of 1s in nums[0...i-1]
7        // prefixWeightedSum[i] = sum of (index * value) for nums[0...i-1]
8        int[] prefixCount = new int[n + 1];
9        long[] prefixWeightedSum = new long[n + 1];
10      
11        // Build prefix sum arrays
12        for (int i = 1; i <= n; ++i) {
13            prefixCount[i] = prefixCount[i - 1] + nums[i - 1];
14            prefixWeightedSum[i] = prefixWeightedSum[i - 1] + i * nums[i - 1];
15        }
16      
17        long minMoves = Long.MAX_VALUE;
18      
19        // Try each position as the collection point
20        for (int position = 1; position <= n; ++position) {
21            long currentMoves = 0;
22            int remaining = k - nums[position - 1];  // Items still needed after taking current position
23          
24            // First, try to collect from immediate neighbors (distance = 1)
25            for (int neighborIdx = position - 1; neighborIdx <= position + 1; neighborIdx += 2) {
26                if (remaining > 0 && 1 <= neighborIdx && neighborIdx <= n && nums[neighborIdx - 1] == 1) {
27                    remaining--;
28                    currentMoves++;
29                }
30            }
31          
32            // Use maxChanges to create and collect items (cost = 2 per item)
33            int changesUsed = Math.min(remaining, maxChanges);
34            remaining -= changesUsed;
35            currentMoves += changesUsed * 2;
36          
37            // If we've collected enough items, update answer and continue
38            if (remaining <= 0) {
39                minMoves = Math.min(minMoves, currentMoves);
40                continue;
41            }
42          
43            // Binary search for the minimum radius to collect remaining items
44            int left = 2, right = Math.max(position - 1, n - position);
45          
46            while (left <= right) {
47                int radius = (left + right) >> 1;
48              
49                // Define search ranges (excluding immediate neighbors already processed)
50                int leftRangeStart = Math.max(1, position - radius);
51                int leftRangeEnd = Math.max(0, position - 2);
52                int rightRangeStart = Math.min(n + 1, position + 2);
53                int rightRangeEnd = Math.min(n, position + radius);
54              
55                // Count available items in both ranges
56                int leftCount = prefixCount[leftRangeEnd] - prefixCount[leftRangeStart - 1];
57                int rightCount = prefixCount[rightRangeEnd] - prefixCount[rightRangeStart - 1];
58              
59                if (leftCount + rightCount >= remaining) {
60                    // Calculate total distance to collect items from both sides
61                    long leftDistance = 1L * leftCount * position - (prefixWeightedSum[leftRangeEnd] - prefixWeightedSum[leftRangeStart - 1]);
62                    long rightDistance = prefixWeightedSum[rightRangeEnd] - prefixWeightedSum[rightRangeStart - 1] - 1L * rightCount * position;
63                  
64                    minMoves = Math.min(minMoves, currentMoves + leftDistance + rightDistance);
65                    right = radius - 1;  // Try smaller radius
66                } else {
67                    left = radius + 1;  // Need larger radius
68                }
69            }
70        }
71      
72        return minMoves;
73    }
74}
75
1class Solution {
2public:
3    long long minimumMoves(vector<int>& nums, int k, int maxChanges) {
4        int n = nums.size();
5      
6        // Prefix sum arrays
7        // prefixCount[i] = count of 1s in nums[0..i-1]
8        // prefixWeightedSum[i] = sum of (index+1) * nums[index] for nums[0..i-1]
9        vector<int> prefixCount(n + 1, 0);
10        vector<long long> prefixWeightedSum(n + 1, 0);
11      
12        // Build prefix sums
13        for (int i = 1; i <= n; ++i) {
14            prefixCount[i] = prefixCount[i - 1] + nums[i - 1];
15            prefixWeightedSum[i] = prefixWeightedSum[i - 1] + 1LL * i * nums[i - 1];
16        }
17      
18        long long minMoves = LLONG_MAX;
19      
20        // Try each position as the collection point
21        for (int position = 1; position <= n; ++position) {
22            long long currentMoves = 0;
23            int remaining = k - nums[position - 1];  // Ones still needed after taking current position
24          
25            // First, collect adjacent ones (distance 1) without changes
26            for (int adjacentPos = position - 1; adjacentPos <= position + 1; adjacentPos += 2) {
27                if (remaining > 0 && 1 <= adjacentPos && adjacentPos <= n && nums[adjacentPos - 1] == 1) {
28                    --remaining;
29                    ++currentMoves;  // Cost 1 to collect adjacent one
30                }
31            }
32          
33            // Use maxChanges to create and collect ones (cost 2 per one)
34            int changesUsed = min(remaining, maxChanges);
35            remaining -= changesUsed;
36            currentMoves += changesUsed * 2;
37          
38            // If we've collected enough ones, update answer
39            if (remaining <= 0) {
40                minMoves = min(minMoves, currentMoves);
41                continue;
42            }
43          
44            // Binary search for minimum radius to collect remaining ones
45            int left = 2, right = max(position - 1, n - position);
46          
47            while (left <= right) {
48                int radius = (left + right) / 2;
49              
50                // Define search ranges (excluding adjacent positions already checked)
51                int leftRangeStart = max(1, position - radius);
52                int leftRangeEnd = max(0, position - 2);
53                int rightRangeStart = min(n + 1, position + 2);
54                int rightRangeEnd = min(n, position + radius);
55              
56                // Count ones in left and right ranges
57                int leftCount = prefixCount[leftRangeEnd] - prefixCount[leftRangeStart - 1];
58                int rightCount = prefixCount[rightRangeEnd] - prefixCount[rightRangeStart - 1];
59              
60                if (leftCount + rightCount >= remaining) {
61                    // Calculate total distance to move ones from left range
62                    long long leftCost = 1LL * leftCount * position - 
63                                        (prefixWeightedSum[leftRangeEnd] - prefixWeightedSum[leftRangeStart - 1]);
64                  
65                    // Calculate total distance to move ones from right range
66                    long long rightCost = (prefixWeightedSum[rightRangeEnd] - prefixWeightedSum[rightRangeStart - 1]) - 
67                                         1LL * rightCount * position;
68                  
69                    minMoves = min(minMoves, currentMoves + leftCost + rightCost);
70                    right = radius - 1;  // Try smaller radius
71                } else {
72                    left = radius + 1;  // Need larger radius
73                }
74            }
75        }
76      
77        return minMoves;
78    }
79};
80
1/**
2 * Finds the minimum number of moves to collect k ones in the array
3 * @param nums - Binary array containing 0s and 1s
4 * @param k - Number of ones to collect
5 * @param maxChanges - Maximum number of changes allowed (0 to 1 conversions)
6 * @returns Minimum number of moves required
7 */
8function minimumMoves(nums: number[], k: number, maxChanges: number): number {
9    const arrayLength = nums.length;
10  
11    // Prefix sum arrays for counting ones and calculating weighted sums
12    const onesCount = Array(arrayLength + 1).fill(0);
13    const weightedSum = Array(arrayLength + 1).fill(0);
14
15    // Build prefix sum arrays
16    // onesCount[i] = number of ones in nums[0...i-1]
17    // weightedSum[i] = sum of (index+1) * value for nums[0...i-1]
18    for (let i = 1; i <= arrayLength; i++) {
19        onesCount[i] = onesCount[i - 1] + nums[i - 1];
20        weightedSum[i] = weightedSum[i - 1] + i * nums[i - 1];
21    }
22
23    let minMoves = Infinity;
24  
25    // Try each position as the collection point
26    for (let position = 1; position <= arrayLength; position++) {
27        let totalMoves = 0;
28        let remainingOnes = k - nums[position - 1]; // Ones still needed after taking current position
29
30        // First, try to collect ones from immediate neighbors (distance 1)
31        for (let neighborIndex of [position - 1, position + 1]) {
32            if (remainingOnes > 0 && 
33                neighborIndex >= 1 && 
34                neighborIndex <= arrayLength && 
35                nums[neighborIndex - 1] === 1) {
36                remainingOnes--;
37                totalMoves++; // Cost 1 move for adjacent position
38            }
39        }
40
41        // Use changes to create ones at distance 2 (most efficient for changes)
42        const changesUsed = Math.min(remainingOnes, maxChanges);
43        remainingOnes -= changesUsed;
44        totalMoves += changesUsed * 2; // Each change costs 2 moves
45
46        // If we've collected enough ones, update answer
47        if (remainingOnes <= 0) {
48            minMoves = Math.min(minMoves, totalMoves);
49            continue;
50        }
51
52        // Binary search for minimum radius to collect remaining ones
53        let searchLeft = 2;
54        let searchRight = Math.max(position - 1, arrayLength - position);
55
56        while (searchLeft <= searchRight) {
57            const radius = (searchLeft + searchRight) >> 1;
58          
59            // Define left range [l1, r1] and right range [l2, r2]
60            // Exclude positions within distance 1 (already handled)
61            const leftRangeStart = Math.max(1, position - radius);
62            const leftRangeEnd = Math.max(0, position - 2);
63            const rightRangeStart = Math.min(arrayLength + 1, position + 2);
64            const rightRangeEnd = Math.min(arrayLength, position + radius);
65
66            // Count ones in left and right ranges using prefix sums
67            const leftOnes = onesCount[leftRangeEnd] - onesCount[leftRangeStart - 1];
68            const rightOnes = onesCount[rightRangeEnd] - onesCount[rightRangeStart - 1];
69
70            if (leftOnes + rightOnes >= remainingOnes) {
71                // Calculate move cost for left range (positions < current)
72                const leftMoveCost = leftOnes * position - (weightedSum[leftRangeEnd] - weightedSum[leftRangeStart - 1]);
73                // Calculate move cost for right range (positions > current)
74                const rightMoveCost = (weightedSum[rightRangeEnd] - weightedSum[rightRangeStart - 1]) - rightOnes * position;
75              
76                minMoves = Math.min(minMoves, totalMoves + leftMoveCost + rightMoveCost);
77                searchRight = radius - 1; // Try smaller radius
78            } else {
79                searchLeft = radius + 1; // Need larger radius
80            }
81        }
82    }
83
84    return minMoves;
85}
86

Time and Space Complexity

Time Complexity: O(n × log n)

The algorithm iterates through each position i in the array (outer loop runs n times). For each position, it performs a binary search to find the optimal range for collecting ones. The binary search runs in O(log n) time since it searches within a range from 2 to max(i - 1, n - i), which is at most n. All operations inside the binary search (calculating prefix sums, counting ones) are done in constant time due to preprocessing. Therefore, the overall time complexity is O(n × log n).

Space Complexity: O(n)

The algorithm uses two auxiliary arrays: cnt (prefix sum array for counting ones) and s (weighted prefix sum array), each of size n + 1. These arrays require O(n) space. The remaining variables (ans, t, need, l, r, etc.) use constant space. Thus, the total space complexity is O(n).

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

Common Pitfalls

1. Incorrect Handling of Partial Collection from Ranges

The Pitfall: The current implementation calculates the cost assuming we take ALL ones from both the left and right ranges when left_count + right_count >= remaining_needed. However, we only need remaining_needed ones, not all available ones. This leads to an overestimation of the minimum cost.

Why It Happens: When binary searching for the minimum radius, once we find a radius where enough ones are available, we calculate:

left_cost = left_count * i - (weighted_sum[left_range_end] - weighted_sum[left_range_start - 1])
right_cost = weighted_sum[right_range_end] - weighted_sum[right_range_start - 1] - right_count * i

This computes the cost to move ALL left_count + right_count ones, but we might only need a subset.

Example Scenario:

  • Position i = 5, remaining_needed = 3
  • Left range has 2 ones at positions [2, 3]
  • Right range has 4 ones at positions [7, 8, 9, 10]
  • Current code calculates cost for all 6 ones, but we only need 3

Solution: We need to select the closest remaining_needed ones from the combined ranges. The optimal strategy is to:

  1. Sort all available ones by their distance from position i
  2. Select the remaining_needed closest ones
  3. Calculate the actual cost for only those selected ones

Corrected Code Segment:

if left_count + right_count >= remaining_needed:
    # Collect all ones with their distances
    ones_with_dist = []
  
    # Add ones from left range
    for j in range(left_range_start, left_range_end + 1):
        if nums[j - 1] == 1:
            ones_with_dist.append(i - j)  # distance to position i
  
    # Add ones from right range  
    for j in range(right_range_start, right_range_end + 1):
        if nums[j - 1] == 1:
            ones_with_dist.append(j - i)  # distance to position i
  
    # Sort by distance and take the closest remaining_needed ones
    ones_with_dist.sort()
    actual_cost = sum(ones_with_dist[:remaining_needed])
  
    min_moves = min(min_moves, moves + actual_cost)
    right = mid_radius - 1

2. Alternative Efficient Solution Using Sliding Window

Instead of iterating through positions in the binary search, a more efficient approach maintains sorted positions of all ones and uses a sliding window:

def minimumMoves(self, nums: List[int], k: int, maxChanges: int) -> int:
    # Collect positions of all ones
    ones_positions = [i for i, val in enumerate(nums) if val == 1]
    m = len(ones_positions)
  
    if m == 0:
        return 2 * k  # All ones must be created using maxChanges
  
    # Prefix sum for efficient range sum calculation
    prefix = [0] * (m + 1)
    for i in range(m):
        prefix[i + 1] = prefix[i] + ones_positions[i]
  
    min_moves = float('inf')
  
    # For each possible collection point
    for alice_pos in range(len(nums)):
        moves = 0
        remaining = k
      
        # Take one at current position if available
        if nums[alice_pos] == 1:
            remaining -= 1
      
        # Use maxChanges optimally (create adjacent ones)
        created = min(remaining, maxChanges)
        remaining -= created
        moves += created * 2
      
        if remaining == 0:
            min_moves = min(min_moves, moves)
            continue
      
        # Find the cost to collect 'remaining' closest ones
        # Use sliding window on ones_positions
        for window_size in range(1, min(remaining, m) + 1):
            for start in range(m - window_size + 1):
                end = start + window_size
                median_idx = (start + end) // 2
                median_pos = ones_positions[median_idx]
              
                # Calculate cost to move all ones in window to median_pos
                cost = 0
                for i in range(start, end):
                    cost += abs(ones_positions[i] - median_pos)
              
                # Then move from median_pos to alice_pos
                cost += abs(median_pos - alice_pos) * window_size
              
                if window_size >= remaining:
                    min_moves = min(min_moves, moves + cost)
  
    return min_moves

This approach correctly handles partial collection and provides optimal selection of ones to minimize total movement cost.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What is the best way of checking if an element exists in a sorted array once in terms of time complexity? Select the best that applies.


Recommended Readings

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

Load More