个人评价:链表的经典面试题,有必要重提一下~
题目难度:🌟 (参考 LeeCode 简单🌟 、中等🌟 🌟 、困难🌟 🌟 🌟 )
另,通常算法题会考察分析时间复杂度和空间复杂度,可参考笔者之前的文章
反转链表
题目描述
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶: 你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
解题思路
方法一
迭代法:按原始顺序迭代,将迭代到的结点依次移为头结点,直至尾结点结束。
Go 代码如下
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseList(head *ListNode) *ListNode {
var prev *ListNode
curr := head
for curr != nil {
next := curr.Next
curr.Next = prev
prev = curr
curr = next
}
return prev
}
相对比较基础,前提需熟悉链表结构,且了解指针操作,详细可参考之前的博文:「数据结构&算法」必知必会系列:7. 常见数据结构——链表(下)
复杂度?🙌 时间 O(n) 空间 O(1)
方法二
链表本身具有天然的递归性,反转链表也可使用递归实现,理解起来比迭代多一点难度。
以下动图的图解可适当便于理解,递归反转前面部分链表指向 & 注意下一节点指向null。
- 使用递归函数,一直递归到链表的最后一个结点,该结点就是反转后的头结点,记作 ret
- 此后,每次函数在返回的过程中,让当前结点的下一个结点的 next 指针,指向当前节点。
- 同时让当前结点的 next 指针指向 NULL ,从而实现从链表尾部开始的局部反转
- 当递归函数全部出栈后,链表反转完成。
作者:huwt 链接:https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-shuang-zhi-zhen-di-gui-yao-mo-/
Golang 实现代码如下:
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseList(head *ListNode) *ListNode {
if head == nil || head.Next == nil { return head }
newHead := reverseList(head.Next)
head.Next.Next = head
head.Next = nil
return newHead
}
复杂度?🙌 时间 O(n) 空间 O(n)
总结
反转链表 真的是面试非常喜欢考的,这题看起来简单,但是能用 两种方法 一遍 bug free 也是不容易的。