leetcode

Leetcode Solutions (0x6A73)
git clone https://git.pngu.org/leetcode
Log | Files | Refs | Submodules | README

commit 33da8f1d4dee4987f9836fbb170a9d6e62f38ce9
parent 8173478662b7e68d38f8f4693249aae4ed8cc285
Author: Jack Sangdahl <jack@pngu.org>
Date:   Mon,  2 Feb 2026 14:32:03 -0700

3013. divide an array into subarrays with minimum cost 2

Diffstat:
Adivide_arr_subarr_min_cost2.c | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adivide_arr_subarr_min_cost2.py | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 228 insertions(+), 0 deletions(-)

diff --git a/divide_arr_subarr_min_cost2.c b/divide_arr_subarr_min_cost2.c @@ -0,0 +1,141 @@ +// 3013. Divide an Array Into Subarrays With Minimum Cost II +#include "leetcode.h" + +/* + * you are given a 0 indexed array of integers 'nums' of length 'n', and two + positive integers 'k' and 'dist'. the cost of an array is the value of its + first element. for example, the cost of '1,2,3' is 1. you need to divide 'nums' + into 'k' disjoint contiguous subarrays, such that the difference between the + starting index of the second subarray and the starting index of the k'th + subarray should be less than or equal to 'dist'. in other words, if you divide + 'nums' into the subarrays, then 'i_k-1 - i_1 <= dist'. return the minimum + possible sum of the cost of these subarrays. + */ + +struct element { + int val; +}; + +int cmp(const void *a, const void *b) { + return ((struct element *)a)->val - ((struct element *)b)->val; +} + +void update(int *bit_cnt, long long *bit_sum, int max_rank, int idx, int cnt, + long long val) { + while (idx <= max_rank) { + bit_cnt[idx] += cnt; + bit_sum[idx] += val; + idx += idx & (-idx); + } +} + +long long query_k_smallest(int *bit_cnt, long long *bit_sum, int max_rank, + int k, int *rank_val) { + int idx = 0, curr_cnt = 0; + for (int i = 1 << 17; i > 0; i >>= 1) + if (idx + i <= max_rank && curr_cnt + bit_cnt[idx + i] < k) { + idx += i; + curr_cnt += bit_cnt[idx]; + } + int target = idx + 1, tmp = target; + long long sum = 0; + while (tmp > 0) { + sum += bit_sum[tmp]; + tmp -= tmp & (-tmp); + } + tmp = target; + int cnt_target = 0; + while (tmp > 0) { + cnt_target += bit_cnt[tmp]; + tmp -= tmp & (-tmp); + } + int exc = cnt_target - k; + if (exc > 0) + sum -= (long long)exc * rank_val[target]; + return sum; +} + +int get_rank(int val, int *unique_vals, int unique_size) { + int l = 0, r = unique_size - 1; + while (l <= r) { + int m = l + (r - l) / 2; + if (unique_vals[m] == val) + return m + 1; + else if (unique_vals[m] < val) + l = m + 1; + else + r = m - 1; + } + return -1; +} + +long long minimumCost(int *nums, int numsSize, int k, int dist) { + int target = k - 1; + struct element *tmp = + (struct element *)malloc(numsSize * sizeof(struct element)); + for (int i = 1; i < numsSize; i++) + tmp[i - 1].val = nums[i]; + qsort(tmp, numsSize - 1, sizeof(struct element), cmp); + int *unique_vals = (int *)malloc(numsSize * sizeof(int)); + int u_ptr = 0; + if (numsSize > 1) { + unique_vals[u_ptr++] = tmp[0].val; + for (int i = 1; i < numsSize - 1; i++) + if (tmp[i].val != tmp[i - 1].val) + unique_vals[u_ptr++] = tmp[i].val; + } + int max_rank = u_ptr; + int *rank_lut = (int *)malloc((max_rank + 2) * sizeof(int)); + for (int i = 0; i < max_rank; i++) + rank_lut[i + 1] = unique_vals[i]; + int *bit_cnt = (int *)calloc(max_rank + 2, sizeof(int)); + long long *bit_sum = (long long *)calloc(max_rank + 2, sizeof(long long)); + int lim = (dist + 1 < numsSize - 1) ? dist + 1 : numsSize - 1; + int curr_window = 0; + for (int i = 1; i <= lim; i++) { + int r = get_rank(nums[i], unique_vals, max_rank); + update(bit_cnt, bit_sum, max_rank, r, 1, nums[i]); + curr_window++; + } + long long min_cost = -1; + if (curr_window >= target) + min_cost = query_k_smallest(bit_cnt, bit_sum, max_rank, target, rank_lut); + for (int i = 2; i < numsSize; i++) { + int out_r = get_rank(nums[i - 1], unique_vals, max_rank); + update(bit_cnt, bit_sum, max_rank, out_r, -1, -nums[i - 1]); + curr_window--; + + if (i + dist < numsSize) { + int in_r = get_rank(nums[i - 1], unique_vals, max_rank); + update(bit_cnt, bit_sum, max_rank, in_r, 1, nums[i + dist]); + curr_window++; + } + if (curr_window >= target) { + long long curr_k_sum = + query_k_smallest(bit_cnt, bit_sum, max_rank, target, rank_lut); + if (min_cost == -1 || curr_k_sum < min_cost) + min_cost = curr_k_sum; + } + } + free(tmp); + free(unique_vals); + free(rank_lut); + free(bit_cnt); + free(bit_sum); + return min_cost + nums[0]; +} + +int main() { + int n1[] = {1, 3, 2, 6, 4, 2}; + int n2[] = {10, 1, 2, 2, 2, 1}; + int n3[] = {10, 8, 18, 9}; + long long r1 = minimumCost(n1, ARRAY_SIZE(n1), 3, 3); + long long r2 = minimumCost(n2, ARRAY_SIZE(n2), 4, 3); + long long r3 = minimumCost(n3, ARRAY_SIZE(n3), 3, 1); + printf("%lld\n", r1); // expect: 5 + assert(r1 == 5); + printf("%lld\n", r2); // expect: 15 + assert(r2 == 15); + printf("%lld\n", r3); // expect: 36 + assert(r3 == 36); +} diff --git a/divide_arr_subarr_min_cost2.py b/divide_arr_subarr_min_cost2.py @@ -0,0 +1,87 @@ +# 3013. Divide an Array Into Subarrays With Minimum Cost II +import bisect + +""" +you are given a 0 indexed array of integers 'nums' of length 'n', and two +positive integers 'k' and 'dist'. the cost of an array is the value of its +first element. for example, the cost of '1,2,3' is 1. you need to divide 'nums' +into 'k' disjoint contiguous subarrays, such that the difference between the +starting index of the second subarray and the starting index of the k'th +subarray should be less than or equal to 'dist'. in other words, if you divide +'nums' into the subarrays, then 'i_k-1 - i_1 <= dist'. return the minimum +possible sum of the cost of these subarrays. +""" + + +class Solution(object): + class smart_window: + def __init__(self, k): + self.k = k + self.low = [] + self.high = [] + self.sumLow = 0 + + def window_size(self): + return len(self.low) + len(self.high) + + def erase_one(self, arr, x): + i = bisect.bisect_left(arr, x) + if i < len(arr) and arr[i] == x: + arr.pop(i) + return True + return False + + def rebalance(self): + need = min(self.k, self.window_size()) + while len(self.low) > need: + x = self.low.pop() + self.sumLow -= x + bisect.insort(self.high, x) + while len(self.low) < need and self.high: + x = self.high.pop(0) + bisect.insort(self.low, x) + self.sumLow += x + + def add(self, x): + if not self.low or x <= self.low[-1]: + bisect.insort(self.low, x) + self.sumLow += x + else: + bisect.insort(self.high, x) + self.rebalance() + + def remove(self, x): + if self.erase_one(self.low, x): + self.sumLow -= x + else: + self.erase_one(self.high, x) + self.rebalance() + + def query(self): + return self.sumLow + + def minimumCost(self, nums, k, dist): + """ + :type nums: List[int] + :type k: int + :type dist: int + :rtype: int + """ + n = len(nums) + k -= 1 + window = self.smart_window(k) + for i in range(1, 1 + dist + 1): + window.add(nums[i]) + ans = window.query() + for i in range(2, n - dist): + window.remove(nums[i - 1]) + window.add(nums[i + dist]) + ans = min(ans, window.query()) + return ans + nums[0] + + +if __name__ == "__main__": + obj = Solution() + print(obj.minimumCost(nums=[1, 3, 2, 6, 4, 2], k=3, dist=3)) + print(obj.minimumCost(nums=[10, 1, 2, 2, 2, 1], k=4, dist=3)) + print(obj.minimumCost(nums=[10, 8, 18, 9], k=3, dist=1))