链表的合并

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


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

分析:有两个链表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)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值