Problem Statement
Given an array of integers nums
, convert it in-place into a min-heap
.
A binary min-heap is a complete binary tree where the key at the root is the minimum among all keys present in a binary min-heap and the same property is recursively true for all nodes in a Binary Tree.
Examples
Example 1:
Input: nums = [6, 5, 2, 7, 1, 7]
Output: [1, 5, 2, 7, 6, 7]
Explanation: nums[0] <= nums[1], nums[2]
nums[1] <= nums[3], nums[4]
nums[2] <= nums[5]
Example 2:
Input: nums = [2, 3, 4, 1, 7, 3, 9, 4, 6]
Output: [1, 2, 3, 3, 7, 4, 9, 4, 6]
Explanation: nums[0] <= nums[1], nums[2]
nums[1] <= nums[3], nums[4]
nums[2] <= nums[5], nums[6]
nums[3] <= nums[7], nums[8]
Different Approaches
1️⃣ Heap
Intuition:
To build a min-heap from the given array, the goal must be to individually heapify each non-leaf node so that it starts following the min-heap property. Once, all the non-leaf nodes are heapified, the resultant array will be a min-heap.
Heapify down is preferred in this case because the property violations occur between a node and its children when building a heap from an unsorted array. Fixing the violations downwards ensures that the entire subtree rooted at the node satisfies the min-heap property efficiently.
Note that the leaf nodes don't have any children i.e., they already follow the min-heap property. Thus, the heapifying down process is performed only for the leaf nodes.
Approach:
- Start from the last non-leaf node in the array, as leaf nodes are already min-heaps.
- Perform a downward heapify operation on each node, ensuring the heap property (the parent is smaller than its children) is maintained.
- The heapify operation compares the current node with its children, swaps it with the smallest child if necessary, and recursively heapifies the affected subtree.
- Once the iterations are over, the array represents a min-heap.
Code:
#include <bits/stdc++.h>
using namespace std;
class Solution {
private:
// Function to recursively heapify the array downwards
void heapifyDown(vector<int> &arr, int ind) {
int n = arr.size(); // Size of the array
// Index of largest element
int largest_Ind = ind;
// Indices of the left and right children
int leftChild_Ind = 2*ind + 1, rightChild_Ind = 2*ind + 2;
// If the left child holds larger value, update the largest index
if(leftChild_Ind < n && arr[leftChild_Ind] < arr[largest_Ind])
largest_Ind = leftChild_Ind;
// If the right child holds larger value, update the largest index
if(rightChild_Ind < n && arr[rightChild_Ind] < arr[largest_Ind])
largest_Ind = rightChild_Ind;
// If the largest element index is updated
if(largest_Ind != ind) {
// Swap the largest element with the current index
swap(arr[largest_Ind] , arr[ind]);
// Recursively heapify the lower subtree
heapifyDown(arr, largest_Ind);
}
return;
}
public:
// Function to convert given array into a min-heap
void buildMinHeap(vector<int> &nums) {
int n = nums.size();
// Iterate backwards on the non-leaf nodes
for(int i = n/2 - 1; i >= 0; i--) {
// Heapify each node downwards
heapifyDown(nums, i);
}
return;
}
};
// Driver code
int main() {
vector<int> nums = {6, 5, 2, 7, 1, 7};
// Input array
cout << "Input array: ";
for(int it : nums) cout << it << " ";
// Creating an object of the Solution class
Solution sol;
// Function call to convert the given array into a min-heap
sol.buildMinHeap(nums);
// Output array
cout << "\nMin-heap array: ";
for(int it : nums) cout << it << " ";
return 0;
}
Complexity Analysis:
- Time Complexity:
O(N)
(where N is the number of elements in the array)- Each heapify call has a time complexity of O(h), where h is the height of the subtree, h = log(N). The heapify operation is performed for approximately N/2 nnon-leaf nodes.
- Due the variable height for all the subtrees, summing the total work done for all the nodes results in an overall time complexity of O(N) for building a heap.
- Space Complexity:
O(log2N)
- The recursive calls during heapify require stack space proportional to the height of the heap which will be of the order of log(N) in the worst-case.