前言
坚持刷题是一种信念,在找工作强调算法能力的今天,刷题已经成为了我们生活的一部分,无论是为了谋一份工作还是参加算法比赛,我们都需要刷题;这篇文章主要包括了博主对于 链接: Leetcode 206.反转链表 的一些理解以及解答方式,希望能帮到你。
以下是博主对于题目的分析以及解决方法,仅供参考
一、题目描述与分析
题目链接在前言里面提供了,感兴趣的同学可以进去看看。
这个题目是一个经典的链表问题,要求反转一个单链表。这道问题考察了对链表数据结构的理解以及对链表操作的掌握。
这道题是链表操作的基础问题,也是面试中常见的问题之一。解决这个问题需要对链表的节点操作有一定的了解,同时也需要掌握链表的遍历和指针操作技巧。学习和掌握这道题可以帮助加深对链表数据结构的理解,并为解决更复杂的链表问题打下基础。
二、题解以及代码
这里是博主对于题目的分析以及解决方法
这里我提供了三种不同的方法来实现链表的反转:
1、迭代法
思路: 迭代法是通过遍历链表,逐步改变每个节点的指针方向,使其指向前一个节点,从而实现链表的反转。
1)初始化 prev
为 null
,表示反转后的链表头节点是 null
。
2)初始化 current
为输入链表的头节点 head
。
3)进入循环,遍历链表直到 current
变为 null
:
4)在循环内部,首先暂存 current
的下一个节点为 nextTemp
。
5)然后将 current
的 next
指针指向 prev
,这一步实现了反转。
6)更新 prev
为 current
,更新 current
为 nextTemp
,以便下一次迭代。
7)当循环结束后,prev
指向反转后的链表的头节点,返回 prev
作为结果。
复杂度分析:
时间复杂度: O(n),需要遍历整个链表一次。
空间复杂度: O(1),只需要常数级别的额外空间来存储指针。
public ListNode reverseList(ListNode head) {
ListNode prev = null; // 前一个节点初始化为null
ListNode current = head; // 当前节点初始化为链表的头节点
while (current != null) {
ListNode nextTemp = current.next; // 暂存当前节点的下一个节点
current.next = prev; // 将当前节点的指针指向前一个节点,实现反转
prev = current; // 更新前一个节点为当前节点
current = nextTemp; // 更新当前节点为下一个节点
}
return prev; // 最终prev指向新的链表头,返回新链表的头节点
}
2、递归方法
思路:递归法是通过递归调用来实现链表反转,递归的核心思想是将问题拆分为更小的子问题,然后递归地解决这些子问题。
1)如果输入链表为空或只有一个节点,直接返回 head
,不需要进行反转。
2)递归调用 reverseList
函数,传入 head.next
,以便反转后面的链表,将返回结果保存在 newHead
中。
3)将 head.next.next
指向 head
,这一步实现了当前节点的反转。
4)将 head.next
指向 null
,防止形成环。
5)返回 newHead 作为结果,它是反转后的链表的头节点。
复杂度分析:
时间复杂度: O(n),需要递归调用 n 次,每次操作的时间复杂度是常数级别的。
空间复杂度: O(n),递归调用的栈深度为 n,因此空间复杂度是 O(n)。
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; // 将当前节点的指针指向null,防止形成环
return newHead; // 返回新的链表头
}
3、使用栈
思路: 使用栈数据结构来反转链表。首先,将链表的所有节点依次压入栈中,然后从栈中弹出节点,构建一个新的链表,这个新链表就是反转后的链表。
1)如果输入链表为空,直接返回 null
。
2)创建一个栈 stack
,用于存储链表的节点。
3)遍历输入链表,将每个节点依次压入栈 stack
中。
4)弹出栈顶节点,将其作为新链表的头节点,保存在 newHead
中。
5)初始化一个指针 current
,指向 newHead
,用于构建反转后的链表。
6)依次弹出栈中的节点,将其设为 current
的下一个节点,构建反转后的链表。
7)将最后一个节点的 next
指针设置为 null
,以防止形成环。
8)返回 newHead
作为结果,它是反转后的链表的头节点。
复杂度分析:
时间复杂度: O(n),需要遍历链表两次,一次将节点入栈,一次将节点出栈。
空间复杂度: O(n),需要额外的栈空间来存储节点。
public ListNode reverseList(ListNode head) {
if (head == null) {
return null;
}
Stack<ListNode> stack = new Stack<>(); // 使用栈来暂存链表节点
// 将链表节点依次入栈
while (head != null) {
stack.push(head);
head = head.next;
}
ListNode newHead = stack.pop(); // 弹出栈顶节点作为新链表的头节点
ListNode current = newHead;
// 依次弹出栈中的节点,构建反转后的链表
while (!stack.isEmpty()) {
current.next = stack.pop();
current = current.next;
}
current.next = null; // 最后一个节点的next设置为null,防止形成环
return newHead; // 返回新的链表头
}
总结
写题目时的一些想法以及收获
在写这个题目时看见题目就立马想到了迭代法,这个方法是一个非常经典的解决链表反转的方法,在用第二个方法时遇见了一些困难,递归本身就比较难以理解,用栈来解决这个题目也算是比较好理解。
那么今天这篇文章就到此为止了,希望可以帮到你,如果有什么问题可以私聊或者在评论区提出,博主看见了就会回复。