剑指offer-25 合并两个有序链表

目录

思路1

思路2(迭代)

思路3(递归)


题目描述:

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

示例1:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

限制:0 <= 链表长度 <= 1000

 

思路1

新定义一个链表,然后分别从l1和l2中取较小的数插入新链表中。空间复杂度O(n),时间复杂度O(n)

思路2(迭代)

新定义一个节点node,然后分别比较l1和l2的当前节点val大小,如果l1 < l2,则把node.next = l1,l1指向下一个节点,否则把node.next = l2,l2指向下一个节点,然后直到l1和l2都为空之前,不断循环以上过程。代码如下:

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */

function ListNode(val){
     this.val = val
     this.next = null
}
var mergeTwoLists = function (l1, l2) {
    if (!l1 && !l2) return null
    let cur = new ListNode()
    const head = cur
    while(l1 || l2){
        if(!l1){
            cur.next = l2 //***
            return head.next
        }else if(!l2){
            cur.next = l1  //***
            return head.next
        }
        if(l1.val <= l2.val){
            cur.next = l1    //***
            l1 = l1.next
        }else {
            cur.next = l2   //***
            l2 = l2.next
        }
        cur = cur.next
    }
    return head.next  //###
}
let l1 = new ListNode(1)
l1.next = new ListNode(2)
l1.next.next = new ListNode(3)
let l2 = new ListNode(1)
l2.next = new ListNode(3)
l2.next.next = new ListNode(4)
console.log(mergeTwoLists(l1, l2))

 注意!!这里我踩了一个坑,记录下来以免日后忘记

假设现在有一个链表LinkList(1->2->3),有以下代码

var cur = new ListNode()
const head = cur
cur = LinkList
console.log(head.next.val)

这里的head.next.val会输出什么?一开始我认为,应该是2。因为head指向cur,cur又指向了LinkList首节点,cur.next节点是2,那么head.next节点也应该是2.这是错的!!事实上,这里会输出undefined。为什么呢?

我们来分析一下这段代码的前三句话

1.定义一个有ListNode里属性的cur节点,为它分配空间,作图如下:

2.定义一个常量head,把cur里存放的堆区的地址给它

3.cur指向LinkList节点,即cur里存放LinkList堆区地址 

坑出现了!!可以由图中看到,head仍旧指向原来没有被赋值的空间,而cur指向了新的空间。所以head.next会等于null,此时head与cur不再相等了。如果我们还想让head与cur指向同一个空间,并且head也能取到LinkList里的值该怎么办呢?

很简单,让cur.next 指向LinkLisk节点!

如果我们把上面第3行cur = LinkList 改为cur.next = LinkList,那么此时堆和栈是什么样的?

要想获取0x456里的val,只要用head.next就好了

综上所述,这就是为什么在迭代代码里***处,要用cur.next去存l1,并且在最后的时候也返回的是head.next

迭代法时间复杂度O(n) ,空间复杂度O(1)

思路3(递归)

把问题细分,考虑两个链表合并,可以转换为两个链表的子链表合并。如果l1.val < l2.val,说明l1当前节点可以被保留,接下来要合并的两个链表就是l1.next和l2,临界条件是l1为空(l1已经遍历完)或l2为空(l2已经遍历完)。以此写出递归方法。

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var mergeTwoLists = function (l1, l2) {//递归
    if(!l1) return l2
    if(!l2) return l1
    while(l1 || l2){
        if(l1.val < l2.val){
            l1.next = mergeTwoLists(l1.next, l2)
            return l1
        }else{
            l2.next = mergeTwoLists(l1, l2.next)
            return l2
        }
    }
}

递归法时间复杂度O(n),空间复杂度O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值