(力扣23)合并排序链表,采用分治思想

题目:

给定一个链表数组,每个链表都已经按升序排列。
请将所有链表合并到一个升序链表中,返回合并后的链表。

(力扣23)合并排序链表,采用分治思想_第1张图片

什么是归并排序?

(力扣23)合并排序链表,采用分治思想_第2张图片

  • 归并排序的时间复杂度仅次于快排,归并排序算法每次将序列折半分组,共需要logn轮,因此归并排序算法的时间复杂度是O(nlogn)

  • 归并排序算法排序过程中需要额外的一个序列去存储排序后的结果,所占空间是n,因此空间复杂度为O(n)

  • 归并排序算法在排序过程中,相同元素的前后顺序并没有改变,所以归并排序是一种稳定排序算法

public class MergeSort {
    public static void mergeSort(int[] arr, int low, int high) {
        if (low < high) {
            int mid = (low + high) / 2;
            mergeSort(arr, low, mid);
            mergeSort(arr, mid + 1, high);
            merge(arr, low, mid, high);
        }
    }

    public static void merge(int[] arr, int low, int mid, int high) {
        int[] temp = new int[high - low + 1];
        int i = low;
        int j = mid + 1;
        int k = 0;
        while (i <= mid && j <= high) {
            if (arr[i] < arr[j]) {
                temp[k++] = arr[i++];
            } else {
                temp[k++] = arr[j++];
            }
        }
        while (i <= mid) {
            temp[k++] = arr[i++];
        }
        while (j <= high) {
            temp[k++] = arr[j++];
        }

解题思路:

这道题可以采用多种方法,常见的可以是堆排序,这里我用分治的思想,二路归并,进行链表的合并。

图片搬运的力扣的地址

(力扣23)合并排序链表,采用分治思想_第3张图片
我们可以在排序的时候,尽量把数组排在靠左的位置,这样,每次归并就可以迅速找到所需要的数组,遍历的时候方便很多。

(力扣23)合并排序链表,采用分治思想_第4张图片

bing感觉比我聪明的样子(QAQ)

java实现代码:

class Solution { 
    //定义一个方法,用于合并k个有序链表
    public ListNode mergeKLists(ListNode[] lists) { 
        //如果输入的数组为空或长度为0,返回空
        if(lists == null || lists.length == 0){ 
            return null; 
        } 
        //使用循环,每次将相邻的两个链表合并,直到只剩下一个链表
        for(int i = 0; i < lists.length; i++){ 
            for(int j = 0; j+(int)Math.pow(2,i) < lists.length; j+=2 * (int)Math.pow(2,i)){ 
                mearge(lists,j,j+(int)Math.pow(2,i)); 
            } 
        } 
        //返回最终合并后的链表
        return lists[0]; 
    } 
    //定义一个辅助方法,用于合并两个有序链表
    public void mearge(ListNode[]lists,int one, int two){ 
        //定义两个临时节点,分别指向两个链表的头节点
        ListNode tempNode0 = lists[one]; 
        ListNode tempNode1 = lists[two]; 
        //如果第一个链表为空,直接将第二个链表赋值给第一个链表,并返回
        if(tempNode0 == null){ 
            lists[one] = lists[two]; 
            return; 
        //如果第二个链表为空,直接返回
        }else if(tempNode1 == null){ 
            return; 
        } 
        //比较两个链表的头节点的值,将较小的值作为第一个链表的头节点,并将对应的临时节点后移一位
        if(tempNode0.val > tempNode1.val){ 
            lists[one] = tempNode1; 
            tempNode1 = tempNode1.next; 
        }else { 
            tempNode0 = tempNode0.next; 
        } 
        //下面进行二路归并
        //定义一个新的临时节点,指向第一个链表的头节点
        ListNode tempNode = lists[one]; 
        //当两个临时节点都不为空时,循环比较它们的值,并将较小的值连接到新的临时节点后面,并将对应的临时节点后移一位
        while(tempNode0 != null || tempNode1 != null){ 
            if(tempNode0 == null){ //如果第一个临时节点为空,将第二个临时节点连接到新的临时节点后面,并跳出循环
                tempNode.next = tempNode1; 
                break; 
            }else if(tempNode1 == null){ //如果第二个临时节点为空,将第一个临时节点连接到新的临时节点后面,并跳出循环
                tempNode.next = tempNode0; 
                break; 
            }else{ //如果两个临时节点都不为空,比较它们的值,并将较小的值连接到新的临时节点后面,并将对应的临时节点后移一位,并将新的临时节点后移一位
                if(tempNode0.val < tempNode1.val){ 
                    tempNode.next = tempNode0; 
                    tempNode0 = tempNode0.next; 
                    tempNode = tempNode.next; 
                    tempNode.next = null; //将新的临时节点的下一个节点置空,避免产生循环引用
                }else{ 
                    tempNode.next = tempNode1; 
                    tempNode = tempNode.next; 
                    tempNode1 = tempNode1.next; 
                    tempNode.next = null; //同理
                } 
            } 
        }

你可能感兴趣的:(链表,leetcode,算法)