leetcode 合并两个有序链表(每日计划)

78 阅读1分钟

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

 

示例:

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

我的算法实现:

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
export var mergeTwoLists = function (l1, l2) {
  if (!l1) return l2;
  else if (!l2) return l1;
  let head = l1.val > l2.val ? l2 : l1;
  let node = head;
  for (let p = l1, q = l2; p !== null || q !== null; ) {
    if (p === null) {
      node.next = q;
      return head;
    } else if (q === null) {
      node.next = p;
      return head;
    } else if (p.val > q.val) {
      let temp1 = q.next;
      node.next = q;
      node = q;
      q.next = null;
      q = temp1;
    } else {
      let temp1 = p.next;
      node.next = p;
      node = p;
      p.next = null;
      p = temp1;
    }
  }
  node.next = null;
  return head;
};

我的实现代码太多了,虽然显示的是超过了百分之八十的人,但我不满意。

官网的实现非常好,我特别喜欢的是递归的实现,这次同样的,我也想到了递归,可是想了好久还是没想到怎么实现这个递归: 合并两个有序链表

写递归的具体思路需要总结归纳,不然下次还是无法实现。

先看看这次官网的递归方法:

var mergeTwoLists = function(l1, l2) {
    if (l1 === null) {
        return l2;
    } else if (l2 === null) {
        return l1;
    } else if (l1.val < l2.val) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
};

首先定义一下函数的含义:给定两个节点,返回两个节点的值小的那个节点。那么首先考虑特殊情况:

  1. 如果其中一个为空,那么直接返回另一个节点;
  2. 如果两个都不为空,那么看前一个节点小的情况,如果前一个节点的确小于,那么返回前一个;
  3. 如果后面个节点大,那么就返回后面的那个节点。

所以函数应该是下面的样子:

var mergeTwoLists = function(l1, l2) {
    if (l1 === null) {
        return l2;
    } else if (l2 === null) {
        return l1;
    } else if (l1.val < l2.val) {
        return l1;
    } else {
        return l2;
    }
};

现在再扩展到如果是一组数据,除了返回最小的那个节点,还需要将当前的节点的下一个节点指向下一个最小的节点,也就是下面这样:

var mergeTwoLists = function(l1, l2) {
    if (l1 === null) {
        return l2;
    } else if (l2 === null) {
        return l1;
    } else if (l1.val < l2.val) {
    	l1.next = /*比较下面两个节点*/
        return l1;
    } else {
    	l2.next = /*比较下面两个节点*/
        return l2;
    }
};

由于当前函数的功能正好满足得到两个节点的最小那个节点,所以可以直接调用自己。于是就得到了前面的递归函数。我们使用这个方法来看昨天官方的递归函数。

// 链表的反转
var reverseList = function (head) {
  if (!head || !head.next) {
    return head;
  }
  let node = reverseList(head.next);
  head.next.next = head;
  head.next = null;
  return node;
};
  1. 函数的功能是将传入节点的下一个节点指向传入的节点,并让传入节点指向空,也就是实现反转,并返回新的头节点;
  2. 首先判断极端的情况,如果当前传入的节点和传入节点的下一个节点为空,那么直接返回传入的节点;
  3. 如果满足上面的情况,那么传入节点的下下个节点等于当前节点:head->next->next = head
  4. 以此类推就可以得到这样的函数,只不过实现起来还是麻烦的,还是需要多练习。

来源:力扣(LeetCode)