mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-06 23:28:29 +08:00
Update
This commit is contained in:
@ -65,7 +65,7 @@ fast指针走过的节点数: x + y + n (y + z),n为fast指针在环内走
|
||||
当 n为1的时候,公式就化解为 `x = z`
|
||||
|
||||
|
||||
这就意味着,从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点
|
||||
这就意味着,**从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点**
|
||||
|
||||
|
||||
也就是在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。
|
||||
|
@ -2,9 +2,15 @@
|
||||
|
||||
https://leetcode-cn.com/problems/remove-linked-list-elements/
|
||||
|
||||
## 思路
|
||||
# leetcode:203. 移除链表元素
|
||||
题意:删除链表中等于给定值 val 的所有节点。
|
||||
示例:
|
||||
输入: 1->2->6->3->4->5->6, val = 6
|
||||
输出: 1->2->3->4->5
|
||||
|
||||
我们这里以链表 1 4 2 4 来举例,移除元素4
|
||||
# 思路
|
||||
|
||||
我们这里以链表 1 4 2 4 来举例,移除元素4。
|
||||
|
||||
<img src='../pics/203_链表删除元素1.png' width=600> </img></div>
|
||||
|
||||
@ -14,63 +20,56 @@ https://leetcode-cn.com/problems/remove-linked-list-elements/
|
||||
|
||||
**当然如果使用java ,python的话就不用手动管理内存了。**
|
||||
|
||||
还要说明一下,就算我们使用C++来做leetcode,如果移除一个节点之后,没有手动在内存中删除这个节点,leetcode依然也是可以通过的,只不过,内存使用的空间大一些而已,但建议依然要养生手动清理内存的习惯,因为在面试中 这些细节都是面试官考察的点
|
||||
还要说明一下,就算我们使用C++来做leetcode,如果移除一个节点之后,没有手动在内存中删除这个节点,leetcode依然也是可以通过的,只不过,内存使用的空间大一些而已,但建议依然要养生手动清理内存的习惯。
|
||||
|
||||
这种情况下的移除操作,就是让节点next指针直接指向下下一个节点就可以了,
|
||||
|
||||
那么因为单链表的特殊性,只能指向下一个节点,我们刚刚删除的是 链表的中第二个,和第四个节点,那么如果我们删除的是头结点 又该怎么办呢
|
||||
那么因为单链表的特殊性,只能指向下一个节点,我们刚刚删除的是链表的中第二个,和第四个节点,那么如果我们删除的是头结点又该怎么办呢?
|
||||
|
||||
这里就涉及到 链表操作的两种方式,**一种是 直接使用原来的链表来进行删除操作,一种是设置一个虚拟头结点在进行删除操作。**
|
||||
这里就涉及如下链表操作的两种方式:
|
||||
* **直接使用原来的链表来进行删除操作。**
|
||||
* **设置一个虚拟头结点在进行删除操作。**
|
||||
|
||||
|
||||
|
||||
我们来看第一种操作 直接使用原来的链表来进行移除
|
||||
我们来看第一种操作:直接使用原来的链表来进行移除。
|
||||
|
||||
<img src='../pics/203_链表删除元素3.png' width=600> </img></div>
|
||||
|
||||
移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点
|
||||
移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点。
|
||||
|
||||
所以头结点如何移除呢,其实我们只要 将头结点向后移动一位就可以,这样我们就从链表中移除了一个头结点
|
||||
所以头结点如何移除呢,其实我们只要将头结点向后移动一位就可以,这样我们就从链表中移除了一个头结点。
|
||||
|
||||
<img src='../pics/203_链表删除元素4.png' width=600> </img></div>
|
||||
|
||||
|
||||
依然别忘将原头结点从内存中删掉
|
||||
依然别忘将原头结点从内存中删掉。
|
||||
<img src='../pics/203_链表删除元素5.png' width=600> </img></div>
|
||||
|
||||
|
||||
这样我们移除了一个头结点,是不是发现,在单链表中移除头结点 和 移除其他节点的操作方式是不一样,其实在我们写代码的时候也会发现,需要单独写一段逻辑来处理 移除头结点的情况。
|
||||
这样我们移除了一个头结点,是不是发现,在单链表中移除头结点 和 移除其他节点的操作方式是不一样,其实在我们写代码的时候也会发现,需要单独写一段逻辑来处理移除头结点的情况。
|
||||
|
||||
那么可不可以 以一种统一的逻辑来移除 链表的节点呢。
|
||||
|
||||
其实我们可以设置一个虚拟头结点,这样原链表的所有节点就都可以按照统一的方式进行移除了。
|
||||
其实**可以设置一个虚拟头结点**,这样原链表的所有节点就都可以按照统一的方式进行移除了。
|
||||
|
||||
我们来看看如何设置一个虚拟头。我们依然还是在这个链表中,移除元素1。
|
||||
|
||||
|
||||
<img src='../pics/203_链表删除元素6.png' width=600> </img></div>
|
||||
|
||||
这里我们来给链表添加一个虚拟头结点为新的头结点,此时我们要移除这个旧头结点 元素1,
|
||||
这里我们来给链表添加一个虚拟头结点为新的头结点,此时我们要移除这个旧头结点元素1。
|
||||
|
||||
这样是不是就可以使用 和移除链表其他节点的方式统一了呢
|
||||
这样是不是就可以使用和移除链表其他节点的方式统一了呢?
|
||||
|
||||
大家来看一下,如何移除元素1 呢,还是我们熟悉的方式,然后从内存中删除元素1
|
||||
来看一下,如何移除元素1 呢,还是我们熟悉的方式,然后从内存中删除元素1。
|
||||
|
||||
最后呢在题目中,return 头结点的时候,别让了 `return dummyNode->next;`, 这才是新的头结点
|
||||
最后呢在题目中,return 头结点的时候,别忘了 `return dummyNode->next;`, 这才是新的头结点
|
||||
|
||||
|
||||
## 代码
|
||||
# C++代码
|
||||
|
||||
**直接使用原来的链表来进行移除节点操作:**
|
||||
|
||||
```
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* struct ListNode {
|
||||
* int val;
|
||||
* ListNode *next;
|
||||
* ListNode(int x) : val(x), next(NULL) {}
|
||||
* };
|
||||
*/
|
||||
// 直接使用原来的链表来进行移除节点操作
|
||||
class Solution {
|
||||
public:
|
||||
ListNode* removeElements(ListNode* head, int val) {
|
||||
@ -97,17 +96,9 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
**设置一个虚拟头结点在进行移除节点操作:**
|
||||
|
||||
```
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* struct ListNode {
|
||||
* int val;
|
||||
* ListNode *next;
|
||||
* ListNode(int x) : val(x), next(NULL) {}
|
||||
* };
|
||||
*/
|
||||
// 设置一个虚拟头结点在进行移除节点操作
|
||||
class Solution {
|
||||
public:
|
||||
ListNode* removeElements(ListNode* head, int val) {
|
||||
|
@ -5,9 +5,12 @@ https://leetcode-cn.com/problems/delete-node-in-a-bst/
|
||||
|
||||
平衡二叉树中删除节点有三种情况
|
||||
|
||||
1. 找到删除的节点,其左节点为空,那么就返回其右节点
|
||||
2. 找到删除的节点,其右节点为空,那么就返回其左节点
|
||||
3. 找到删除的节点,左右孩子节点都不为空,则将左孩子放到右孩子的最左面的节点的左孩子上。
|
||||
* 没找到删除的节点,遍历到空节点直接返回了
|
||||
* 找到删除的节点
|
||||
* 左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
|
||||
* 其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
|
||||
* 其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
|
||||
* 左右孩子节点都不为空,则将删除节点的左孩子放到删除节点的右孩子的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
|
||||
|
||||
|
||||
## C++代码
|
||||
@ -18,9 +21,14 @@ public:
|
||||
TreeNode* deleteNode(TreeNode* root, int key) {
|
||||
if (root == NULL) return root;
|
||||
if (root->val == key) {
|
||||
if (root->left == NULL) return root->right; // 第一种情况
|
||||
else if (root->right == NULL) return root->left; // 第二种情况
|
||||
else { // 第三种情况
|
||||
// 第一种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
|
||||
// 第二种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
|
||||
if (root->left == NULL) return root->right;
|
||||
// 第三种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
|
||||
else if (root->right == NULL) return root->left;
|
||||
// 第四种情况:左右孩子节点都不为空,则将删除节点的左孩子放到删除节点的右孩子的最左面节点的左孩子的位置
|
||||
// 返回删除节点右孩子为新的根节点。
|
||||
else {
|
||||
TreeNode* cur = root->right;
|
||||
while(cur->left != NULL) {
|
||||
cur = cur->left;
|
||||
|
@ -3,11 +3,35 @@ https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/
|
||||
|
||||
## 思路
|
||||
|
||||
其实这道题目是一道很简单的题目,**但是题目中的提示:有多种有效的插入方式,还可以重构二叉搜索树,一下子吓退了不少人**,瞬间感觉题目复杂了很多。
|
||||
|
||||
其实**可以不考虑题目中提示所说的改变树的结构的插入方式。**
|
||||
|
||||
如下演示视频中可以看出:只要按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了。
|
||||
|
||||
例如插入元素10 ,需要找到末尾节点插入便可,一样的道理来插入元素15,插入元素0,插入元素6,**需要调整二叉树的结构么? 并不需要。**只需要遍历二叉搜索树,找到空节点 插入元素就可以了, 那么这道题其实就非常简单了。
|
||||
|
||||
<video src='../video/701.二叉搜索树中的插入操作.mp4' controls='controls' width='640' height='320' autoplay='autoplay'> Your browser does not support the video tag.</video></div>
|
||||
|
||||
接下来就是遍历二叉搜索树的过程了。
|
||||
|
||||
代码如下:
|
||||
|
||||
## C++代码
|
||||
|
||||
### 递归
|
||||
```
|
||||
/**
|
||||
* Definition for a binary tree node.
|
||||
* struct TreeNode {
|
||||
* int val;
|
||||
* TreeNode *left;
|
||||
* TreeNode *right;
|
||||
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
|
||||
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
|
||||
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
|
||||
* };
|
||||
*/
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* insertIntoBST(TreeNode* root, int val) {
|
||||
@ -24,6 +48,10 @@ public:
|
||||
|
||||
### 迭代
|
||||
|
||||
在来看看迭代法
|
||||
|
||||
在迭代法遍历的过程中,需要记录一下当前遍历的节点的父节点,这样才能做插入节点的操作。
|
||||
|
||||
```
|
||||
class Solution {
|
||||
public:
|
||||
|
BIN
video/701.二叉搜索树中的插入操作.mp4
Normal file
BIN
video/701.二叉搜索树中的插入操作.mp4
Normal file
Binary file not shown.
Reference in New Issue
Block a user