合并K个有序链表O(N lgK)

问题:在O(N lgK) 时间内合并K个有序链表, 这里N指的是K个链表中所有的元素个数。

这题的思路如下:

1 ) 在每一个链表中取出第一个值,然后把它们放在一个大小为K的数组里,然后把这个数组当成heap,然后把该堆建成最小堆。O(K)

2 )取出堆中的最小值(也是数组的第一个值),然后把该最小值所处的链表的下一个值放在数组的第一个位置。如果链表中有一个已经为空(元素已经都被取出),则改变heap的大小。然后,执行MIN-HEAPIFY操作,O(lg K).

3 ) 不断的重复步骤二,直到所有的链表都为空。

class ListNode {
	int val;
	ListNode next;
	ListNode(int x) {
		val = x;
		next = null;
	}
}
public class Solution {
	public static void main(String[] args) {
		ListNode n1 = new ListNode(1);
		ListNode n7 = new ListNode(2);
		ListNode n9 = new ListNode(2);
		ListNode n2 = new ListNode(1);
		ListNode n4 = new ListNode(1);
		ListNode n8 = new ListNode(2);
		ArrayList<ListNode> lists = new ArrayList<ListNode>();	
		n1.next = n7;
		n7.next = n9;
		n2.next = n4;
		n4.next = n8;
		lists.add(n1);
		lists.add(n2);
		Solution test = new Solution();
		ListNode head = test.mergeKLists(lists);
		while(head != null) {
			System.out.println(head.val);
			head = head.next;
		}
	}
    public ListNode mergeKLists(ArrayList<ListNode> lists) {
        ArrayList<ListNode> heap = new ArrayList<ListNode>();
        for (int i = 0; i < lists.size(); i++) {
            if (lists.get(i) != null) {
                heap.add(lists.get(i));
            }
        }
        ListNode head = null;
        ListNode current = null;
        if (heap.size() == 0) return null;
        minHeapify(heap);
        while (heap.size() != 0) {
            if (head == null) {
                head = heap.get(0);
                current = heap.get(0);
            } else {
                current.next = heap.get(0);
                current = current.next;
            }
            if (current.next != null) {
                heap.set(0, current.next);
                heapify(heap, 0);
            } else {
                heap.remove(0);
                minHeapify(heap);
            }
        }
        return head;
    }  
    public void heapify(ArrayList<ListNode> heap, int index) {
        int position = index;
        int left = 2 * index + 1;
        int right = 2 * index + 2;  
        if(left < heap.size() && heap.get(left).val < heap.get(position).val) {
            position = left;
        } 
        if(right < heap.size() && heap.get(right).val < heap.get(position).val) {
            position = right;
        }
        if (position != index) {
            ListNode temp = heap.get(position);
            heap.set(position, heap.get(index));
            heap.set(index, temp);
            heapify(heap, position);
        }
    }
    public void minHeapify(ArrayList<ListNode> heap) {
        for (int i = heap.size()/2 - 1; i >= 0; i--) {
            heapify(heap, i);
        }
    }
}

合并两个有序链表:

一般有两种方法:递归和非递归。尤其注意两个链表都为空,和其中一个为空时的情况。只需要O(1)的空间。时间复杂度为O(max(len1, len2))。

1、递归:设两个链表的头结点分别是head1,和head2。如果head1为空,直接返回head2;同理如果head2为空,直接返回head1。否则,如果head1链表的第一个数据小于head2链表的第一个数据,那么直接继续递归 head1->next和head2这两个链表,并把返回值赋给head1->next。
Node * listMerge(Node *head1, Node * head2)
{
 Node * node = NULL;
 if(head1 == NULL)
  return head2;
 if(head2 == NULL)
  return head1;
 if(head1->data < head2->data)
 {
  node = head1;
  head1 = head1->next;
 }
 else
 {
  node = head2;
  head2 = head2->next;
 }
 node->next = listMerge(head1, head2);
 return node;
}
2:非递归的:分别用指针head1,head2来遍历两个链表,如果当前head1指向的数据小于head2指向的数据,则将head1指向的结点归入合并后的链表中,否则,将head2指向的结点归入合并后的链表中。如果有一个链表遍历结束,则把未结束的链表连接到合并后的链表尾部。
// 合并两个有序链表
ListNode * MergeSortedList(ListNode * pHead1, ListNode * pHead2)
{
	if(pHead1 == NULL)
		return pHead2;
	if(pHead2 == NULL)
		return pHead1;
	ListNode * pHeadMerged = NULL;
	if(pHead1->m_nKey < pHead2->m_nKey)
	{
		pHeadMerged = pHead1;
		pHeadMerged->m_pNext = NULL;
		pHead1 = pHead1->m_pNext;
	}
	else
	{
		pHeadMerged = pHead2;
		pHeadMerged->m_pNext = NULL;
		pHead2 = pHead2->m_pNext;
	}
	ListNode * pTemp = pHeadMerged;
	while(pHead1 != NULL && pHead2 != NULL)
	{
		if(pHead1->m_nKey < pHead2->m_nKey)
		{
			pTemp->m_pNext = pHead1;
			pHead1 = pHead1->m_pNext;
			pTemp = pTemp->m_pNext;
			pTemp->m_pNext = NULL;
		}
		else
		{
			pTemp->m_pNext = pHead2;
			pHead2 = pHead2->m_pNext;
			pTemp = pTemp->m_pNext;
			pTemp->m_pNext = NULL;
		}
	}
	if(pHead1 != NULL)
		pTemp->m_pNext = pHead1;
	else if(pHead2 != NULL)
		pTemp->m_pNext = pHead2;
	return pHeadMerged;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值