给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
又是一道链表题目,要求是两两交换链表中的节点,看似很复杂的一个问题,但是使用分治法,可以很简单的解决这个问题,我们只需将链表中的节点两两取出,交换位置,并在其后连接上后两个交换过位置的链表即可,那么我们就开始编写代码吧。
首先根据题目我们可以构建出来函数头,输入为一个链表,输出也为一个链表:
public ListNode SwapPairs(ListNode head)
分治法多用递归来实现,那么我们要找到递归终结的条件,因为需要两两交换,那么在最后一组之后,没有节点或只剩下一个节点均为递归结束,那么判断条件为node == null || node.next == null
,有了终止条件,我们可以构建代码如下
public ListNode SwapPairs(ListNode head)
{
if (head == null || head.next == null) //判断是否无法组成一组
{
return head;
}
ListNode result = head.next; //第二个节点
head.next = SwapPairs(result.next); //将第一个节点的next指向后边交换后的节点
result.next = head;//将第二个节点的next指向第一个节点
return result;
}
放入LeetCode 跑一下
执行用时 :104 ms, 在所有 C# 提交中击败了86.22%的用户
内存消耗 :22.9 MB, 在所有 C# 提交中击败了93.22%的用户
性能不错,而且代码十分简洁。但是我们这里使用了递归,递归尤其很明显的缺点,当数据量过大时,因为递归每一次函数调用都会在内存调用栈中分配空间,而调用栈的空间是有限的,所以会导致栈溢出。曾经听一位前辈说过所有的递归都可以改写成循环,那么既然今天这道题目很容易就解出来了,我们就再花一点时间将之改造成循环吧。中间过程不赘述,直接上代码
public ListNode SwapPairs(ListNode head)
{
ListNode current = head;
ListNode preNode = new ListNode(-1);//记录前一个节点
preNode.next = head;//将现在链表写入pre的后边
ListNode result = preNode;
while (current != null && current.next != null)
{
ListNode first = current;
ListNode second = current.next; //取出需要交换的两个节点
preNode.next = second;//将第二个节点接入上一个节点中
first.next = second.next;//将第二个节点的下一个节点接入第一个节点
second.next = first;//将第一个节点放入第二个节点后边
preNode = first;//此时第一个节点即为下次循环的前一个节点
current = first.next;//此时第一个节点的下一个即为下一次循环的起始节点
}
return result.next;
}
放入LeetCode 跑一下
执行用时 :100 ms, 在所有 C# 提交中击败了95.92%的用户
内存消耗 :23.1 MB, 在所有 C# 提交中击败了72.03%的用户
性能有所提升,但是代码的可读性会降低不少,那么今天这道题目就讲到这里了。