题目描述
解题
实现链表的反转其实不难,一开始想到的是把链表转化为数组,然后将数组元素的值逆序存入新链表中,返回新链表。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null) return head;
ListNode list1 = head,list2 = head;
int len = 0;
while(list1 != null){
list1 = list1.next;
len++;
}
int[] dp = new int[len];
int tag = 0;
while(list2 != null){
dp[tag] = list2.val;
tag++;
list2 = list2.next;
}
ListNode newList = new ListNode(dp[len-1]);
newList.next = null;
ListNode result = newList;
for(int i=len-2;i>=0;i--){
ListNode temp = new ListNode(dp[i]);
temp.next = null;
newList.next = temp;
newList = newList.next;
}
return result;
}
}
这种解题方法直接简单暴力,很容易就想到,没什么技术含量。
接下来看看更加便捷高效的方法:
1.双指针
- 定义两个 ListNode 分别为 pre,cur;pre 在前,cur紧跟在 pre 之后;
- 每次让 pre 的 next 指向 cur,反转 pre 结点;
- pre 结点反转完成后,将 pre 和 cur 同时向前移动一个位置;
- 循环上述过程,直到 pre 到达链表尾部(指向 null)。
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null) return head;
ListNode pre = head,cur = null;
while(pre != null){
ListNode preNext = pre.next;
pre.next = cur;
cur = pre;
pre = preNext;
}
return cur;
}
}
2.递归
递归的关键在于 逆序将节点一个个进行反转。
class Solution {
public ListNode reverseList(ListNode head) {
//递归终止条件:当前head为空或head链表只有一个节点
if(head == null || head.next == null) return head;
//通过递归前往链表的最后一个节点(并且以此节点为返回链表的头节点),并依逆序对每个节点进行反转
ListNode cur = reverseList(head.next);
//将当前节点进行反转(使得当前节点与其next节点成“双链”状态)
// 4 -> 5 变成 4 <=> 5
//ListNode temp = head.next;
//temp.next = head;
head.next.next = head;
//移除当前节点指向其下一个节点(恢复“单链”)
// 4 <=> 5 变成 4 <- 5
head.next = null;
//返回head的最后一个节点
return cur;
}
}
注:可以利用栈先进后出的特性实现链表的反转,实现原理就是把链表节点一个个入栈,当全部入栈完之后再一个个出栈,出栈的时候在把出栈的结点串成一个新的链表。但使用栈实际效果不太好,特别是时耗较高。