【路飞】-算法练习——复杂链表的复制、两数相加 II

168 阅读3分钟

445. 两数相加 II

题目:】 给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

示例 1:

image.png

输入: l1 = [7,2,4,3], l2 = [5,6,4]
输出: [7,8,0,7]

示例2:

输入: l1 = [2,4,3], l2 = [5,6,4]
输出: [8,0,7]

示例3:

输入: l1 = [0], l2 = [0]
输出: [0]

提示:

  • 链表的长度范围为 [1, 100]
  • 0 <= node.val <= 9
  • 输入数据保证链表代表的数字无前导 0

题解:】 计算两个链表形式的数组之和,我们是需要从链表尾部开始计算的,因此可以有以下思路:

  • 反转两个初始链表 l1 => rl1l2 => rl2
  • 在反转链表的同时获取两个链表的长度level1level2,两个链表长度不一定相同,因此循环次数为最长链表的长度
  • 计算的和值newListNode可保存在一个新链表,初始值为0,next为level1level2同级值的和的个位
  • 计算和值需要需要将level1level2从链表开始处开始逐级计算,并向下一级进行进位计算,最后一级为默认值0
  • 将得到的newListNode进行反转,并去除首位的0,得到最终解

代码:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

function addTwoNumbers(l1: ListNode | null, l2: ListNode | null): ListNode | null {

    let {level: level1, head: rl1} = reserve(l1)
    let {level: level2, head: rl2} = reserve(l2)

    let level: number = Math.max(level1, level2)
    let newListNode: ListNode = new ListNode(0, null), cur:ListNode = newListNode

    while(level){

        let val1: number = rl1 && rl1.val || 0
        let val2: number = rl2 && rl2.val || 0
        let nVal: number = cur.val || 0

        let n1: number = (nVal + val1 + val2) % 10
        let n2: number = Math.floor((nVal + val1 + val2) / 10)

        cur.val = n1
        cur.next = new ListNode(n2, null)
        cur = cur.next

        rl1 = (rl1 && rl1.next) || null
        rl2 = (rl2 && rl2.next) || null

        level--
    }
    let {head: ret} = reserve(newListNode)
    if(ret.val === 0) ret = ret.next
    
    return ret
};

function reserve(head: ListNode): {level: number, head: ListNode | null}{
  if(!head) return {level: 0, head: null}

  let pre = null, cur: ListNode  = head, con = 0
  while(cur){
      let next: ListNode | null = cur.next

      cur.next = pre
      pre = cur
      cur = next
      con++
  }
  return {level: con, head: pre}
}

剑指 Offer 35. 复杂链表的复制

题目:】 请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

示例 1:

image.png

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

示例2:

image.png

输入: head = [[1,1],[2,1]]
输出: [[1,1],[2,1]]

示例3:

image.png

输入: head = [[3,null],[3,0],[3,null]]
输出: [[3,null],[3,0],[3,null]]

示例 4:

输入: head = []
输出: []
解释: 给定的链表为空(空指针),因此返回 null。

提示:

  • -10000 <= Node.val <= 10000
  • Node.random 为空(null)或指向链表中的节点。
  • 节点数目不超过 1000 。

题解:】 基本思路:

  1. 遍历整个链表,复制每个节点及其值,然后拼接到原节点的后面,形成一个新的链表 x=>y=>z ==> x=>x1=>y=>y1=>z=>z1

  2. 找到一个克隆节点,修正random,将克隆节点的random指向克隆节点,克隆节点的random原节点的random的next

  3. 拆分链表分成原链表和克隆链表

代码:

/**
 * // Definition for a Node.
 * function Node(val, next, random) {
 *    this.val = val;
 *    this.next = next;
 *    this.random = random;
 * };
 */

/**
 * @param {Node} head
 * @return {Node}
 */
 var copyRandomList = function(head) {
  if(!head) return null
  // 创建两个指针
  let cur = head, cur1
  // 遍历整个链表,复制每个节点及其值,然后拼接到原节点的后面
  while(cur){
      cur1 = new Node(cur.val, cur.next, cur.random)
      cur.next = cur1
      cur = cur1.next
  }
  // 找到一个克隆节点,修正random,将克隆节点的random指向克隆节点
  cur = head.next
  while(cur){
      cur.random && (cur.random = cur.random.next)
      cur = cur.next && cur.next.next
  }
  // 拆分链表分成原链表和克隆链表
  cur = cur1 = head.next
  while(cur1.next){
      head.next = head.next.next
      cur1.next = cur1.next.next
      head = head.next
      cur1 = cur1.next
  }
  head.next = null
  return cur
};