237. 删除链表中的节点
题目描述
基础框架
详细思路
思路一
876. 链表的中间结点
题目描述
基础框架
详细思路
思路一【数组】
思路二【快慢指针】
剑指 Offer 24. 反转链表
题目描述
基础框架
详细思路
思路一【迭代】
思路二【递归】
234. 回文链表
题目描述
基础框架
详细思路
思路一【双指针】
思路二【快慢指针】
1669. 合并两个链表
题目描述
基础框架
详细思路
思路一【快慢指针】
题目描述
请编写一个函数,用于 删除单链表中某个特定节点 。在设计函数时需要注意,你无法访问链表的头节点 head ,只能直接访问 要被删除的节点 。
题目数据保证需要删除的节点 不是末尾节点 。
示例 1:
输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:指定链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9示例 2:
输入:head = [4,5,1,9], node = 1
输出:[4,5,9]
解释:指定链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9提示:
- 链表中节点的数目范围是 [2, 1000]
- -1000 <= Node.val <= 1000
- 链表中每个节点的值都是 唯一 的
- 需要删除的节点 node 是 链表中的节点 ,且 不是末尾节点
基础框架
- C++ 版本给出的基础框架代码如下:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: void deleteNode(ListNode* node) { } };
详细思路
思路一
由于不能访问给定的要删除的结点前一结点,不能采用常见的删除方法。
根据题目提示,要删除的结点不是末尾结点,我们可以对删除结点的下一结点进行操作。
代码演示
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: void deleteNode(ListNode* node) { node->val = node->next->val; node->next = node->next->next; } };
题目描述
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.示例 2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。提示:
- 给定链表的结点数介于 1 和 100 之间。
基础框架
- C++ 版本给出的基础框架代码如下:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* middleNode(ListNode* head) { } };
详细思路
思路一【数组】
遍历链表,将链表内元素存入数组。若数组长度为 A ,则中间结点为 A/2
代码演示
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* middleNode(ListNode* head) { vector
A = {head}; while (A.back()->next != NULL) A.push_back(A.back()->next); return A[A.size() / 2]; } };
思路二【快慢指针】
使用快慢指针,快指针一次走两步,满指针一次走一步。当快指针移动到链表的末尾时,慢指针恰好到链表的中间。
代码演示
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* middleNode(ListNode* head) { ListNode* slow = head; ListNode* fast = head; while (fast != NULL && fast->next != NULL) { slow = slow->next; fast = fast->next->next; } return slow; } };
题目描述
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL限制:
0 <= 节点个数 <= 5000
基础框架
- C++ 版本给出的基础框架代码如下:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* reverseList(ListNode* head) { } };
详细思路
思路一【迭代】
翻转链表只需要把每一个指针的指向反过来就行了,我们定义两个指针,一个指向前一结点,另一个指向当前结点,然后进行反向操作即可。
代码演示
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* reverseList(ListNode* head) { ListNode* prev = nullptr; ListNode* curr = head; while (curr) { ListNode* next = curr->next; curr->next = prev; prev = curr; curr = next; } return prev; } };
思路二【递归】
递归三部曲
- 递归结束条件,
- 找到函数的等价关系式
- 调用函数
(1)当头结点或第二个结点为空的时候,返回头结点
(2)在返回的过程中,让当前结点的下一个结点的next指向当前结点,当前结点的next指向NULL,实现局部翻转。
(3)调用函数
代码演示
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* reverseList(ListNode* head) { if (!head || !head->next) { return head; } ListNode* newHead = reverseList(head->next); head->next->next = head; head->next = nullptr; return newHead; } };
题目描述
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入:head = [1,2,2,1]
输出:true示例 2:
输入:head = [1,2]
输出:false提示:
- 链表中节点数目在范围[1, 105] 内
- 0 <= Node.val <= 9
进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
基础框架
- C++ 版本给出的基础框架代码如下:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: bool isPalindrome(ListNode* head) { } };
详细思路
思路一【双指针】
- 将链表中所有元素存储到容器中
- 使用双指针,判断是否为回文链表
代码演示
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: bool isPalindrome(ListNode* head) { vector
vals; while (head != nullptr) { vals.push_back(head->val); head = head->next; } for (int i = 0, j = vals.size() - 1; i < j; ++i, --j) { if (vals[i] != vals[j]) { return false; } } return true; } };
思路二【快慢指针】
为了避免O(n)的空间复杂度,我们可以改变输入,也就是改变题目所给的链表。
我们将链表的后半部分反转,再与前半部分作比较,判断是否为回文链表
- 使用快慢指针,快指针一次走两步,满指针一次走一步。当快指针移动到链表的末尾时,慢指针恰好到链表的中间。通过慢指针将链表分为两部分。
反转后半部分的链表。
判断是否回文
代码演示
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: bool isPalindrome(ListNode* head) { if (head == nullptr) return true; ListNode* halfNode = halfList(head); ListNode* endNode = reverseList(halfNode->next); ListNode* p1 = head; ListNode* p2 = endNode; while (p2 != nullptr) { if (p1->val != p2->val) { return false; } p1 = p1->next; p2 = p2->next; } return true; } ListNode* halfList(ListNode* head) //快慢指针确立中间结点 { ListNode* fast = head; ListNode* slow = head; while (fast->next != NULL && fast->next->next != NULL) { slow = slow->next; fast = fast->next->next; } return slow; } ListNode* reverseList(ListNode* head) //反转链表 { ListNode* prev = nullptr; ListNode* curr = head; while (curr != nullptr) { ListNode* nextTemp = curr->next; curr->next = prev; prev = curr; curr = nextTemp; } return prev; } };
题目描述
给你两个链表 list1 和 list2 ,它们包含的元素分别为 n 个和 m 个。
请你将 list1 中下标从 a 到 b 的全部节点都删除,并将list2 接在被删除节点的位置。
下图中蓝色边和节点展示了操作后的结果:
请你返回结果链表的头指针。
示例 1:
输入:list1 = [0,1,2,3,4,5], a = 3, b = 4, list2 = [1000000,1000001,1000002]
输出:[0,1,2,1000000,1000001,1000002,5]
解释:我们删除 list1 中下标为 3 和 4 的两个节点,并将 list2 接在该位置。上图中蓝色的边和节点为答案链表。示例 2:
输入:list1 = [0,1,2,3,4,5,6], a = 2, b = 5, list2 = [1000000,1000001,1000002,1000003,1000004]
输出:[0,1,1000000,1000001,1000002,1000003,1000004,6]
解释:上图中蓝色的边和节点为答案链表。提示:
- 3 <= list1.length <= 104
- 1 <= a <= b < list1.length - 1
- 1 <= list2.length <= 104
基础框架
- C++ 版本给出的基础框架代码如下:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* mergeInBetween(ListNode* list1, int a, int b, ListNode* list2) { } };
详细思路
思路一【快慢指针】
- 快指针向前遍历list1,到a点停下,做一个标记
- 快指针继续遍历list1,遍历到b+1点停止,插入list2
- 连接list1的后半部分
代码演示
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* mergeInBetween(ListNode* list1, int a, int b, ListNode* list2) { int fast=0; ListNode*pre=new ListNode(0); ListNode*prehead=pre; pre->next=list1; ListNode*secondhead=list1; while(fast!=a) { fast++; pre=pre->next; } ListNode*first_tail=pre; while(fast!=b+1) { fast++; pre=pre->next; } secondhead=pre->next; ListNode*curr=list2; while(curr->next) { curr=curr->next; } first_tail->next=list2; curr->next=secondhead; return prehead->next; } };