6 分钟阅读

困难算法题,按格式合并两个链表,使用 JavaScript 语言编写

题目

给定两个链表:

  • $L_{1} ​= a_{1}​ → a_{2} ​→ ⋯ → a_{n-1} ​→ a_{n}$​
  • $L_{2}​ = b_{1}​ → b_{2} ​→ ⋯ → b_{m-1} ​→ b_{m}$​,其中 n ≥ 2m

需要将较短的链表 $L_{2}$ ​反转并合并到较长的链表 $L_{1}$ ​中,使得合并后的链表如下形式:$a_{1}​ → a_{2} ​→ b_{m} ​→ a_{3}​ → a_{4} ​→ b_{m-1} → … $​

合并规则:在长链表中每隔两个元素,将短链表中的元素倒序插入

例如:给定一个较长链表 $1 → 2 → 3 → 4 → 5$ ,另外一个较短链表 6 → 7,需要输出 $1 → 2 → 7 → 3 → 4 → 6 → 5$

输入格式

第一行包含两个链表的第一个节点地址(不确定哪个链表更长),以及两个链表的总节点数 N(≤100000)。节点地址用一个 5 位非负整数表示(可能有前导 0),空地址 NULL 用 −1 表示

例如:00100 01000 7。其中 00100 表示第一个链表的首个节点地址,01000 表示第二个链表的首个节点地址,7 表示两个链表的总节点数。

接下来 N 行,每行描述一个节点的信息,格式为 Address Data Next。其中 Address 是节点地址,Data 是一个绝对值不超过 100000 的整数,Next 是下一个节点的地址。保证两个链表都不为空,且较长的链表至少是较短链表长度的两倍

输出格式

对于每个测试用例,按顺序输出合并后的结果链表。每个结点占一行,按输入的格式输出

输入样例

在这里给出一组输入。例如:

00100 01000 7
02233 2 34891
00100 6 00001
34891 3 10086
01000 1 02233
00033 5 -1
10086 4 00033
00001 7 -1

输出样例

在这里给出相应的输出。例如:

01000 1 02233
02233 2 00001
00001 7 34891
34891 3 10086
10086 4 00100
00100 6 00033
00033 5 -1

分析

  • JavaScript 中没有链表,需要模拟

解答

const inputs = `
00100 01000 7
02233 2 34891
00100 6 00001
34891 3 10086
01000 1 02233
00033 5 -1
10086 4 00033
00001 7 -1
`;

// 链表类
const nodeAddrMap = new Map();

class Node {
  addr = null
  data = null
  next = null
  constructor(addr, len) {
    len.val += 1;
    this.addr = addr;
    let [data, next] = nodeAddrMap.get(addr);
    this.data = data;
    if (next !== '-1') {
      this.next = new Node(next, len);
    }
  }
  toString() {
    let [next, retV] = [this, []];
    while (next !== null) {
      retV.push(`${next.addr} ${next.data} ${next.next === null ? '-1' : next.next.addr}`);
      next = next.next;
    }
    return retV.join('\n');
  }
  reverse() {
    // 反转链表
    let [prev, current] = [null, this];
    while (current !== null) {
      [current.next, prev, current] = [prev, current, current.next];
    }
    return prev;
  }
}
const c = inputs.split('\n');
const [startAddr1, startAddr2, totalNodeNum] = c[0].split(' ');

for (let i = 1; i <= parseInt(totalNum); i++) {
  let [addr, data, next] = c[i].split(' ');
  nodeAddrMap.set(addr, [data, next]);
}
//构建两个链表并且直接返回链表长度
let len1 = { val: 0 };
let len2 = { val: 0 };
let list1 = new Node(startAddr1, len1);
let list2 = new Node(startAddr2, len2);
if (len1.val < len2.val) {
  // 确保 list1 是长的链表
  [list1, list2] = [list2, list1];
}
// 反转短链表
list2 = list2.reverse();
let [cl1, cl2] = [list1, list2];
while (cl2 !== null) {
  // 长链表每隔2个结点,插一个短链表的结点。直到短链表没有剩余结点
  cl1 = cl1.next;
  [cl1.next, cl2.next, cl2, cl1] = [cl2, cl1.next, cl2.next, cl1.next];
}
console.log('' + list1);

留下评论