【算法-LeetCode】24. 两两交换链表中的节点(链表;双指针;内存消耗首次击败100%用户)

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

发布:2021年10月8日18:47:33

问题描述及示例

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

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

示例 2:
输入:head = []
输出:[]

示例 3:
输入:head = [1]
输出:[1]

提示:
链表中节点的数目在范围 [0, 100] 内
0 <= Node.val <= 100

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的题解(双指针)

链表类的题目往往要用到指针。之前也碰到过链表相关的题,有关题解博客可参看下方【有关参考】处的链接。

本题也是利用了双指针的思路。

首先需要创建一个辅助头结点 dummy,然后让指针 p 和 指针 q 完成将两个节点交换的任务。对于某两个节点的交换过程,可以参看下方动态图:

请添加图片描述

交换两个节点的过程

而之后的交换过程也是一样的。直到遇到 p === nullp.next === null 的情况。

值得一提的是,这次提交似乎是我第一次碰到击败 100% 用户的情况,不过LeetCode的判题结果和网络有一定关系,所以也不能全信,但是还是值得纪念一下。
在这里插入图片描述

内存消耗首次击败 100% 用户,纪念一下(虽然我知道这个结果和网络有关系)

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var swapPairs = function(head) {
  // 如果链表为空,直接返回null
  if(!head) {
    return null;
  }
  // 创建辅助头结点dummy
  let dummy = new ListNode(0,head);
  // 初始化p、q指针的指向
  let p = dummy;
  let q = head;
  // 开始交换两个相邻的节点,注意下面这个while循环的条件,只要 q 或者 q.next中有任何一方
  // 为空,则停止循环。而且一定要将 q 放在前面,这是利用了 && 的短路特性,如果 q 为 null
  // 的话,则直接判断整个条件为 false,于是跳出循环。如果将 q.next 放在前面的话,
  // 如果 q 为 null,则 q.next 就会报错:
  // 【TypeError: Cannot read property 'next' of null】
  while(q && q.next) {
    // 下面三句就是关键的交换两个相邻节点的逻辑,建议在图上自己动手画一画指针变化
    p.next = q.next;
    q.next = q.next.next;
    p.next.next = q;
    // 【tag1】下面三句用来移动p、q指针来为下一次交换做准备,可以简化为两句,详看下方优化
    q = p.next;
    q = q.next.next;
    p = p.next.next;
  }
  // 最后返回头结点,注意不是辅助头结点
  return dummy.next;
};


提交记录
55 / 55 个通过测试用例
状态:通过
执行用时:72 ms, 在所有 JavaScript 提交中击败了53.66%的用户
内存消耗:36.7 MB, 在所有 JavaScript 提交中击败了100.00%的用户
时间:2021/10/08 18:51

小小的优化

在【tag1】处的指针移动,其实可以把 q 指针【先往前走一步再往后走两步】的操作改成直【接让 q 指针往后走一步】:

// 原来的写法
...
q = p.next;
q = q.next.next;
p = p.next.next;
...

// 改进之后的写法
...
q = q.next;
p = p.next.next;
...


提交记录
55 / 55 个通过测试用例
状态:通过
执行用时:64 ms, 在所有 JavaScript 提交中击败了89.55%的用户
内存消耗:37.9 MB, 在所有 JavaScript 提交中击败了66.75%的用户
时间:2021/10/08 19:41

但是这个时间表现和空间表现和自己预想的结果好像还是有点出入,感觉这个结果和网络波动的因素关联挺大的……权当图个乐吧~

官方题解

更新:2021年7月29日18:43:21

因为我考虑到著作权归属问题,所以【官方题解】部分我不再粘贴具体的代码了,可到下方的链接中查看。

更新:2021年10月8日18:54:36

参考:两两交换链表中的节点 - 两两交换链表中的节点 - 力扣(LeetCode)

【更新结束】

有关参考

【此前做过的链表类题目】
更新:2021年10月8日20:17:10
参考:【算法-LeetCode】206. 反转链表(单链表;生成LeetCode单链表)_赖念安的博客-CSDN博客
参考:【算法-LeetCode】141. 环形链表(单链表;环;快慢指针;双指针)_赖念安的博客-CSDN博客
参考:【算法-剑指 Offer】22. 链表中倒数第k个节点(单链表;双指针)_赖念安的博客-CSDN博客
参考:【算法-LeetCode】160. 相交链表(双指针)_赖念安的博客-CSDN博客
参考:【算法-LeetCode】19. 删除链表的倒数第 N 个结点(双指针/快慢指针)_赖念安的博客-CSDN博客
参考:【算法-LeetCode】19. 删除链表的倒数第 N 个结点(双指针/快慢指针)_赖念安的博客-CSDN博客
参考:【算法-LeetCode】2. 两数相加(双指针/同步指针;链表)_赖念安的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值