《程序员代码面试指南》合并两个有序的单链表

题目:

给定两个有序单链表头节点 head1 和 head2 请合并两个有序链表,合并后依然有序,并返回合并后的头节点。

例如:

0->2->3->7->null

1->3->5->7->9->null

合并后的链表为:0->1->2->3->3->5->7->7->9->null

解答:

假设两个链表长度分别为 M 和 N 直接给出时间复杂度为 O(M+N), 额外空间复杂度为 O(1) 的方法,具体过程如下:

1、如果两个链表有其中一个为空,说明无需合并过程,返回另一个链表的头节点即可。

2、比较 head1 和 head2 的值,小的节点也是合并后链表的最小节点,这个节点应该是合并后链表的头节点,记作 head,之后的步骤中哪个链表的头节点值更小要把另一个链表的所有节点都会依次插入到个链表中来。

3、不妨设 head 头节点所在的链表为 链表1 ,另一个链表为 链表2 ,链表1 和 链表2 都从头部开始一起遍历,比较每次遍历到两个节点的值,记作 cur1 和 cur2 然后根据大小不同的关系做出调整,同时用一个变量 pre 表示上次比较时值较小的节点。

例如:链表1 为1->5->6->null,链表2 为 2->3->7->null。

cur1 = 1, cur2 = 2, pre = null。cur1 小于 cur2 不做调整因为此时 cur1 较小,所以令 pre = cur  = 1,然后继续遍历链表1 的下一个节点,也就是节点 5。

cur1 = 5, cur2 = 2, pre = 1, cur2 小于 cur1 让 pre 的 next 指针指向 cur2, cur2 的 next 指针指向 cur1, 这样,cur2便插入到链表1之中了。因为此时的cur2 较小所以令pre = cur2 = 2,然后继续遍历链表2 的下一个节点也就是节点3 ,这一步完成后,链表1变为1->2->5->6->null , 链表2 变为 3->7->null, cur1 = 5, cur2 = 3, pre = 2。

cur1 = 5, cur2 = 3, pre = 2, 此时又是 cur2 较小,与上一步调整类似,这一步完成后,链表1变为 1->2->3->5->6->null,链表2变为7->null,cur1 = 5,cur2 = 7,pre = 3。

cur1 = 5, cur2 = 7, pre = 3, cur1 小于 cur2 不用做调整,因为此时 cur1 较小,所以令 pre = cur1 = 5, 然后继续遍历链表1 的下一个节点,也就是节点6。

cur1 = 6, cur2 = 7, pre = 5, cur1 小于 cur2 不用做调整,因为此时 cur1 较小,所以令 pre = cur1 = 6, 此时已经走到了链表1 的末尾,再往下就结束了,链表1或者链表2 有任何一个结束的话,就进入到步骤4。

4、如果链表1 先走完,此时 cur1 = null, pre 为 链表1 的最后一个节点,那么就把 pre 的 next 指针指向 链表2 的当前节点(cur2),表示把链表2没有遍历完的的部分拼接到最后,如果 链表2 先结束说明 链表2 中的元素全部插入到里面。

public class Node{

            public int value;

            public Node next;

            

            public Node(int data){

                  this.value = data;

            }

      }

      public Node merge(Node head1, Node head2){

            if(head1 == null || head2 == null){

                  return head1 != null ? head1 : head2;

            }

            Node head = head1.value < head2.value ? head1 : head2;

            Node cur1 = head == head1 ? head1 : head2;

            Node cur2 = head == head1 ? head2 : head1;

            Node pre = null;

            Node next = null;

            while(cur1 != null && cur2 != null){

                  if(cur1.value <= cur2.value){

                        pre = cur1;

                        cur1 = cur1.next;

                  }else{

                        next = cur2.next;

                        pre.next = cur2;

                        cur2.next = cur1;

                        pre =cur2;

                        cur2 = next;

                  }

            }

            pre.next = cur1 == null ? cur2 : cur1;

            return head;

      }

参考资料:《程序员面试代码指南》左程云 著

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值