【Leetcode】算法總結——堆
2. 堆
- Merge k Sorted Lists
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
。
解法一: 先算兩個鏈表的合併
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int len=lists.length;
ListNode r=null;
if(len==0){
return null;
}
if(len==1){
return lists[0];
}
if(len==2){
return mergeTwoLists(lists[0],lists[1]);
}
for(int i=2;i<len;i++){
r=mergeTwoLists(lists[i-1],lists[i-2]);
r=mergeTwoLists(r,lists[i]);
}
return r;
}
private ListNode mergeTwoLists(ListNode node1,ListNode node2) {
ListNode p=node1;
ListNode q=node2;
ListNode pre=null;//p指針的前一個
if(p==null){
return node2;
}
if(q==null){
return node1;
}
while(p!=null&&q!=null) {
int val1=p.val;
int val2=q.val;
//情況1
if(val1>val2) {
if(pre==null) {
//這種情況是node1的第一個數字node2的第一個數大,需要將node2的第一個數插入到node1的第一個書前面
node1=q;
q=q.next;
node1.next=p;
pre=node1;
}
else {
pre=q;
q=q.next;
pre.next=p;
}
}
else {
if(p.next==null) {
//將q插入到p後面
p.next=q;
break;
}
else {
int val=p.next.val;
if(val>=val2) {
//插進入
ListNode r=p.next;
p.next=q;
q=q.next;
p.next.next=r;
pre=p;
p=p.next;
}
else {
pre=p;
p=p.next;
}
}
}
if(p==null&&q!=null) {
pre.next=q;
}
}
return node1;
}
}
方法二:分治
class Solution {
public ListNode mergeKLists(ListNode[] lists){
if(lists.length == 0)
return null;
if(lists.length == 1)
return lists[0];
if(lists.length == 2){
return mergeTwoLists(lists[0],lists[1]);
}
int mid = lists.length/2;
ListNode[] l1 = new ListNode[mid];
for(int i = 0; i < mid; i++){
l1[i] = lists[i];
}
ListNode[] l2 = new ListNode[lists.length-mid];
for(int i = mid,j=0; i < lists.length; i++,j++){
l2[j] = lists[i];
}
return mergeTwoLists(mergeKLists(l1),mergeKLists(l2));
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
ListNode head = null;
if (l1.val <= l2.val){
head = l1;
head.next = mergeTwoLists(l1.next, l2);
} else {
head = l2;
head.next = mergeTwoLists(l1, l2.next);
}
return head;
}
}
方法三:優先隊列(堆)
/**
* 優先級隊列小頂堆
* @param lists
* @return
*/
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null || lists.length == 0){
return null;
}
PriorityQueue<ListNode> queue = new PriorityQueue<ListNode>(new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val - o2.val;
}
});
for(int i = 0; i < lists.length; i++){
if(lists[i] != null){
queue.offer(lists[i]);
}
}
ListNode head = null;
ListNode cur = null;
while (!queue.isEmpty()){
ListNode node = queue.poll();
if(head == null){
head = node;
cur = head;
}else {
cur.next = node;
cur = cur.next;
}
if(node.next != null){
queue.offer(node.next);
}
}
return head;
}
/**
* 自己寫堆 效率高點
* @param lists
* @return
*/
public ListNode mergeKLists2(ListNode[] lists) {
if(lists == null || lists.length == 0){
return null;
}
MinHeap minHeap = new MinHeap(lists.length);
for(int i = 0; i < lists.length; i++){
if(lists[i] != null){
minHeap.insert(lists[i]);
}
}
ListNode head = null;
ListNode cur = null;
while (!minHeap.isEmpty()){
ListNode node = minHeap.remove();
if(head == null){
head = node;
cur = head;
}else {
cur.next = node;
cur = cur.next;
}
if(node.next != null){
minHeap.insert(node.next);
}
}
return head;
}
/**
* 實現一個簡易的堆看看效果
*/
public class MinHeap{
private ListNode[] lists;
private int index = 1; //索引開始爲1 根據子節點查找父節點只需要除二 不用判斷奇偶
public MinHeap(int len){
lists = new ListNode[len + 1];
}
public ListNode insert(ListNode node){
if(index == lists.length){
return lists[1];
}
int pos = index;
lists[index++] = node;
//堆化
while (pos > 1){
int midPos = pos >> 1;
if(lists[pos].val < lists[midPos].val){
ListNode tmp = lists[midPos];
lists[midPos] = lists[pos];
lists[pos] = tmp;
pos = midPos;
}else {
break;
}
}
return lists[1];
}
public ListNode remove(){
ListNode result = lists[1];
lists[1] = lists[index - 1];
lists[index - 1] = null;
index--;
int pos = 1;
while (pos <= (index - 1)/2){
int minPos = pos;
int minValue = lists[pos].val;
if(lists[pos].val > lists[pos * 2].val){
minPos = pos * 2;
minValue = lists[pos * 2].val;
}
if(index - 1 >= 2 * pos + 1){
//右節點存在
if(minValue > lists[2 * pos + 1].val){
minPos = 2 * pos + 1;
minValue = lists[2 * pos + 1].val;
}
}
//和minPos互換
if(pos != minPos){
ListNode tmp = lists[pos];
lists[pos] = lists[minPos];
lists[minPos] = tmp;
pos = minPos;
}else {
break;
}
}
return result;
}
public boolean isEmpty(){
return index <= 1;
}
}
215.Kth Largest Element in an Array(數組中的第k個最大元素)
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
Example 1:
Input: [3,2,1,5,6,4] and k = 2
Output: 5
Example 2:
Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4
public class Solution215 {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> queue=new PriorityQueue<Integer>(
new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
return o2-o1;
}
}
) ;
int len=nums.length;
for(int i=0;i<len;i++) {
queue.offer(nums[i]);
}
int num=0;
for(int i=0;i<k;i++) {
num=queue.poll();
}
return num;
}
}
- The Skyline Problem(天際線的問題)
A city’s skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Now suppose you are given the locations and height of all the buildings as shown on a cityscape photo (Figure A), write a program to output the skyline formed by these buildings collectively (Figure B).
The geometric information of each building is represented by a triplet of integers [Li, Ri, Hi], where Li and Ri are the x coordinates of the left and right edge of the ith building, respectively, and Hi is its height. It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX, and Ri - Li > 0. You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.
For instance, the dimensions of all buildings in Figure A are recorded as: [ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] .
The output is a list of “key points” (red dots in Figure B) in the format of [ [x1,y1], [x2, y2], [x3, y3], … ] that uniquely defines a skyline. A key point is the left endpoint of a horizontal line segment. Note that the last key point, where the rightmost building ends, is merely used to mark the termination of the skyline, and always has zero height. Also, the ground in between any two adjacent buildings should be considered part of the skyline contour.
For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ].
分析:(下面的小方框就是堆)
public List<List<Integer>> getSkyline(int[][] buildings) {
int[][] arrange=new int[2*buildings.length][2];
List<List<Integer>>ans = new ArrayList<>();
if(buildings.length<=0){
return ans;
}
for(int i=0;i<buildings.length;i++){
//起點高度記爲負數、終點高度記爲正數。
arrange[2*i][0]=buildings[i][0];
arrange[2*i][1]=-buildings[i][2];
arrange[2*i+1][0]=buildings[i][1];
arrange[2*i+1][1]=buildings[i][2];
}
//sort 先按照橫座標進從小到大排序,如果橫座標相對,則按照縱座標(高度)進行從小到大排序
Arrays.sort(arrange,new Comparator<int[]>(){
public int compare(int[] o1,int[] o2){
if(o1[0]!=o2[0]){
return o1[0]-o2[0];
}else{
return o1[1]-o2[1];//這裏區間可以拼接,所以start在前 end 在後
}
}
});
// for height calculation
//使用指定的初始容量創建一個 PriorityQueue,並根據其自然順序來排序其元素(使用 Comparable)。 PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
//默認容量是11
PriorityQueue<Integer> que = new PriorityQueue(11,new Comparator<Integer>(){
public int compare(Integer o1,Integer o2){
return o2-o1;
}
});
int pre=0;
int cp=0;
//sweep
for(int i=0;i<arrange.length;i++){
if(arrange[i][1]<0){
//start
que.offer(-arrange[i][1]);//起點高度入隊
}
else {
que.remove(arrange[i][1]);//終點 從隊列刪除相同高度的一個元素
}//end remove(Object o)方法用於刪除隊列中跟o相等的某一個元素(如果有多個相等,只刪除一個)
int now=0;//初始化高度爲爲0
//now height
if(que.size()>0){
now=que.peek();//取堆頂元素(高度)。
}
// they are different store change point
if(now!=pre){
List<Integer> subans=new ArrayList<>();
cp=arrange[i][0];
pre=now;
subans.add(cp);
subans.add(pre);
ans.add(subans);
}
}
return ans;
}