难度简单205
目录
刷题日期:20:5635 星期二2021年3月30日
个人刷题记录,代码收集,来源皆为leetcode
经过多方讨论和请教,现在打算往Java方向发力
主要答题语言为Java
题目:
剑指 Offer 24. 反转链表
难度简单 205
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
限制:
0 <= 节点个数 <= 5000
题目分析
因为链表的性质,如果是单向链表的话,是不能往前搜索的,所以乍一想只能新建一个链表,然后以特殊的形式把数据又后往前存储的新链表里。
或者参考书里的思路,想办法让每个指针都指向前面的数据,这期间需要防止链表断开。
初始解答:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
//设想需要三个指针分别指向前中后
ListNode pAhead = null, pCur = head, pBehind = null;
if (head == null || head.next == null) return head; //特殊情况
while (pCur.next != null) {
pBehind = pCur.next;
pCur.next = pAhead;
pAhead = pCur;
pCur = pBehind;
// pBehind.next = pCur;
}
pBehind.next = pAhead;
return pBehind;
}
}
提交了几次分别卡在空链表和单个链表的输入,加入考虑特殊情况的if判断后实现了功能,值得深思考虑。
执行结果: 通过
显示详情
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.2 MB, 在所有 Java 提交中击败了67.03%的用户
学习K神的迭代写法,最后发现自己想的其实大差不差的,一个临时变量又减少了空间占用,性能更好了。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
//设想需要三个指针分别指向前中后
ListNode pAhead = null, pCur = head; //其实两个常用就够了
// if (head == null || head.next == null) return head; //特殊情况
while (pCur != null) {
ListNode pBehind = pCur.next; //存后继节点
pCur.next = pAhead; //前面指向
pAhead = pCur; //前面指中
pCur = pBehind; //中访问下一节点
}
return pAhead;
}
}
执行结果:通过
显示详情
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:37.9 MB, 在所有 Java 提交中击败了94.37%的用户
递归写法也尝试了下,和他人的差不多:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
return recur(head,null); //直接进入递归,null是结果的最后一个值
}
private ListNode recur(ListNode cur, ListNode pre) {
if (cur == null) return pre; //遇到说明已经到底了,示例输入时pre=5
ListNode res = recur(cur.next, cur); //递归代码,不断访问下一套
cur.next = pre; //修改指向
return res; //返回当前指向的下一个
}
}
执行结果: 通过
显示详情
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38 MB, 在所有 Java 提交中击败了93.26%的用户
学习他人:
方法一:
2020-07-16
/**
* 迭代法
*/
public ListNode reverseList_1(ListNode head) {
ListNode newHead = null;
while (head != null){
ListNode temp = head.next;
head.next = newHead;
newHead = head;
head = temp;
}
return newHead;
}
/**
* 递归法
*/
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
/**
* 借助栈
*/
public ListNode reverseList_stack(ListNode head) {
if (head == null) return head;
Stack<ListNode> stack = new Stack<>();
while (head!=null){
stack.push(head);
head = head.next;
}
ListNode newHead = stack.pop();
ListNode tailNode = newHead;
while (!stack.isEmpty()){
ListNode cur = stack.pop();
tailNode.next = cur;
tailNode = cur;
}
tailNode.next = null;
return newHead;
}
方法二:
K神
作者:jyd
链接:https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/solution/jian-zhi-offer-24-fan-zhuan-lian-biao-die-dai-di-2/
来源:力扣(LeetCode)
方法一:迭代(双指针)
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head, pre = null;
while(cur != null) {
ListNode tmp = cur.next; // 暂存后继节点 cur.next
cur.next = pre; // 修改 next 引用指向
pre = cur; // pre 暂存 cur
cur = tmp; // cur 访问下一节点
}
return pre;
}
}
利用 Python 语言的平行赋值语法,可以进一步简化代码(但可读性下降):
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
cur, pre = head, None
while cur:
cur.next, pre, cur = pre, cur, cur.next
return pre
递归
class Solution {
public ListNode reverseList(ListNode head) {
return recur(head, null); // 调用递归并返回
}
private ListNode recur(ListNode cur, ListNode pre) {
/*
本递归方法返回的永远是最后一个节点,无论是哪一层递归
*/
if (cur == null) return pre; // 终止条件,这里的pre是最后一个节点
ListNode res = recur(cur.next, cur); // 递归后继节点,res是最后一个节点
cur.next = pre;//注意此pre一直在变化
return res; // 返回反转链表的头节点,返回最后一个节点res
}
}
总结
以上就是本题的内容和学习过程了,就递归和迭代两种解法,需要考虑边界输入,都值得学习,自己理清思路。
欢迎讨论,共同进步。