LeetCode 1721:交换链表中的节点

133 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情

LeedCode 1721:交换链表中的节点

题目描述

给你链表的头节点 head 和一个整数 k 。

交换 链表正数第 k 个节点和倒数第 k 个节点的值后,返回链表的头节点(链表 从 1 开始索引)。

解题思路

思路一:利用快慢指针

可以先参考LeetCode 19:删除链表的倒数第 N 个结点 - 掘金 (juejin.cn)

1. 根据快慢指针,定位到第k个节点的前一个节点kNodePre;倒数第 k 个节点slow;倒数第 k 个节点前一个节点lastKNodePre

  1. 分三种情况:
  • 两节点是同一个;不需要交换,直接返回;如head = [1,2,3,4,5], k = 3
  • 两节点相邻;
  • 两节点不相邻;

我们使用dummy节点, kNodePre指正数第 k 个节点前一个节点,即第 k - 1个节点

for (let i = 1; i < k; i++) {
  kNodePre = fast;
  fast = fast.next;
}

fast指针走到头时, slow指向倒数第 k 个节点,lastKNodePre指倒数第 k 个节点前一个节点

while (fast !== null && fast.next !== null) {
  lastKNodePre = slow;
  slow = slow.next;
  fast = fast.next;
}

两个节点相邻, 交换代码如下:

if (kNode.next === slow) {
  // 两个节点相邻; 如 head = [1,2], k = 1
  kNode.next = slow.next;
  slow.next = kNode;
  kNodePre.next = slow;
}

完整实现代码如下:

/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var swapNodes = function (head, k) {
  if (head === null || head.next === null) {
    return head;
  }
  let dummy = new ListNode(0, head);
  let kNodePre = dummy,
    lastKNodePre = dummy,
    slow = head,
    fast = head;
  // kNodePre指正数第 k 个节点前一个节点,即第 k - 1个节点
  for (let i = 1; i < k; i++) {
    kNodePre = fast;
    fast = fast.next;
  }
  // kNode指正数第 k 个节点
  var kNode = fast;
  // fast指针走到头时, slow指向倒数第 k 个节点
  // lastKNodePre指倒数第 k 个节点前一个节点
  while (fast !== null && fast.next !== null) {
    lastKNodePre = slow;
    slow = slow.next;
    fast = fast.next;
  }
  // 正数第 k 个节点 与 倒数第 k 个节点 是同一个时, 不用交换,直接返回; 如 head = [1,2,3,4,5], k = 3
  if (kNode === slow) {
    return dummy.next;
  } else if (kNode.next === slow) {
    // 两个节点相邻; 如 head = [1,2], k = 1
    kNode.next = slow.next;
    slow.next = kNode;
    kNodePre.next = slow;
  } else if (slow.next === kNode) {
    // 两个节点相邻; 如 head = [1,2], k = 2
    slow.next = kNode.next;
    kNode.next = slow;
    lastKNodePre.next = kNode;
  } else {
    var tmp = slow.next;
    kNodePre.next = slow;
    lastKNodePre.next = kNode;
    slow.next = kNode.next;
    kNode.next = tmp;
  }
  return dummy.next;
};

简化版

var swapNodes = function (head, k) {
  if (head === null || head.next === null) {
    return head;
  }
  var dummy = new ListNode(0, head);
  var kNodePre = dummy,
    kNode,
    lastKNode;
  // kNodePre指正数第 k 个节点前一个节点,即第 k - 1个节点
  for (var i = 1; i < k; i++) {
    kNodePre=kNodePre.next;
  }
  var slow = dummy, 
    fast = kNodePre.next;
  // 此时slow指向倒数第 k-1 个节点
  while (fast.next != null) {
    fast = fast.next;
    slow = slow.next;
  }

  if (kNodePre != slow) {
    // kNode指正数第 k 个节点
    kNode = kNodePre.next;
    // lastKNode指向倒数第 k 个节点
    lastKNode = slow.next;
    slow.next = kNode;
    kNodePre.next = lastKNode;
    var tmp = lastKNode.next;
    lastKNode.next = kNode.next;
    kNode.next = tmp;
  }
  return dummy.next;
};

参考资料

1721. 交换链表中的节点 - 力扣(LeetCode)