class ListNode:
def __init__(self,x):
self.val = x
self.next = None
def reverseList(head:ListNode)->ListNode:
'''
原地反转
时间复杂度:O(N)
额外空间复杂度 O(1)
Args:
head:
Returns:
'''
if not head or not head.next:
return head
before = None
cur = head
# 这里必须多一个指针记录下一个节点,因为当cur进行就地反转后就无法知道后面的节点,需要提前记录
after = head.next
# 当after为None是说明cur已经到达结尾了
while after:
cur.next = before
before =cur
cur = after
after = after.next
# 做最后一次反转
cur.next = before
return cur
def reverseList1(head:ListNode)->ListNode:
'''
递归反转(直接超时了)
Args:
head:
Returns:
'''
if not head or not head.next:
return head
# 反转子链表
# 一层一层的递归就是要找到反转后的头节点(这个头节点在递归返回的过程并没有参与运算)
re = reverseList1(head.next)
# 在递归到最深层找到头节点后,在递归返回到过程中就需要进行每个节点到反转
# 每一层的next节点就是下一层的头节点,而每一层的head和head.next的节点都是已知的,要做的反转就是将head.next的next反转为head,并将原来的head.next断开(不然就会出现死循环)
head.next.next = head
head.next = None
return re
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
pre = None
cur = head
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre
时间复杂度:O(N)
额外空间复杂度 O(1)
递归
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
tmp = self.reverseList(head.next)
head.next.next = head
head.next = None
return tmp
时间复杂度:O(n)
空间复杂度:O(n)
func reverseList(head *ListNode) *ListNode {
if head == nil {
return nil
}
var pre *ListNode
for head != nil {
next := head.Next
head.Next = pre
pre = head
head = next
}
return pre
}
//原地翻转
func reverseList(head *ListNode) *ListNode {
var p *ListNode
cur := head
for cur != nil{
next := cur.Next
cur.Next = p
p = cur
cur = next
}
return p
}
//递归
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
}
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre = None
while head:
tmp = head.next
head.next = pre
pre = head
head = tmp
return pre
class Solution(object):
def reverseList(self, head):
# 递归
# temp = self.reverseList(head.next)
# head.next.next =head
# head.next = None
# return temp
#迭代
#初始化,cur当前节点,pre为cur前节点
cur = head
pre = None
while cur:
# temp暂存cur后节点
temp = cur.next
#cur节点指向前节点
cur.next = pre
# 移动节点
pre = cur
cur = temp
return pre
class Solution {
public ListNode reverseList(ListNode head) {
ListNode left = null;
ListNode right = new ListNode(0);
right = head;
ListNode temp = new ListNode(0);
while(right != null){
temp = right.next;
right.next = left;
left = right;
right = temp;
}
return left;
}
}
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
# 迭代方法(原地反转)
pre,curr = None,head
while curr:
temp = curr.next
curr.next = pre
pre = curr
curr = temp
return pre
# 递归
def recur(curr,pre):
if not curr:
return pre
res = recur(curr.next,curr)
curr.next = pre
return res
return recur(head,None)
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode pre = null;
ListNode cu = head;
ListNode next = null;
while (cu != null) {
next = cu.next;
cu.next = pre;
pre = cu;
cu = next;
}
return pre;
}
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
lst = []
t1 = head
k1 = head
while head != None:
lst.append(head.val)
head = head.next
for i in range(len(lst)):
t1.val = lst[-(i+1)]
t1 = t1.next
return k1
方法二:原地反转,看的题解思路,然后双指针实现O(n)
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
t =None
h =None
if head is None:
return head
while head.next != None:
t = head.next
head.next = h
h = head
head = t
head.next = h
return head
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null, cur = head, next = null;
while(cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
共以下 81 个回答
原地颠倒
头插法
递归法
时间复杂度、空间复杂度均为:O(n)
“`c++
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head)
return NULL;
ListNode*p = head;
p = p->next;
head->next = NULL;
// 头插法创建链表
ListNode*q = p;
while(p!=NULL)
{
p = p->next;
q->next = head;
head = q;
q = p;
}
return head;
}
};“`
时间复杂度:O(n)
空间复杂度:O(1)
时间o(n),空间o(1)
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode pre = null;
while( cur!=null){
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
#时间复杂度 o(N)
#空间复杂度o(1)
“`java
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode cur=head,pre=null;
while(cur!=null){
ListNode temp= cur.next;
cur.next=pre;
pre=cur;
cur= temp;
}
}
迭代
递归
1、说实话,不会,看了帅地代码略知一些
2、时间复杂度O(n),空间复杂度O(n)
1.递归解决
时间复杂度:O(n)
空间复杂度:O(n)
2.原地反转
时间复杂度: O(n)
空间复杂度: O(1)
迭代法
“`java
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head, pre = null;
while(cur != null) {
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
“`
时间复杂度o(n)
空间复杂度o(1)
时间复杂度:O(N) 遍历链表
空间复杂度:O(1) cur,pre使用额外空间
解法二:递归
时间复杂度:O(N) 遍历链表
空间复杂度:O(N) 递归深度N
思路:原地反转
每次当前节点指向前一个结点 之后当前节点和前一个结点同时右移
原地反转,时间复杂度O(n) 空间复杂度O(1),多写了一个没用的node,不改了
时间复杂度O(n)
空间复杂度O(1)
时间:O(n)
空间:O(n)
思路:
S1:用到两个指针pre指针指向前一个节点(最开始时pre初始化为null),cur指针指向当前节点,
S2:循环遍历链表,当cur没指向空值时,就执行步骤S3
S3:用一个临时节点t存储 当前节点的下一个节点,当前节点(cur)指向前继节点(pre),然后pre指针指向下一个节点,cur指向临时节点t,直到cur指向空值跳出循环。
时间复杂度:O(n)
空间复杂度: O(n)
递归 时间O(n) 空间O(n)
迭代 头插法实现反转 时间O(n) 空间O(1)
时间复杂度:O(N)
空间复杂度:O(1)
复杂度:
时间复杂度:O(n)
空间复杂度:O(1)
原地反转,只要在回溯的时候让当前引用的下一个引用指向自己即可
非原地反正的话,我的思路是设3个指针,分别指向当前元素,以及的它的前一个和后一个元素,然后每次遍历。只要让当前的元素指向他的前一个元素,然后在让这三个指针总体往后移,不断持续这个过程即可
递归,将子任务交给递归,设置好base_case,假设此时链表中该节点的子链表翻转完成,那么此时只需要设置当前节点的next的next指向自己,自己的next 指向空即可。返回值始终都是最后一个节点,因为后续操作中对此无更改便一直顺着函数调用栈返回。最后返回该节点即是翻转后的头节点。
时间复杂度O(n)
空间复杂度(函数调用栈) O(n)
学习到的原地反转思路,发现和自己最开始想用在递归中的思路很像,不过没想清楚,借助第三个node通过直接赋值来访问自己的前驱节点。
时间复杂度:O(N)
额外空间复杂度(需要多申请几个变量) O(1)
时间复杂度O(n)
空间复杂度O(1)
反转链表
时间复杂度:O(n),其中 n是链表的长度。需要对链表的每个节点进行反转操作。
空间复杂度:O(n),其中 n是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为 n层。
时间复杂度: O(n)
空间复杂度: O(1)
解法1:递归
思路:就是画图,先反转一个,后面直接递归
时间复杂度 :O(N)
空间复杂度 :O(N)
解法2:原地迭代
时间复杂度 :O(N)
空间复杂度 :O(1)
时间复杂度: O(n)
递归的思想,视后序要反转的节点为一个整体,改变指针指向并返回新的头结点,时间O(n),空间O(n)
下面代码
时间复杂度n
空间复杂度 1
时间复杂度O(n) 空间复杂度O(1)
时间复杂度 O(n)
//迭代方法iteration
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre=nullptr,* cur=head;
while(cur){
ListNode* temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
};
注意最后return的是哪个指针
迭代法
空间复杂度O1
时间复杂度On
时间复杂度O(n)
空间复杂度(1)
递归
时间复杂度:O(n)
空间复杂度:O(n)
第一种:原地交换法
第二种:递归
双指针,定义左右指针,右指针先指向头结点,作指针为空,定义一个新节点暂存右节点的下一个节点,让右指针指向左指针,
完成后,左右指针都向后移(把右指针赋给左指针,暂存节点的赋给右指针)完成后移直到右指针为null
时间复杂度:O(n)
空间复杂度:O(n)
时间O(n) 空间O(1)
来个递归版本的
额
递归
时间复杂度O(n)
空间复杂度O(1)
时间复杂度O(n)
空间复杂度O(1)
方法1:迭代,通过保存curr.next 到temp,保证反转后后续节点不丢失,再反转,知道curr为空,此时的prev即为反转的结果
方法1时间复杂度:O(n)
方法1空间复杂度:O(1)
方法2:递归
方法2时间复杂度:O(n)
方法2空间复杂度:O(n)
// 模拟链表头插法 调整钩链关系
时间复杂度:O(n)
空间复杂度:O(1)
原地反转
使用辅助栈
递归
递归与原地反转
就是注意反转的时候的前后反转的顺序关系,和交换函数差不多
时间复杂度O(n)
空间复杂度O(1)
递归
双指针法
递归
思路一:原地反转。pre初始化为null,cur指向第一个要翻转的节点,让cur.next=pre就可以实现防止,为了翻转整个链表,需要一个临时节点temp保存cur的下一个节点,执行cur.next=pre后,需要让pre=cur,cur=temp来为翻转下一个节点做准备。时间复杂度O(N),空间复杂度O(1)。给出代码。
思路二:递归。想好递归处理的过程,注意递归终止条件。时间复杂度O(N),空间复杂度O(N)。给出代码。
思路三:使用辅助栈。时间复杂度O(N),空间复杂度O(N)。给出代码
方法1 时间复杂度O(n)
时间复杂度:O(n),空间复杂度:O(1)
原地反转,时间空间都为O(n)
时间复杂度为O(n),空间复杂度O(1)
使用递归,时间复杂度空间复杂度O(n)
时间O(n)
// 时间发复杂度O(n),空间复杂度O(1)。