Problem
Given a linked list, swap every two adjacent nodes and return its head.
Example:
1 | Given 1->2->3->4, you should return the list as 2->1->4->3. |
Note:
- Your algorithm should use only constant extra space.
- You may not modify the values in the list’s nodes, only nodes itself may be changed.
Analysis
2018.01.12
这道题考察的是关于链表的操作,难点在于它要求交换相邻的两个节点。同时题目要求不能更改节点的值,我们只能通过更改节点之间的指针来实现。
因为是交换相邻的两个节点,因此我们需要使用两个指针分别指向先后两个节点。如果链表的节点数是偶数,那么每两个交换;如果链表的节点数是奇数,那么最后一个节点则不需要操作。如果给出两个节点,要求交换,这个操作并不难,first->next = second->next; second->next = first
即可实现。难度在于如果切换至下一对节点。首先我们需要判断后面是否有节点,这里对first
判断是否为null即可。循环的退出条件是只剩最后一个节点或后面没有节点。
运行后发现仍然报错了,出错的原因是,上一对的first
应该指向的是当前对的second
。如果需要在上一对处理的时候判断,那么将会增加大量的代码。这里我将判断放到了当前对中,因此只需要额外增加一个变量last
来表示上一对的first
。在当前对中,直接将last->next = second
来完成两对之间的连接。这个办法显然快很多。
至此,整个算法思路就很明确了。同时要注意两个问题:
- 当链表长度小于等于2的时候,直接返回。
- 我们需要用一个变量
result
来返回交换后的表头,因为交换后的表头一定是第一对中的second
,所以可以直接赋值result = second
。
更新于2021.03.21
一年多之后又碰到了这道题目,解决这道题目的思路还是一样的,但是在代码层面上比之前更加统一以及易懂。交换两个元素,假设结构是a->b->c->d
。这里假设我们要交换b
和c
,我们的做法分解为三步:
- 先使用一个变量存储
c
,因为在交换完这一对之后,b
要指向c
后面的元素d
,所以要先记下来,用于访问d
; - 然后改变
b
的指向,b
指向d
; - 然后
c
指向b
; - 最后是
a
指向c
。
通过上面四个步骤就可以完成,因为我们每次都是从a
开始的,所以要保证a->next
和a->next->next
都不为空。
同时,还有一个技巧可以使用,当处理第一对的时候,我们会发现没有a
,这种情况下直接新增一个dummy
节点即可。这样处理后所有的情况都可以统一处理了。
Code
2018.01.12
1 | /** |
运行时间:约0ms,超过100%的CPP代码。
2021.03.21
1 | /** |
Summary
这道题目考点还是链表的操作,相比起以前的插入删除,这道题的难度有所提高,做起来还是花了点时间。我的建议是关于链表的题目多在纸上画,模拟一下算法的过程,然后可以在程序中打印一下相关的值,同时牵涉到指针问题需要特别注意指针为空的情况。本题的分析就到这里,感谢您的支持!