题目:反转链表
反转一个单链表。
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
题解:
方法1:迭代法
step1:设置两个指针,一个prev,初始为null,用来记录当前指针的前一个指针,一个curr,curr初始为head,用于记录当前需要反转的指针
step2:遍历链表,对当前的指针进行反转,即curr.next-->prev,然后curr向后移动,prev也向后移动一个
step3:遍历结束后,返回prev,即为一个反转后的新链表
时间复杂度:O(n)
空间复杂度:O(1)
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
// 迭代法
let prev = null
let curr = head
while(curr){
//改变当前curr的指向,进行反转
let temp = curr.next
curr.next = prev
prev = curr
curr = temp
}
return prev
方法2:尾递归
尾递归可以看作迭代法的简化版本,将迭代部分进行递归实现
step1:将当前节点curr指向前一个节点prev,该节点反转完成
step2:前一个节点curr以及当前节点prev往后顺移,直到curr为空
时间复杂度:O(n)
空间复杂度:O(1)
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
return reverse(null,head)
};
//尾递归
function reverse(prev, curr){
if(!curr){
return prev
}
let temp = curr.next
curr.next = prev
//往后顺移,再反转
return reverse(curr,temp)
}
方法3:递归
step1:将当前链表看作两部分
当前节点
剩下部分
step2:假设余下部分是已经反转的链表,只需要将此节点,与余下部分进行链接,即余下部分的最后一个节点,指向当前节点
step3:剩下的部分又可以看作是两部分,以此类推,形成递归
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
//递归
//如果剩下一个节点,则返回head
if(!head||!head.next){
return head
}
//余下部分
let next = head.next
//对余下部分进行递归处理
let reverseHead = reverseList(next)
//在每一次递归时,需要进行一次反转
head.next = null
next.next = head
return reverseHead
};
博客围绕反转单链表问题展开,介绍了三种解题方法。迭代法通过设置两个指针遍历链表实现反转;尾递归是迭代法的简化,将迭代部分递归实现;递归则把链表不断拆分为两部分,逐步完成反转。三种方法时间复杂度均为O(n),空间复杂度为O(1)。
869

被折叠的 条评论
为什么被折叠?



