文章目录
LC206 反转链表
1.读题
反转一个单链表。
2.题解
【1】解题思路
这里参考王尼玛大佬的题解(这IDemmmm
这个图解超级清晰啊!
感谢大佬!!
方法一 迭代
这里我们用双指针迭代法!
【1】我们要定义两个指针pre
——初始指向nullptr
& cur
——初始指向head
【2】每次让cui
的next
指向pre
——这样就实现了一次局部反转!
【3】每次迭代到cur
就重复【2】操作
然后pre
cur
两个指针都前进一位
【4】迭代完成之后 pre变为最后一个节点
以上四步走省略了一个变量 cur_next
此变量将会将
cur
的下一个节点保存起来!!
我们在代码中会看到这个变量发挥的作用滴~
方法二 递归
简要来说
一次拆掉一个节点并递归处理剩余的子链表
递归法不是很好理解
So——
二刷见
这个坑放在这里!一定要回来填呐!
【2】代码逻辑
方法一 迭代
【1】初始化定义两个指针 一个指向空——pre
一个指向头节点——cur
【2】只要cur
不为空 就一直循环
【3】循环中不断地让cur
指向pre
【3’】并不断将二者前移
方法二 递归
二刷见
3.C++代码
方法一 迭代
超棒的逻辑性!
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre = nullptr;//定义指针pre
ListNode* cur = head;//定义指针cur
while(cur) {
ListNode* cur_next = cur -> next;//创建一个cur_next变量存储cur指针的下一个节点
cur -> next = pre;//cur的next指向pre
pre = cur;//pre往前进一位
cur = cur_next;//cur往前进一位
}
return pre;
}
};
4.Java代码
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
ListNode cur_next = null;
while(cur != null) {
cur_next = cur.next;
cur.next = pre;
pre = cur;//pre前移!
cur = cur_next;//cur前移!
}
return pre;
}
}
LC92 反转链表II
1.读题
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
2.题解
这里挖的坑是 使用头插法一次遍历反转链表!
坐等二刷什么滴
【1】解题思路
参考了LC 木已成舟 大佬的解析
https://leetcode-cn.com/problems/reverse-linked-list-ii/solution/java-shuang-zhi-zhen-tou-cha-fa-by-mu-yi-cheng-zho/
【0】使用虚拟头节点 避免复杂的分类讨论
【1】先定义两个指针 (和LC206一样 )g(guard守卫)
& p(point)
【2】根据 m
确定g
p
的位置 —— 将g
动到第一个要反转的节点前面 将p
移动到第一个要反转的节点的位置上
下面的图解中 以 n=2
m=4
为例
【3】把p后面的元素删除 然后添加到g的后面——“头插法”
【4】根据m
和n
重复步骤 【2】
【5】返回虚拟头节点指向的内容(即为反转好的链表)
【2】代码逻辑
【1】定义虚拟头节点
【2】初始化指针
(根据虚拟头节点)
【3】让g达到第一个要反转的节点前面
让p达到第一个要反转的节点位置
这是本题的核心思想!!!!
肥肠重要!!
【4】头插法插入节点 达到反转的效果
这一步的操作关键是删除p后面的元素然后添加到g的后面
【5】最后输出虚拟头节点指向的链表即可
3.C++代码
与JAVA版本的几乎一致哦~
二刷仔细多看几遍 ~
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
int pos = 1;
ListNode* dummyNode = new ListNode(0);
dummyNode->next = head;
ListNode* pre = dummyNode;
ListNode* cur = head;
while(cur && pos < left) {
pre = pre -> next;
cur = cur -> next;
pos ++;
}
ListNode* tailNode = cur;
while(cur && pos <= right) {
ListNode* removed = cur -> next;
cur -> next = pre -> next;
pre -> next = cur;
tailNode->next = removed;
cur = removed;
pos ++;
}
return dummyNode->next;
}
};
4.Java代码
详细得就离谱!
看不懂你来找我!!
(结合着上面的图)
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode dummyNode = new ListNode(0);
//因为头节点可能会发生变化 所以使用虚拟头节点可以避免复杂的分类讨论
dummyNode.next = head;//虚拟头节点指向头节点
ListNode g = dummyNode;
ListNode p = dummyNode.next;//初始化两个指针(LC206中熟悉的操作鸭)
for (int step = 0; step < m - 1; step++) {
//第一步
//g从虚拟头节点走m-1步 来到m节点的前一个节点————即第一个要反转的节点的前面
//p从虚拟头节点的下一个位置走m-1步 来到m节点
g = g.next;
p = p.next;
}
//第二步
//头插法插入节点
for (int i = 0; i < n-m; i++){
//【1】定义删除p后面的节点 为 removed
ListNode removed = p.next;
//【2】p指向删除掉元素的下一个节点
p.next = p.next.next;
//【3】删除节点指向p节点(也就是g.next)
removed.next = g.next;
//【4】最后一步 将g与删除节点连接起来
g.next = removed;
}
return dummyNode.next;
}
}
5.本题收获
1.链表中通过步长做标准——访问到特定的那个节点