链表的合并

Posted 爱coding的卖油翁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表的合并相关的知识,希望对你有一定的参考价值。

对于链表的操作,还有几个是比较常用的,比如:将两个已排序的链表合并成一个长的排序链表;在已排序的链表中插入一个元素;对一个无序链表根据给定的某个值,进行分区。现在,我们就来看看这三个问题。


问题:如何将两个排序链表合并成一个长排序链表

分析:有两个链表curr1,curr2,构建一个新的链表 dummy,遍历 curr1 和 curr2,比较 curr1 和 curr2,谁小移动谁,用 curr 来记录需要移动的位置。循环结束,curr1 和 curr2 有一个尾指针没有指向,需要在把尾指针指向 dummy 的结尾的,最后返回 dummy 的下一个节点即可。

/**
 * 合并链表
 */
public ListNode merge(ListNode first, ListNode second) 
    ListNode curr1 = first;
    ListNode curr2 = second;
    ListNode dummy = new ListNode(0);
    ListNode curr = dummy;
    while (curr1 != null && curr2 != null) 
        if (curr1.value >= curr2.value) 
            curr.next = curr2;
            curr2 = curr2.next;
            curr = curr.next;
         else 
            curr.next = curr1;
            curr1 = curr1.next;
            curr = curr.next;
        
    
    if (curr1 != null) 
        curr.next = curr1;
     else 
        curr.next = curr2;
    
    return dummy.next;

时间复杂度 O(m+n)
空间复杂度 O(1)


问题:在链表中插入一个节点

分析:遍历链表,取出每个节点与目标值 target 进行比较,小于 target,记录节点 prev,当前节点 curr 往后移动一位。遍历结束,把 target 插入 prev 后面,在 target 插入 curr。

public ListNode insert(ListNode head, int target) 
    if (head == null || head.value >= target) 
        ListNode newHead = new ListNode(target);
        newHead.next = head;
        return newHead;
    
    ListNode prev = null;
    ListNode curr = head;
    while (curr != null) 
        if (curr.value < target) 
            prev = curr;
            curr = curr.next;
         else 
            break;
        
    
    ListNode newHead = new ListNode(target);
    prev.next = newHead;
    newHead.next = curr;
    return head;

问题:如何分区一个链表

描述:给定一个链表和一个目标值x,将其划分为所有小于x的节点放在左边,大于x的节点放在右边,并且保证两个分区中每个节点的原始相对顺序。

例子:
输入:1 6 3 2 5 2 目标值:4
输出:1 3 2 2 6 5

分析:构建两个链表 dummy1,dummy2,遍历链表,比较当前节点 curr 与目标值 target,小于的话放到 dummy1 中,大于的话放到 dummy2 中,最后把 dummy1 和 dummy2 相接。注意,要把 dummy2 的尾节点置空,否则,就是一个环状。

public static void main(String[] args) 
    ListNode head = new ListNode(1);
    ListNode node2 = new ListNode(6);
    ListNode node3 = new ListNode(3);
    ListNode node4 = new ListNode(2);
    ListNode node5 = new ListNode(5);
    ListNode node6 = new ListNode(2);
    head.next = node2;
    node2.next = node3;
    node3.next = node4;
    node4.next = node5;
    node5.next = node6;

    ListNode newHead = new PartitionLinked().partition(head, 4);
    while (newHead.next != null) 
        System.out.print(newHead.value + " ");
        newHead = newHead.next;
    
    System.out.print(newHead.value + " ");



public ListNode partition(ListNode head, int target) 
    if (head == null) return null;
    ListNode dummy1 = new ListNode(0);
    ListNode dummy2 = new ListNode(0);
    ListNode curr1 = dummy1;
    ListNode curr2 = dummy2;
    ListNode curr = head;
    while (curr != null) 
        if (curr.value < target) 
            curr1.next = curr;
            curr = curr.next;
            curr1 = curr1.next;
         else 
            curr2.next = curr;
            curr = curr.next;
            curr2 = curr2.next;
        
    
    // dummy1: 0-->1-->3-->2-->2-->null
    //                         curr1

    // dummy2: 0-->6-->5-->2-->null
    //                 curr2

    // result: >1-->3-->2-->2-->6-->5-->null

    curr1.next = dummy2.next;
    // dummy1: 0-->1-->3-->2-->2-->6-->5-->2-->null
    //                                 curr2

    curr2.next = null;
    // dummy1: 0-->1-->3-->2-->2-->6-->5-->null

    return dummy1.next;

时间复杂度 O(n)
空间复杂度 O(1)

以上是关于链表的合并的主要内容,如果未能解决你的问题,请参考以下文章

K个排序链表的合并(Hard)

链表的基本操作 三(增序链表的合并,无序链表的交集)

两个有序链表的合并

合并两个有序链表【递归、迭代】

两个排序链表的合并(Easy)

leetcode 链表的合并和分割两道题