- Define precisely what one DP state represents.
- Establish the base cases before transitions are evaluated.
- Process states in dependency order and combine only already-known values.
Code notes
- 190 lines of Python from the credited upstream file minimum-operations-to-make-elements-within-k-subarrays-equal.py.
- The implementation visibly relies on sequence storage, hash lookup, work queue, cached states.
- No explicit loop blocks detected.
Complexity
Multiply the number of reachable states by the work performed for each transition, then include the stored state table in memory usage.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
123 4from sortedcontainers import SortedList5 6 78class Solution(object):9 def minOperations(self, nums, x, k):10 """11 :type nums: List[int]12 :type x: int13 :type k: int14 :rtype: int15 """16 class SlidingWindow(object):17 def __init__(self):18 self.left = SortedList()19 self.right = SortedList()20 self.total1 = self.total2 = 021 22 def add(self, val):23 if not self.left or val <= self.left[-1]:24 self.left.add(val)25 self.total1 += val26 else:27 self.right.add(val)28 self.total2 += val29 self.rebalance()30 31 def remove(self, val):32 if val <= self.left[-1]:33 self.left.remove(val)34 self.total1 -= val35 else:36 self.right.remove(val)37 self.total2 -= val38 self.rebalance()39 40 def rebalance(self):41 if len(self.left) < len(self.right):42 self.total2 -= self.right[0]43 self.total1 += self.right[0]44 self.left.add(self.right[0])45 self.right.pop(0)46 elif len(self.left) > len(self.right)+1:47 self.total1 -= self.left[-1]48 self.total2 += self.left[-1]49 self.right.add(self.left[-1])50 self.left.pop()51 52 def median(self):53 return self.left[-1]54 55 56 INF = float("inf")57 sw = SlidingWindow()58 cost = [INF]*(len(nums)+1)59 for i in xrange(len(nums)):60 if i-x >= 0:61 sw.remove(nums[i-x])62 sw.add(nums[i])63 if i >= x-1:64 cost[i+1] = (sw.median()*len(sw.left)-sw.total1) + (sw.total2-sw.median()*len(sw.right))65 dp = [0]*(len(nums)+1)66 for i in xrange(k):67 new_dp = [INF]*(len(nums)+1)68 for j in xrange((i+1)*x, len(nums)+1):69 new_dp[j] = min(new_dp[j-1], dp[j-x]+cost[j])70 dp = new_dp71 return dp[-1]72 73 747576import heapq77import collections78 79 8081class Solution2(object):82 def minOperations(self, nums, x, k):83 """84 :type nums: List[int]85 :type x: int86 :type k: int87 :rtype: int88 """89 class LazyHeap(object):90 def __init__(self, sign):91 self.heap = []92 self.to_remove = collections.defaultdict(int)93 self.cnt = 094 self.sign = sign95 96 def push(self, val):97 heapq.heappush(self.heap, self.sign*val)98 99 def full_remove(self):100 result = []101 for x in self.heap:102 if x not in self.to_remove:103 result.append(x)104 continue105 self.to_remove[x] -= 1106 if not self.to_remove[x]:107 del self.to_remove[x]108 self.heap[:] = result109 heapq.heapify(self.heap)110 111 def remove(self, val):112 self.to_remove[self.sign*val] += 1113 self.cnt += 1114 if self.cnt > len(self.heap)-self.cnt:115 self.full_remove()116 self.cnt = 0117 118 def pop(self):119 self.remove(self.top())120 121 def top(self):122 while self.heap and self.heap[0] in self.to_remove:123 self.to_remove[self.heap[0]] -= 1124 self.cnt -= 1125 if self.to_remove[self.heap[0]] == 0:126 del self.to_remove[self.heap[0]]127 heapq.heappop(self.heap)128 return self.sign*self.heap[0]129 130 def __len__(self):131 return len(self.heap)-self.cnt132 133 134 class SlidingWindow(object):135 def __init__(self):136 self.left = LazyHeap(-1) 137 self.right = LazyHeap(+1) 138 self.total1 = self.total2 = 0139 140 def add(self, val):141 if not self.left or val <= self.left.top():142 self.left.push(val)143 self.total1 += val144 else:145 self.right.push(val)146 self.total2 += val147 self.rebalance()148 149 def remove(self, val):150 if val <= self.left.top():151 self.left.remove(val)152 self.total1 -= val153 else:154 self.right.remove(val)155 self.total2 -= val156 self.rebalance()157 158 def rebalance(self):159 if len(self.left) < len(self.right):160 self.total2 -= self.right.top()161 self.total1 += self.right.top()162 self.left.push(self.right.top())163 self.right.pop()164 elif len(self.left) > len(self.right)+1:165 self.total1 -= self.left.top()166 self.total2 += self.left.top()167 self.right.push(self.left.top())168 self.left.pop()169 170 def median(self):171 return self.left.top()172 173 174 INF = float("inf")175 sw = SlidingWindow()176 cost = [INF]*(len(nums)+1)177 for i in xrange(len(nums)):178 if i-x >= 0:179 sw.remove(nums[i-x])180 sw.add(nums[i])181 if i >= x-1:182 cost[i+1] = (sw.median()*len(sw.left)-sw.total1) + (sw.total2-sw.median()*len(sw.right))183 dp = [0]*(len(nums)+1)184 for i in xrange(k):185 new_dp = [INF]*(len(nums)+1)186 for j in xrange((i+1)*x, len(nums)+1):187 new_dp[j] = min(new_dp[j-1], dp[j-x]+cost[j])188 dp = new_dp189 return dp[-1]190