leetcode

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

commit 6167455d5177400d604fd64272d3fd1be8aebee3
parent 45479952ecfb1e41ca79982b36d0fcbec35c0476
Author: Jack Sangdahl <jack@pngu.org>
Date:   Thu, 22 Jan 2026 20:12:00 -0700

3510. minimum pair removal to sort array 2

Diffstat:
Aminimum_pair_removal_sort_arr2.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aminimum_pair_removal_sort_arr2.py | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 284 insertions(+), 0 deletions(-)

diff --git a/minimum_pair_removal_sort_arr2.c b/minimum_pair_removal_sort_arr2.c @@ -0,0 +1,225 @@ +// 3510. Minimum Pair Removal to Sort Array II +#include "leetcode.h" + +/* + * given an array 'nums', you can perfor the following operation any number of + * times: select the adjacent pair with the minimum sum in 'nums'. if multiple + * such pairs exist, choose the leftmost one. replace the pair with their sum. + * return the minimum number of operations needed to make the array + * non-decreasing. an array is said to be non-decreasing if each element is + * greater than or equal to its previous element. + */ + +#define QUEUE_SIZE 4096 + +struct node { + long long val; + int left; + struct node *prev; + struct node *next; +}; + +struct node *node_init(long long val, int left) { + struct node *obj = (struct node *)malloc(sizeof(struct node)); + obj->val = val; + obj->left = left; + obj->prev = NULL; + obj->next = NULL; + return obj; +} + +struct queue_item { + struct node *first; + struct node *second; + long long cost; + int first_left; + int second_left; +}; + +struct element { + struct queue_item item; +}; + +typedef bool (*cmp)(const void *, const void *); + +static bool item_less(const void *a, const void *b) { + const struct element *e1 = (const struct element *)a; + const struct element *e2 = (const struct element *)b; + const struct queue_item *i1 = &e1->item; + const struct queue_item *i2 = &e2->item; + if (i1->cost != i2->cost) + return i1->cost > i2->cost; + return i1->first_left > i2->first_left; +} + +static void swap(struct element *obj, int i, int j) { + struct element tmp = obj[i]; + obj[i] = obj[j]; + obj[j] = tmp; +} + +struct priority_queue { + struct element *arr; + int capacity; + int queue_size; + cmp less_fn; +}; + +struct priority_queue *priority_queue_init(cmp cmp_fn) { + struct priority_queue *obj = + (struct priority_queue *)malloc(sizeof(struct priority_queue)); + obj->capacity = QUEUE_SIZE; + obj->arr = (struct element *)malloc(obj->capacity * sizeof(struct element)); + obj->queue_size = 0; + obj->less_fn = cmp_fn; + return obj; +} + +static void down(struct element *obj, int size, int i, cmp cmp_fn) { + while (true) { + int left = 2 * i + 1, right = 2 * i + 2, smallest = i; + if (left < size && cmp_fn(&obj[smallest], &obj[left])) + smallest = left; + if (right < size && cmp_fn(&obj[smallest], &obj[right])) + smallest = right; + if (smallest == i) + break; + swap(obj, i, smallest); + i = smallest; + } +} + +void queue_push(struct priority_queue *obj, const struct queue_item *item) { + if (obj->queue_size == obj->capacity) { + obj->capacity *= 2; + obj->arr = (struct element *)realloc(obj->arr, obj->capacity * + sizeof(struct element)); + } + obj->arr[obj->queue_size].item = *item; + int i = obj->queue_size; + while (i > 0) { + int parent = (i - 1) / 2; + if (!obj->less_fn(&obj->arr[parent], &obj->arr[i])) + break; + swap(obj->arr, i, parent); + i = parent; + } + obj->queue_size++; +} + +struct queue_item *queue_pop(struct priority_queue *obj) { + if (!obj->queue_size) + return NULL; + swap(obj->arr, 0, obj->queue_size - 1); + struct queue_item *res = &obj->arr[obj->queue_size - 1].item; + obj->queue_size--; + if (obj->queue_size > 0) + down(obj->arr, obj->queue_size, 0, obj->less_fn); + return res; +} + +struct queue_item *queue_top(const struct priority_queue *obj) { + if (!obj->queue_size) + return NULL; + return &obj->arr[0].item; +} + +bool empty(const struct priority_queue *obj) { return !obj->queue_size; } + +int size(const struct priority_queue *obj) { return obj->queue_size; } + +void queue_free(struct priority_queue *obj) { + free(obj->arr); + free(obj); +} + +int minimumPairRemoval(int *nums, int numsSize) { + struct priority_queue *pq = priority_queue_init(item_less); + bool *merged = (bool *)calloc(numsSize, sizeof(bool)); + int decrease_cnt = 0, cnt = 0; + struct node **nodes = + (struct node **)malloc(numsSize * sizeof(struct node *)); + for (int i = 0; i < numsSize; i++) { + nodes[i] = node_init(nums[i], i); + if (i > 0) { + nodes[i - 1]->next = nodes[i]; + nodes[i]->prev = nodes[i - 1]; + } + } + for (int i = 1; i < numsSize; i++) { + struct queue_item item; + item.first = nodes[i - 1]; + item.second = nodes[i]; + item.cost = item.first->val + item.second->val; + item.first_left = item.first->left; + item.second_left = item.second->left; + queue_push(pq, &item); + if (nums[i - 1] > nums[i]) + decrease_cnt++; + } + while (decrease_cnt > 0 && !empty(pq)) { + struct queue_item *item_ptr = queue_pop(pq); + if (!item_ptr) + break; + struct queue_item item = *item_ptr; + if (merged[item.first_left] && merged[item.second_left]) + continue; + struct node *first = item.first, *second = item.second; + long long cost = item.cost; + if (!first || !second) + continue; + if (first->next != second) + continue; + if (first->val + second->val != cost) + continue; + cnt++; + if (first->val > second->val) + decrease_cnt--; + struct node *prev_node = first->prev, *next_node = second->next; + first->next = next_node; + if (next_node) + next_node->prev = first; + second->prev = second->next = NULL; + if (prev_node) { + if (prev_node->val > first->val && prev_node->val <= cost) + decrease_cnt--; + if (prev_node->val <= first->val && prev_node->val > cost) + decrease_cnt++; + struct queue_item new_item; + new_item.first = prev_node; + new_item.second = first; + new_item.cost = prev_node->val + cost; + new_item.first_left = prev_node->left; + new_item.second_left = first->left; + queue_push(pq, &new_item); + } + if (next_node) { + if (second->val > next_node->val && cost <= next_node->val) + decrease_cnt--; + if (second->val <= next_node->val && cost > next_node->val) + decrease_cnt++; + struct queue_item new_item; + new_item.first = first; + new_item.second = next_node; + new_item.cost = cost + next_node->val; + new_item.first_left = first->left; + new_item.second_left = next_node->left; + queue_push(pq, &new_item); + } + first->val = cost; + merged[second->left] = true; + } + for (int i = 0; i < numsSize; i++) + if (!merged[i]) + free(nodes[i]); + free(nodes); + free(merged); + queue_free(pq); + return cnt; +} + +int main() { + int n1[] = {5, 2, 3, 1}, n2[] = {1, 2, 2}; + printf("%d\n", minimumPairRemoval(n1, ARRAY_SIZE(n1))); // expect: 2 + printf("%d\n", minimumPairRemoval(n2, ARRAY_SIZE(n2))); // expect: 0 +} diff --git a/minimum_pair_removal_sort_arr2.py b/minimum_pair_removal_sort_arr2.py @@ -0,0 +1,59 @@ +# 3510. Minimum Pair Removal to Sort Array II +from sortedcontainers import SortedList + +""" +given an array 'nums', you can perfor the following operation any number of +times: select the adjacent pair with the minimum sum in 'nums'. if multiple +such pairs exist, choose the leftmost one. replace the pair with their sum. +return the minimum number of operations needed to make the array +non-decreasing. an array is said to be non-decreasing if each element is +greater than or equal to its previous element. +""" + + +class Solution(object): + def minimumPairRemoval(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + n = (len(nums),) + l = list(range(-1, n - 1)) + r = list(range(1, n + 1)) + self.inversions = sum(nums[i] > nums[i + 1] for i in range(n - 1)) + s = SortedList([nums[i] + nums[i + 1], i] for i in range(n - 1)) + + def add(i): + j = r[i] + if 0 <= i < j < n: + s.add([nums[i] + nums[j], i]) + self.inversions += nums[i] > nums[j] + + def remove(i): + j = r[i] + if 0 <= i < j < n: + s.discard([nums[i] + nums[j], i]) + self.inversions -= nums[i] > nums[j] + + ans = 0 + while self.inversions: + ans += 1 + total, i = s.pop() + j = r[i] + h, k = l[i], r[j] + remove(h) + remove(i) + remove(j) + nums[i] += nums[j] + r[i] = k + if k < n: + l[k] = i + add(h) + add(i) + return ans + + +if __name__ == "__main__": + obj = Solution() + print(obj.minimumPairRemoval(nums=[5, 2, 3, 1])) + print(obj.minimumPairRemoval(nums=[1, 2, 2]))