Reduction Operations using Priority Queue

This is my 859th solved problem on Leetcode. Took me several attempts before getting a working solution. The problem asks to reduce an array to the same element using pre-defined operations. From the get-go it looked to me like a problem that could be solved using a Priority Queue. Initial attempts failed since I was simulating one operation at a time. When I realized that one can simulate multiple operations at a time, it finally worked. Code is below, cheers, ACC.

Reduction Operations to Make the Array Elements Equal - LeetCode

1887. Reduction Operations to Make the Array Elements Equal
Medium

Given an integer array nums, your goal is to make all elements in nums equal. To complete one operation, follow these steps:

  1. Find the largest value in nums. Let its index be i (0-indexed) and its value be largest. If there are multiple elements with the largest value, pick the smallest i.
  2. Find the next largest value in nums strictly smaller than largest. Let its value be nextLargest.
  3. Reduce nums[i] to nextLargest.

Return the number of operations to make all elements in nums equal.

 

Example 1:

Input: nums = [5,1,3]
Output: 3
Explanation: It takes 3 operations to make all elements in nums equal:
1. largest = 5 at index 0. nextLargest = 3. Reduce nums[0] to 3. nums = [3,1,3].
2. largest = 3 at index 0. nextLargest = 1. Reduce nums[0] to 1. nums = [1,1,3].
3. largest = 3 at index 2. nextLargest = 1. Reduce nums[2] to 1. nums = [1,1,1].

Example 2:

Input: nums = [1,1,1]
Output: 0
Explanation: All elements in nums are already equal.

Example 3:

Input: nums = [1,1,2,2,3]
Output: 4
Explanation: It takes 4 operations to make all elements in nums equal:
1. largest = 3 at index 4. nextLargest = 2. Reduce nums[4] to 2. nums = [1,1,2,2,2].
2. largest = 2 at index 2. nextLargest = 1. Reduce nums[2] to 1. nums = [1,1,1,2,2].
3. largest = 2 at index 3. nextLargest = 1. Reduce nums[3] to 1. nums = [1,1,1,1,2].
4. largest = 2 at index 4. nextLargest = 1. Reduce nums[4] to 1. nums = [1,1,1,1,1].

 

Constraints:

  • 1 <= nums.length <= 5 * 104
  • 1 <= nums[i] <= 5 * 104
Accepted
7,998
Submissions
13,888





public class Solution {
    public int ReductionOperations(int[] nums)
    {
        Hashtable htCount = new Hashtable();

        foreach (int n in nums)
        {
            if (!htCount.ContainsKey(n)) htCount.Add(n, 0);
            htCount[n] = (int)htCount[n] + 1;
        }

        PriorityQueue pQueue = new PriorityQueue(false);

        foreach (int value in htCount.Keys)
        {
            int count = (int)htCount[value];
            pQueue.Enqueue(count, value);
        }

        int nSteps = 0;
        while (pQueue.Count > 1)
        {
            double temp = 0;

            int valueLargest = 0;
            int countLargest = (int)pQueue.Dequeue(out temp);
            valueLargest = (int)temp;

            int valueSecondLargest = 0;
            int countSecondLargest = (int)pQueue.Dequeue(out temp);
            valueSecondLargest = (int)temp;

            nSteps += countLargest;
            countSecondLargest += countLargest;
            pQueue.Enqueue(countSecondLargest, valueSecondLargest);
        }

        return nSteps;
    }
}

public class PriorityQueue
{
    public struct HeapEntry
    {
        private object item;
        private double priority;
        public HeapEntry(object item, double priority)
        {
            this.item = item;
            this.priority = priority;
        }
        public object Item
        {
            get
            {
                return item;
            }
        }
        public double Priority
        {
            get
            {
                return priority;
            }
        }
    }

    private bool ascend;
    private int count;
    private int capacity;
    private HeapEntry[] heap;

    public int Count
    {
        get
        {
            return this.count;
        }
    }

    public PriorityQueue(bool ascend)
    {
        capacity = 1000000;
        heap = new HeapEntry[capacity];
        this.ascend = ascend;
    }

    public object Dequeue(out double priority)
    {
        priority = heap[0].Priority;
        object result = heap[0].Item;
        count--;
        trickleDown(0, heap[count]);
        return result;
    }

    public object Peak(/*out double priority*/)
    {
        //priority = heap[0].Priority;
        object result = heap[0].Item;
        return result;
    }

    public void Enqueue(object item, double priority)
    {
        count++;
        bubbleUp(count - 1, new HeapEntry(item, priority));
    }

    private void bubbleUp(int index, HeapEntry he)
    {
        int parent = (index - 1) / 2;
        // note: (index > 0) means there is a parent
        if (this.ascend)
        {
            while ((index > 0) && (heap[parent].Priority > he.Priority))
            {
                heap[index] = heap[parent];
                index = parent;
                parent = (index - 1) / 2;
            }
            heap[index] = he;
        }
        else
        {
            while ((index > 0) && (heap[parent].Priority < he.Priority))
            {
                heap[index] = heap[parent];
                index = parent;
                parent = (index - 1) / 2;
            }
            heap[index] = he;
        }
    }

    private void trickleDown(int index, HeapEntry he)
    {
        int child = (index * 2) + 1;
        while (child < count)
        {
            if (this.ascend)
            {
                if (((child + 1) < count) &&
                    (heap[child].Priority > heap[child + 1].Priority))
                {
                    child++;
                }
            }
            else
            {
                if (((child + 1) < count) &&
                    (heap[child].Priority < heap[child + 1].Priority))
                {
                    child++;
                }
            }
            heap[index] = heap[child];
            index = child;
            child = (index * 2) + 1;
        }
        bubbleUp(index, he);
    }
}

Comments

Popular posts from this blog

Advent of Code - Day 6, 2024: BFS and FSM

Golang vs. C#: performance characteristics (simple case study)

Advent of Code - Day 7, 2024: Backtracking and Eval