- Heapify
Given an integer array, heapify it into a min-heap array.
For a heap array A, A[0] is the root of heap, and for each A[i], A[i * 2 + 1] is the left child of A[i] and A[i * 2 + 2] is the right child of A[i].
Example
Example 1
Input : [3,2,1,4,5]
Output : [1,2,3,4,5]
Explanation : return any one of the legitimate heap arrays
Challenge
O(n) time complexity
Clarification
What is heap? What is heapify? What if there is a lot of solutions?
Heap is a data structure, which usually have three methods: push, pop and top. where “push” add a new element the heap, “pop” delete the minimum/maximum element in the heap, “top” return the minimum/maximum element.
Convert an unordered integer array into a heap array. If it is min-heap, for each element A[i], we will get A[i * 2 + 1] >= A[i] and A[i * 2 + 2] >= A[i].
Return any of them.
解法1:经典的O(n)解法。递归版。这个min_heapify()就类似于shiftdown()。
下面这个链接解释了为什么复杂度是O(n)。
https://www.zhihu.com/question/20729324
class Solution {
public:
/*
* @param A: Given an integer array
* @return: nothing
*/
void heapify(vector<int> &A) {
int n = A.size();
for (int i = (n - 2) / 2; i >= 0; --i)
min_heapify(A, i, n);
}
private:
void min_heapify(vector<int> &A, int i, int len) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int smallest = i;
if (left < len && A[left] < A[i]) smallest = left;
if (right < len && A[right] < A[smallest]) smallest = right;
if (smallest != i) {
swap(A[i], A[smallest]);
min_heapify(A, smallest, len);
}
}
};
解法2:迭代版
// it the same as shiftDown()
void min_heapify(vector<int> &A, int i, int len) {
while(2 * i + 1 < len) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int smallest = i;
if (left < len && A[left] < A[i]) smallest = left;
if (right < len && A[right] < A[smallest]) smallest = right;
if (smallest != i) {
swap(A[i], A[smallest]);
i = smallest;
} else {
break;
}
}
}
二刷:
class Solution {
public:
/**
* @param a: Given an integer array
* @return: nothing
*/
void heapify(vector<int> &a) {
int arraySize = a.size();
for (int i = arraySize / 2; i >= 0; i--) {
int smallest = i;
while (smallest < arraySize) {
int orig = smallest;
int left = smallest * 2 + 1;
int right = smallest * 2 + 2;
if (left < arraySize && a[left] < a[smallest]) smallest = left;
if (right < arraySize && a[right] < a[smallest]) smallest = right;
if (smallest == orig) break;
swap(a[smallest], a[orig]);
}
}
return;
}
};
解法3:新建一个堆(数组)。每次往新堆末尾塞一个元素,然后shiftup。
此法较慢,时间复杂度O(nlogn),而且空间复杂度O(n)。
class Solution {
public:
/*
* @param A: Given an integer array
* @return: nothing
*/
void heapify(vector<int> &A) {
int n = A.size();
vector<int> B(n + 1, 0);
for (int i = 1; i <= n; ++i) {
B[i] = A[i - 1];
shiftup(B, i);
}
for (int i = 1; i <= n; ++i) {
A[i - 1] = B[i];
}
}
private:
void shiftup(vector<int> & nums, int pos) {
while(pos > 1) {
if (nums[pos / 2] > nums[pos]) {
swap(nums[pos / 2], nums[pos]);
pos /= 2;
} else {
break;
}
}
}
};
注意:同样的数组nums,但建堆方法不一样,则建的堆也不一样。
下面是借用一个大牛的图。
添加链接描述