- Choose the invariant that makes a window valid or useful.
- Advance the right boundary and add the new element.
- Move the left boundary only as needed while maintaining the invariant and updating the answer.
Code notes
- 87 lines of C++ from the credited upstream file 3049.cpp.
- The implementation visibly relies on sequence storage, hash lookup, work queue.
- 5 loop blocks detected.
Complexity
Confirm that neither pointer moves backwards; if so, the scan is usually linear apart from the window’s data-structure operations.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
1class Solution {2 public:3 int earliestSecondToMarkIndices(vector<int>& nums,4 vector<int>& changeIndices) {5 const long numsSum = accumulate(nums.begin(), nums.end(), 0L);6 7 const unordered_map<int, int> secondToIndex =8 getSecondToIndex(nums, changeIndices);9 int l = 0;10 int r = changeIndices.size() + 1;11 12 while (l < r) {13 const int m = (l + r) / 2;14 if (canMark(nums, secondToIndex, m, numsSum))15 r = m;16 else17 l = m + 1;18 }19 20 return l <= changeIndices.size() ? l : -1;21 }22 23 private:24 25 bool canMark(const vector<int>& nums,26 const unordered_map<int, int>& secondToIndex, int maxSecond,27 const long numsSum) {28 29 30 priority_queue<int, vector<int>, greater<int>> minHeap;31 int marks = 0;32 33 for (int second = maxSecond - 1; second >= 0; --second) {34 if (const auto it = secondToIndex.find(second);35 it != secondToIndex.end()) {36 37 const int index = it->second;38 minHeap.push(nums[index]);39 if (marks == 0) {40 41 42 minHeap.pop();43 ++marks;44 } else {45 46 47 --marks;48 }49 } else {50 51 52 ++marks;53 }54 }55 56 const int heapSize = minHeap.size();57 const long decrementAndMarkCost =58 numsSum - getHeapSum(minHeap) + (nums.size() - heapSize);59 const long zeroAndMarkCost = heapSize + heapSize;60 return decrementAndMarkCost + zeroAndMarkCost <= maxSecond;61 }62 63 long getHeapSum(priority_queue<int, vector<int>, greater<int>>& heap) {64 long heapSum = 0;65 while (!heap.empty())66 heapSum += heap.top(), heap.pop();67 return heapSum;68 }69 70 unordered_map<int, int> getSecondToIndex(const vector<int>& nums,71 const vector<int>& changeIndices) {72 73 unordered_map<int, int> indexToFirstSecond;74 unordered_map<int, int> secondToIndex;75 for (int zeroIndexedSecond = 0; zeroIndexedSecond < changeIndices.size();76 ++zeroIndexedSecond) {77 78 const int index = changeIndices[zeroIndexedSecond] - 1;79 if (nums[index] > 0 && !indexToFirstSecond.contains(index))80 indexToFirstSecond[index] = zeroIndexedSecond;81 }82 for (const auto& [index, second] : indexToFirstSecond)83 secondToIndex[second] = index;84 return secondToIndex;85 }86};87