# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head:
return None
def recur(cur, pre):
if not cur:
return pre
res = recur(cur.next, cur)
cur.next = pre
return res
return recur(head, None)
原地反转
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur, pre = head, None
while cur:
_next = cur.next
cur.next = pre
pre = cur
cur = _next
return pre
“`python
//遍历链表,并在访问各节点时修改next引用指向
class Solution(object):
def trainningPlan(self, head):
cur=head
pre=None
while cur:
tmp=cur.next
cur.next=pre
pre=cur
cur=tmp
return pre
时间复杂度:O(N) N为链表的长度
空间复杂度:O(1) pre cur 额外占用常数的空间
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head: return head #头节点为空
if not head.next: return head #单独只有一个节点,直接返回该节点,不用翻转
temp=self.trainningPlan(head.next) #后续要翻转的节点,作为返回值
head.next.next=head #考虑一个节点的翻转(此时已经至少有两个节点存在)
head.next=None # 原来的节点指向None!!!不能忘记
return temp #返回后续节点
时间复杂度为:O(n)
空间复杂度为:O(n) 递归调用消耗栈空间
迭代
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next: return head
pre=None #pre初始化为None
cur=head
while cur:
temp=cur.next
cur.next=pre
pre=cur #一定要先更新pre
cur=temp
return pre #返回pre
class Solution:
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head
node = self.trainningPlan(head.next)
head.next.next = head
head.next = None
return node
class Solution:
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is []: return []
stack = []
temp = head
while temp is not None:
stack.append(temp.val)
temp = temp.next
new_head = ListNode(0)
temp = new_head
for i in range(len(stack)):
temp.next = ListNode(stack.pop())
temp = temp.next
return new_head.next
time O(n) space O(n)
方法2:递归 本质也有一个n长度的stack,重新链接回head的部分要注意。
class Solution:
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None: return head
# we cannot use head other wise this will not actually run.
temp = self.trainningPlan(head.next)
# update the head's link, tricky part
# 5 -> 4 -> 3 -> 2
# ^
# |
# 1
head.next.next = head # head is 1, 1's next is 2, then change its next back to 1
head.next = None # reconfirm the original head is the tail with None as next
# time O(n) space O(n) because of the stack.
return temp
time O(n) space O(n)
方法3:in place重建链接,需要用到一些缓存的点来保证前后关系,用到了双指针的思想。
class Solution:
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None: return head
cur = head
pre = None
while cur:
temp = cur.next # temp store the cur.next
cur.next = pre # reverse the link
pre = cur # update the previous to be the current visited
cur = temp # update the current to pre-stored next
return pre
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur, res = head, None
while cur:
tmp = cur.next
cur.next = res
res = cur
cur = tmp
return res
class Solution:
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
temp = None
cur = head
if head None:
return
while(cur):
nex = cur.next
cur.next = temp
temp = cur
cur = nex
return temp
时间复杂度O(n), 空间复杂度O(n)
共以下 47 个回答
“`java
//时间On^2 内存On
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode trainningPlan(ListNode head) {
if (head == null)
return null;
ListNode p = head;
int cnt = 0;
ListNode reverse = new ListNode();
ListNode cur = reverse;
while (p.next != null) {
p = p.next;
cnt++;
ListNode node = new ListNode();
cur.next = node;
cur = cur.next;
}
cur = reverse;
int tmp = cnt;
for (int i = 1; i <= cnt + 1; i++) { p = head; for (int j = 1; j <= tmp; j++) p = p.next; tmp--; cur.val = p.val; cur = cur.next; } return reverse; } }
class Solution {
public ListNode trainningPlan(ListNode head) {
// 原地反转
if(head null || head.next null){
return head;
}
}
递归
原地反转
class Solution {
public ListNode trainningPlan(ListNode head) {
ListNode pre =null;
ListNode cur = head;
while(cur!= null){
ListNode t = cur.next;
cur.next = pre;
pre=cur;
cur=t;
}
return pre;
}
}打卡
题解【递归】
[图片]
“`python
//遍历链表,并在访问各节点时修改next引用指向
class Solution(object):
def trainningPlan(self, head):
cur=head
pre=None
while cur:
tmp=cur.next
cur.next=pre
pre=cur
cur=tmp
return pre
时间复杂度:O(N) N为链表的长度
空间复杂度:O(1) pre cur 额外占用常数的空间
代码:class Solution {
public ListNode trainningPlan(ListNode head) {
ListNode pre=null,cur=head;
while(cur!=null){
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
}
代码:class Solution {
public ListNode trainningPlan(ListNode head) {
ListNode pre=null,cur=head;
while(cur!=null){
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
}
”’java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode trainningPlan(ListNode head) {
// 原地反转
// 非空判断
if (head null || head.next null) {
// 链表为空或者链表只有一个节点时直接返回
return head;
}
ListNode cur = head;
ListNode pre = null;
while (cur != null) {
// 暂存
ListNode temp = cur.next;
// 通过cur与pre进行链表反转
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
”’
时间复杂度On
空间复杂度O1
###
时间复杂度0(n)、空间复杂度O(n)
时间复杂度0(n)、空间复杂度O(1)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode trainningPlan(ListNode head) {
ListNode pre = null, cnt = head, temp = null;
while (cnt != null) {
temp = cnt.next;
cnt.next = pre;
pre = cnt;
cnt = temp;
}
return pre;
}
}//运用指针
递归
时间复杂度为:O(n)
空间复杂度为:O(n) 递归调用消耗栈空间
迭代
时间复杂度为:O(n)
空间复杂度为:O(1)
//递归1
class Solution {
public ListNode trainningPlan(ListNode head) {
return recur(head,null);//cur pre
}
ListNode recur(ListNode cur,ListNode pre){
if(curnull)
return pre;//pre是头
ListNode res=recur(cur.next,cur);
cur.next=pre;
return res;
}
}
头插法
···java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode trainningPlan(ListNode head) {
if(head null || head.next null) return head;
ListNode res = new ListNode();
ListNode p = head;
while(p != null){
ListNode next = p.next;
p.next = res.next;
res.next = p;
p = next;
}
return res.next;
}
}
“`c++
class Solution {
public:
ListNode* trainningPlan(ListNode* head) {
if(nullptr == head || nullptr == head->next){
return head;
}
ListNode* temp = trainningPlan(head->next);
head->next->next = head;
head->next = nullptr;
return temp;
}
};
“`
//使用递归比较简单且不易出错
双指针
O(n), O(1)
“`c++
ListNode* trainningPlan(ListNode* head) {
ListNode* cur=head;
ListNode* pre=nullptr;
while(cur!=nullptr){
ListNode* temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
}
“`
““java
递归方法:
class Solution {
ListNode head2 =new ListNode();
ListNode p=head2;
public ListNode trainningPlan(ListNode head) {
reverse(head);
return head2.next;
}
//原地遍历法
class Solution {
public ListNode trainningPlan(ListNode head) {
ListNode pre=null;
ListNode cur=head;
while(cur!=null){
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
}
O(N) O(1)
思路:两种方式都使用了。原地和递归。递归的时候是想着,一层层往里递归后,从最里层向外回溯,两两操作节点
递归!!!
//法一迭代:
class Solution {
public ListNode trainningPlan(ListNode head) {
if (head null||head.nextnull )
return head;
ListNode pre=null;
ListNode cur=head;
ListNode tmp=null;
while(cur!=null){
tmp=cur.next;
cur.next=pre;
pre=cur;
cur=tmp;
}
return pre;
}
}
时间复杂度 O(n)
空间复杂度 O(1)
*/
//法二递归:
class Solution {
public ListNode trainningPlan(ListNode head) {
return reverse(head,null);
}
ListNode reverse(ListNode cur,ListNode pre){
if(curnull) return pre;
ListNode tmp=cur.next;
cur.next=pre;
return reverse(tmp,cur);
}
}
时间复杂度 O(n)
空间复杂度 O(n)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode trainningPlan(ListNode* head) {
auto pHead=new ListNode();
auto p=head,q=head;
while(p!=nullptr)
{
q=p->next;
p->next=pHead->next;
pHead->next=p;
p=q;
}
p=pHead->next;
delete pHead;
return p;
}
};
使用头指针
“`C++
class Solution {
public:
ListNode* trainningPlan(ListNode* head) {
if(head==nullptr || head->next == nullptr){
return head;
}
ListNode* cur = trainningPlan(head->next);
head->next->next = head;
head->next = nullptr;
return cur;
}
};
“`
时间复杂度O(n),空间复杂度O(n)
时间复杂度:O(N)
额外空间复杂度 O(n)
时间复杂度:O(N)
额外空间复杂度 O(1)
方法1:单独把值倒序拉出来 然后重新建立link。
time O(n) space O(n)
方法2:递归 本质也有一个n长度的stack,重新链接回head的部分要注意。
time O(n) space O(n)
方法3:in place重建链接,需要用到一些缓存的点来保证前后关系,用到了双指针的思想。
time O(n) space O(1) 仅额外开了两个node的空间。
class Solution {
public:
ListNode* trainningPlan(ListNode* head) {
if(head NULL || head->next NULL){
return head;
}
ListNode* p = head;
ListNode* q = NULL;
while(p){
ListNode* temp = p->next;
p->next = q;
q = p;
p = temp;
}
return q;
}
};
思路:控制两个指针一前一后,每走一步改变一次next的赋值,使其指向前方节点,同时另一个指针向后保存断开处下一个指针。
时间复杂度O(N),空间复杂度O(1)
时间间O(n) 空间O(1)
ListNode* reverseList(ListNode* head) {
if(head nullptr || head->next nullptr){
return head;
}
ListNode *res = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return res;
}
时间复杂度o(n) 空间复杂度o(n)
class Solution:
def trainningPlan(self, head: Optional[ListNode]) -> Optional[ListNode]:
temp = None
cur = head
if head None:
return
while(cur):
nex = cur.next
cur.next = temp
temp = cur
cur = nex
return temp
时间复杂度O(n), 空间复杂度O(n)
时间复杂度O(n), 空间复杂度O(n)
还是想不通递归为什么这样写,只能用顺序翻转的方法了
时间复杂度:O(n)
空间复杂度:O(1)
1.建立两个节点,需要一个暂存节点
2.后一个节点指向前一个节点
3.返回pre节点
class Solution {
public:
ListNode* trainningPlan(ListNode* head) {
ListNode *pre = nullptr;
ListNode *cur = head;
while(cur){
ListNode *next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
时间On
class Solution {
public:
};
时间o(n)空间o(1)
//头插法,时间O(N),空间O(1)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode trainningPlan(ListNode head) {
if(head null) {
return head;
}
ListNode p1 = new ListNode(-1);
ListNode cur = head;
ListNode nextListNode = head;
}
a.思路分析
1.设置虚拟头节点dummyHead为null(因为链表的最后一个节点一定为null)。
2.设置一个当前节点cur,以及下一个节点next。
3.将cur指向dummyHead,然后将dummyHead位置更新为cur的位置,cur的位置更新为next的位置。
4.最后一次,因为cur在循环条件nullptr的位置上,而dummyHead指向的是链表最后一个有效节点,因此返回该节点。
b.代码分析:
c.时间复杂度为o(n),n为链表长度;空间复杂度为o(1),使用了常数级别的额外内存。
递归:
class Solution {
public ListNode trainningPlan(ListNode head) {
return reverse2(head);
}
}
思路:1、原地逆转;2、递归
时间:o(n)o(n)
空间:o(1)o(n)
思路:原地反转 使用 头插法
双指针原地反转链表方法
思路:
reverse方法是以head为头节点,end为尾节点的链表,使用了三个指针pre、cur和tmp;pre指针指向的是反转的部分链表的头节点,初始值为end(本题为null);cur指向的是当前正在处理的节点,初始值为head;tmp用于暂时存储cur的下一个节点,防止修改cur.next的指向时出现的链表丢失问题。使用while循环,进行更新,直至cur == end,表明链表反转完成。时间复杂度:O(n),遍历了一次链表。
空间复杂度:O(1),使用了常数级的额外空间。
递归反转链表方法
思路:递归结束条件为当链表为空或只有一个节点时,直接返回当前节点
head;不断的递归,直至head == null || head.next == null,得到从head.next开始反转的链表的头节点newHead;递归到最后,只剩下两个节点, 反转这两个节点即可;最后返回反转后的新链表头节点newHead。时间复杂度:O(n),递归遍历时,每个节点都被访问了一次。
空间复杂度:O(n),递归调用时,栈的深度就是链表的长度。