当你穿过了暴风雨,你已不是原来那个人
—— 24.9.21
206. 反转链表
给你单链表的头节点
head
,请你反转链表,并返回反转后的链表。示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]示例 2:
输入:head = [1,2] 输出:[2,1]示例 3:
输入:head = [] 输出:[]提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
方法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; }
* }
*/
public ListNode reverseList(ListNode head) {
ListNode prev = null;
while (head != null) {
prev = new ListNode(head.val, prev);
head = head.next;
}
return prev;
}
方法2
与方法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 reverseList(ListNode head) {
List list1 = new List(head);
List list2 = new List(null);
while (head != null) {
ListNode remove = list1.removeFirst();
if (remove == null){
break;
}
list2.addFirst(remove);
}
return list2.head;
}
static class List {
ListNode head;
public List(ListNode head) {
this.head = head;
}
public void addFirst(ListNode First){
First.next = head;
head = First;
}
public ListNode removeFirst(){
if (head == null){
return null;
}
ListNode thanRemove = head;
head = head.next;
return thanRemove;
}
}
}
方法3
用递归的方法,直接将链表进行翻转
注意:if的判断要左边先进行head是否为空的判断,在进行head.next是否为空的判断,否则力扣判题系统会进行报错,提示程序试图在 null 对象上调用方法或访问字段
/**
* 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 reverseList(ListNode head) {
if (head == null || head.next == null){
// 找到了最后一个节点
return head;
}
ListNode last = reverseList(head.next);
head.next.next = head;
head.next = null;
return last;
}
}
方法4
从链表每次拿到第二个节点,将其从链表断开,插入头部,直至它为 null 结束
1.设置指针 old1(旧头)、new1(新头)、old2(旧老二),分别指向第一,第一,第二节点
new1old1(1)—>old2(2)—>3—>4—>5—>null
2.将 old2 节点从链表断开,即 old1 节点指向第三节点
new1old1(1)—>3—>4—>5—>null;old2(2)
3.old2 节点链入链表头部,即
old2(2)—>new1old1(1)->3—>4—>5—>null
4.new1 指向 old2
new1old2(2) —>old1(1) —>3—>4—>5—>null
5.old2 指向 old1 的下一个节点,即
new1(2)—>old1(1)—>old2(3)—>4—>5—>null
6.重复以上 2 ~ 5 步,直到 old2 指向 null
7.还应当考虑边界条件,即链表中不满两个元素时,无需走以上逻辑
// 方法4 原始链表设置新旧两个指针进行复制
public ListNode reverseList4(ListNode old1) {
if (old1 == null || old1.next == null){
return old1;
}
// 每次把原始链表的第二个结点剪切放到新链表的头部,当旧链表的第二个结点为null时,结束
ListNode old2 = old1.next;
ListNode new1 = old1;
while (old2 != null) {
old1.next = old2.next;
old2.next = new1;
new1 = old2;
old2 = old1.next;
}
return new1;
}
方法5
要点:把链表分成两部分,思路就是不断从链表2的头,往链表1的头搬移
1.new1 指向 null,代表新链表一开始没有元素,old1 指向原链表的首节点
new1(null),o1(1)—>2—>3—>4—>5—>null
2.开始循环,old2指向原链表次结点
new1(null),old1(1)—>old2(2)—>3—>4—>5—>null
3.挪移
old1(1)—>new1(null),old2(2)—>3—>4—>5—>null
4.指针复位
new(1)—>null,new1 old2(2)—>3—>4—>5—>null
5.重复2~4步
6.当old1 = null时,退出循环
// 方法5 面向过程同一链表互换
public ListNode reverseList5(ListNode old1) {
if (old1 == null || old1.next == null){
return old1;
}
ListNode new1 = null;
while (old1 != null) {
ListNode old2 = old1.next;
old1.next = new1;
new1 = old1;
old1 = old2;
}
return new1;
}