#3086
Hard Algorithms Minimum moves to pick k ones
Array Greedy Sliding Window Prefix Sum
21.5% acceptance
Feb 25, 2026
61
53
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 the goal is for Alice to pick up k ones from nums using the minimum number of moves.
Alice picks up any index aliceIndex in the range [0, n - 1] and stands there. If nums[aliceIndex] == 1, Alice picks up the one and nums[aliceIndex] becomes 0 (this does not count as a move).
After this, Alice can make any number of moves where in each move Alice must perform exactly one of the following actions:
Select any index j != aliceIndex such that nums[j] == 0 and set nums[j] = 1. This action can be performed at most maxChanges times.
Select any two adjacent indices x and y (|x - y| == 1) such that nums[x] == 1, nums[y] == 0, then swap their values. If y == aliceIndex, Alice picks up the one after this move and nums[y] becomes 0.
Return the minimum number of moves required by Alice to pick exactly k ones.
Solution
Rust
Time O(n²)
Space O(n)
impl Solution {
pub fn minimum_moves(nums: Vec<i32>, k: i32, max_changes: i32) -> i64 {
let n = nums.len();
let k = k as i64;
let max_changes = max_changes as i64;
// Positions of 1s
let ones: Vec<i64> = (0..n).filter(|&i| nums[i] == 1).map(|i| i as i64).collect();
let total_ones = ones.len() as i64;
// Prefix sum of ones positions
let prefix: Vec<i64> = {
let mut p = vec![0i64; ones.len() + 1];
for i in 0..ones.len() { p[i+1] = p[i] + ones[i]; }
p
};
let mut ans = i64::MAX;
// Try each position as Alice's starting position
// When standing at pos p with some 1s nearby and using maxChanges:
// We can pick up at most min(3, k, maxChanges*2...) via changes quickly
// This is O(n) with sliding window on ones positions
// For each center position (from ones), try picking nearby ones with sliding window
// Actually: for each potential alice position (from ones array), sliding window of k ones
// But that's complex. Let me use the sliding window approach on the ones array.
// For a window of 'need' ones centered around some alice position:
// - Ones at distance 1 or 2 can be moved to alice in 1 or 2 moves
// - For 'grabs' via maxChanges, each costs 2 moves (create + move to alice)
// Approach: try every alice position = ones[i]
// For each alice position, we can instantly pick up nearby ones (within 2 steps via adjacent swaps)
// But this gets complex. Use standard sliding window approach.
// Greedy:
// - First, take up to min(k, maxChanges*2) via changes (2 moves each, 1 if adjacent=1)
// Actually: if there's a 1 adjacent, pick it up (1 move). Else create then pick (2 moves).
// But we want to minimize. Let's count: up to min(3, k) "free" from standing position + neighbors.
// Then use maxChanges for remaining (2 each). Then use slide for the rest (median trick).
// This problem is complex. Let me implement the O(n log n) solution with binary search on window.
for i in 0..ones.len() {
// Alice at ones[i]
let pos = ones[i];
// Count immediately free picks (at pos, pos-1, pos+1)
let free_picks = nums[pos as usize] as i64; // already picked in the problem (not a move)
// Actually the "free" pick at aliceIndex is handled separately.
// Use the ones array directly.
// For each window of size k around i, compute cost.
// Actually I'll use a different approach: try all windows of ones with sliding window.
let _ = (free_picks, pos);
break; // This approach is too complex, use a different method below
}
// Use the approach: for each alice position (which must be an optimal position, i.e., a median),
// Binary search on window of ones of size 'window_size' and compute median cost.
let m = ones.len();
// For window of size w of ones, alice position at ones[mid], cost = sum |ones[j] - ones[mid]|
// But we also have maxChanges (each change: 2 moves if no adjacent 1, 1 if adjacent 1)
// Simplified: pretend max_changes are each 2 moves, and nearby ones slide at 1 move each.
// Let need = k (ones to pick), changes = min(need, max_changes) via 2 moves each
// remaining = need - changes from the ones array (slide)
// But this isn't exact. Let me implement the standard approach:
// Phase 1: use maxChanges changes (each 2 moves = place 1 adjacent then slide to alice)
// Phase 2: pick remaining ones by sliding (window of remaining around alice, median optimal)
// We want to minimize: 2 * used_changes + sum of distances to alice for slid ones
// Try all splits: used_changes in [max(0, k - total_ones) .. min(k, max_changes)]
let min_changes = (k - total_ones).max(0);
let max_used = k.min(max_changes);
if min_changes > max_used { return -1; } // impossible (shouldn't happen per constraints)
// For each used_changes, need to slide (k - used_changes) ones
// These ones should be the closest to alice position (median trick)
for used_changes in min_changes..=max_used {
let need_slide = k - used_changes;
let cost_changes = used_changes * 2;
if need_slide == 0 {
ans = ans.min(cost_changes);
continue;
}
let ns = need_slide as usize;
if ns > m { continue; }
// Sliding window of size ns over ones
for r in (ns-1)..m {
let l = r + 1 - ns;
let mid = (l + r) / 2;
let alice = ones[mid];
// Sum of distances to alice for ones[l..=r]
let left_sum = alice * (mid - l) as i64 - (prefix[mid] - prefix[l]);
let right_sum = (prefix[r+1] - prefix[mid+1]) - alice * (r - mid) as i64;
let dist_cost = left_sum + right_sum;
// Count ones adjacent to alice (ones that can be picked up in 1 move instead of computing dist)
// Actually if they're in the array, the dist is correct.
// But wait: adjacent ones (at alice ± 1) have cost 1, not their actual distance.
// The actual dist IS their distance. So this is fine.
ans = ans.min(cost_changes + dist_cost);
}
}
ans
}
}