题目链接:JZ24:反转链表
题目描述:
给定一个单链表的头结点head(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
数据范围:
0
≤
n
≤
10000
0\leq n\leq10000
0≤n≤10000
要求:空间复杂度
O
(
1
)
O(1)
O(1) ,时间复杂度
O
(
n
)
O(n)
O(n) 。
解题思路:
①借助傀儡结点newHead,记录链表的头结点,增加一个headNext保存head的后一个结点。时间复杂度
O
(
n
)
O(n)
O(n) ,空间复杂度
O
(
1
)
O(1)
O(1)
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode ReverseList(ListNode head) {
//新增一个傀儡结点newHead,增加一个headNext记录head的下一个结点
ListNode newHead = new ListNode(0);
ListNode headNext = null;
while(head!=null){
headNext = head.next; //每次先记录后一个结点
head.next = newHead.next; //头插法
newHead.next = head;
head = headNext;
}
return newHead.next; //返回傀儡结点的下一个位置
}
}
② 用栈解决。将链表中的结点依次入栈,出栈时将结点串成一个新的链表。注意出栈时代码的写法,我们需要先将第一个出栈元素作为newHead结点,当循环出栈结束后,要将最后一个元素(即原链表的首元素)的next置空!
时间复杂度
O
(
n
)
O(n)
O(n) ,空间复杂度
O
(
n
)
O(n)
O(n)
import java.util.Stack;
import java.util.LinkedList;
public class Solution {
public ListNode ReverseList(ListNode head) {
Stack<ListNode> stack = new Stack<>();
while(head!=null){
stack.push(head);
head = head.next;
}
LinkedList<ListNode> ret = new LinkedList<>();
if(stack.isEmpty()){
return null;
}
ListNode node = stack.pop(); //node记录新链表的尾结点
ListNode newHead= node; //先确定链表新的头结点
while(!stack.isEmpty()){
ListNode tempNode = stack.pop();
node.next = tempNode;
node = node.next;
}
//将最后一个结点的next置空(是原来链表的头结点)
node.next=null;
return newHead;
}
}
③递归方法:时间复杂度
O
(
n
)
O(n)
O(n) ,空间复杂度
O
(
n
)
O(n)
O(n)
终止条件:headnull || head.nextnull
迭代逻辑:让当前迭代下的head下一个结点指向自己,head.next==null 防止产生环链。
递归调用
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode ret = ReverseList(head.next);
head.next.next = head; //后一个结点指向前一个结点
head.next = null; //放置产生环链
return ret;
}
}
总结:以上链表反转采用了借助傀儡结点、栈、以及递归方法,时间复杂度都为O(n),但是针对不同的方法空间复杂度是不一样的,具体情况具体分析。还有一些其他的方法,如双指针、头插…要及时复习。图多画几遍理解!加油!