mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-09 19:44:45 +08:00
Merge remote-tracking branch 'upstream/master' into feature-0077
This commit is contained in:
@ -3,7 +3,8 @@
|
||||
> 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者)
|
||||
> 2. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ) 。
|
||||
> 3. **学习社区** : 一起学习打卡/面试技巧/如何选择offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入[「代码随想录」学习社区](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) 。
|
||||
> 4. **转载须知** :以下所有文章皆为我([程序员Carl](https://github.com/youngyangyang04))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!
|
||||
> 4. **提交代码**:本项目统一使用C++语言进行讲解,但已经有Java、Python、Go、JavaScript等等多语言版本,感谢[这里的每一位贡献者](https://github.com/youngyangyang04/leetcode-master/graphs/contributors),如果你也想贡献代码点亮你的头像,[点击这里](https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A)了解提交代码的方式。
|
||||
> 5. **转载须知** :以下所有文章皆为我([程序员Carl](https://github.com/youngyangyang04))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/youngyangyang04/leetcode-master" target="_blank">
|
||||
@ -409,6 +410,10 @@
|
||||
|
||||
(持续更新中....)
|
||||
|
||||
# 贡献者
|
||||
|
||||
你可以[点此链接](https://github.com/youngyangyang04/leetcode-master/graphs/contributors)查看LeetCode-Master的所有贡献者。感谢你们补充了LeetCode-Master的其他语言版本,让更多的读者收益于此项目。
|
||||
|
||||
# 关于作者
|
||||
|
||||
大家好,我是程序员Carl,哈工大师兄,ACM 校赛、黑龙江省赛、东北四省赛金牌、亚洲区域赛铜牌获得者,先后在腾讯和百度从事后端技术研发,CSDN博客专家。对算法和C++后端技术有一定的见解,利用工作之余重新刷leetcode。
|
||||
@ -420,7 +425,7 @@
|
||||
<a name="微信"></a>
|
||||
<img src="https://img-blog.csdnimg.cn/20200814140330894.png" data-img="1" width="175" height="175">
|
||||
|
||||
# 我的公众号
|
||||
# 公众号
|
||||
|
||||
更多精彩文章持续更新,微信搜索:「代码随想录」第一时间围观,关注后回复:「666」可以获得所有算法专题原创PDF。
|
||||
|
||||
|
@ -37,9 +37,9 @@ https://leetcode-cn.com/problems/two-sum/
|
||||
本题呢,则要使用map,那么来看一下使用数组和set来做哈希法的局限。
|
||||
|
||||
* 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
|
||||
* set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下表位置,因为要返回x 和 y的下表。所以set 也不能用。
|
||||
* set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。
|
||||
|
||||
此时就要选择另一种数据结构:map ,map是一种key value的存储结构,可以用key保存数值,用value在保存数值所在的下表。
|
||||
此时就要选择另一种数据结构:map ,map是一种key value的存储结构,可以用key保存数值,用value在保存数值所在的下标。
|
||||
|
||||
C++中map,有三种类型:
|
||||
|
||||
@ -156,6 +156,21 @@ impl Solution {
|
||||
}
|
||||
```
|
||||
|
||||
Javascript
|
||||
|
||||
```javascript
|
||||
var twoSum = function (nums, target) {
|
||||
let hash = {};
|
||||
for (let i = 0; i < nums.length; i++) {
|
||||
if (hash[target - nums[i]] !== undefined) {
|
||||
return [i, hash[target - nums[i]]];
|
||||
}
|
||||
hash[nums[i]] = i;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -247,6 +247,32 @@ def is_valid(strs)
|
||||
end
|
||||
```
|
||||
|
||||
Javascript:
|
||||
```javascript
|
||||
var isValid = function (s) {
|
||||
const stack = [];
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
let c = s[i];
|
||||
switch (c) {
|
||||
case '(':
|
||||
stack.push(')');
|
||||
break;
|
||||
case '[':
|
||||
stack.push(']');
|
||||
break;
|
||||
case '{':
|
||||
stack.push('}');
|
||||
break;
|
||||
default:
|
||||
if (c !== stack.pop()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return stack.length === 0;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||
|
@ -132,6 +132,21 @@ Python:
|
||||
|
||||
Go:
|
||||
|
||||
Javascript:
|
||||
```javascript
|
||||
var swapPairs = function (head) {
|
||||
let ret = new ListNode(0, head), temp = ret;
|
||||
while (temp.next && temp.next.next) {
|
||||
let cur = temp.next.next, pre = temp.next;
|
||||
pre.next = cur.next;
|
||||
cur.next = pre;
|
||||
temp.next = cur;
|
||||
temp = pre;
|
||||
}
|
||||
return ret.next;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||
|
@ -207,7 +207,8 @@ func backtrack(nums,pathNums []int,used []bool){
|
||||
}
|
||||
|
||||
Javascript:
|
||||
```Javascript
|
||||
|
||||
```javascript
|
||||
|
||||
var permute = function(nums) {
|
||||
let result = []
|
||||
|
@ -220,6 +220,43 @@ class Solution:
|
||||
return res
|
||||
```
|
||||
|
||||
Javascript:
|
||||
|
||||
```javascript
|
||||
|
||||
var permuteUnique = function (nums) {
|
||||
nums.sort((a, b) => {
|
||||
return a - b
|
||||
})
|
||||
let result = []
|
||||
let path = []
|
||||
|
||||
function backtracing( used) {
|
||||
if (path.length === nums.length) {
|
||||
result.push(path.slice())
|
||||
return
|
||||
}
|
||||
for (let i = 0; i < nums.length; i++) {
|
||||
if (i > 0 && nums[i] === nums[i - 1] && !used[i - 1]) {
|
||||
continue
|
||||
}
|
||||
if (!used[i]) {
|
||||
used[i] = true
|
||||
path.push(nums[i])
|
||||
backtracing(used)
|
||||
path.pop()
|
||||
used[i] = false
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
backtracing([])
|
||||
return result
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -122,6 +122,24 @@ class Solution:
|
||||
```
|
||||
|
||||
Go:
|
||||
```Go
|
||||
func canJUmp(nums []int) bool {
|
||||
if len(nums)<=1{
|
||||
return true
|
||||
}
|
||||
dp:=make([]bool,len(nums))
|
||||
dp[0]=true
|
||||
for i:=1;i<len(nums);i++{
|
||||
for j:=i-1;j>=0;j--{
|
||||
if dp[j]&&nums[j]+j>=i{
|
||||
dp[i]=true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[len(nums)-1]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -336,8 +336,26 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
//递归法
|
||||
class Solution:
|
||||
def isValidBST(self, root: TreeNode) -> bool:
|
||||
res = [] //把二叉搜索树按中序遍历写成list
|
||||
def buildalist(root):
|
||||
if not root: return
|
||||
buildalist(root.left) //左
|
||||
res.append(root.val) //中
|
||||
buildalist(root.right) //右
|
||||
return res
|
||||
buildalist(root)
|
||||
return res == sorted(res) and len(set(res)) == len(res) //检查list里的数有没有重复元素,以及是否按从小到大排列
|
||||
```
|
||||
Go:
|
||||
```Go
|
||||
import "math"
|
||||
|
@ -687,6 +687,26 @@ func levelOrder(root *TreeNode) [][]int {
|
||||
return result
|
||||
}
|
||||
```
|
||||
Javascript:
|
||||
```javascript
|
||||
var levelOrder = function (root) {
|
||||
let ans = [];
|
||||
if (!root) return ans;
|
||||
let queue = [root];
|
||||
while (queue.length) {
|
||||
let size = queue.length;
|
||||
let temp = [];
|
||||
while (size--) {
|
||||
let n = queue.shift();
|
||||
temp.push(n.val);
|
||||
if (n.left) queue.push(n.left);
|
||||
if (n.right) queue.push(n.right);
|
||||
}
|
||||
ans.push(temp);
|
||||
}
|
||||
return ans;
|
||||
};
|
||||
```
|
||||
|
||||
-----------------------
|
||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||
|
@ -618,8 +618,42 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
|
||||
105.从前序与中序遍历序列构造二叉树
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
//递归法
|
||||
class Solution:
|
||||
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
|
||||
if not preorder: return None //特殊情况
|
||||
root = TreeNode(preorder[0]) //新建父节点
|
||||
p=inorder.index(preorder[0]) //找到父节点在中序遍历的位置(因为没有重复的元素,才可以这样找)
|
||||
root.left = self.buildTree(preorder[1:p+1],inorder[:p]) //注意左节点时分割中序数组和前续数组的开闭环
|
||||
root.right = self.buildTree(preorder[p+1:],inorder[p+1:]) //分割中序数组和前续数组
|
||||
return root
|
||||
```
|
||||
106.从中序与后序遍历序列构造二叉树
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
//递归法
|
||||
class Solution:
|
||||
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
|
||||
if not postorder: return None //特殊情况
|
||||
root = TreeNode(postorder[-1]) //新建父节点
|
||||
p=inorder.index(postorder[-1]) //找到父节点在中序遍历的位置*因为没有重复的元素,才可以这样找
|
||||
root.left = self.buildTree(inorder[:p],postorder[:p]) //分割中序数组和后续数组
|
||||
root.right = self.buildTree(inorder[p+1:],postorder[p:-1]) //注意右节点时分割中序数组和后续数组的开闭环
|
||||
return root
|
||||
```
|
||||
Go:
|
||||
|
||||
|
||||
|
@ -302,6 +302,53 @@ class Solution:
|
||||
Go:
|
||||
|
||||
|
||||
JavaScript:
|
||||
|
||||
递归法:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @param {TreeNode} root
|
||||
* @return {number}
|
||||
*/
|
||||
var minDepth1 = function(root) {
|
||||
if(!root) return 0;
|
||||
// 到叶子节点 返回 1
|
||||
if(!root.left && !root.right) return 1;
|
||||
// 只有右节点时 递归右节点
|
||||
if(!root.left) return 1 + minDepth(root.right);、
|
||||
// 只有左节点时 递归左节点
|
||||
if(!root.right) return 1 + minDepth(root.left);
|
||||
return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
|
||||
};
|
||||
```
|
||||
|
||||
迭代法:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @param {TreeNode} root
|
||||
* @return {number}
|
||||
*/
|
||||
var minDepth = function(root) {
|
||||
if(!root) return 0;
|
||||
const queue = [root];
|
||||
let dep = 0;
|
||||
while(true) {
|
||||
let size = queue.length;
|
||||
dep++;
|
||||
while(size--){
|
||||
const node = queue.shift();
|
||||
// 到第一个叶子节点 返回 当前深度
|
||||
if(!node.left && !node.right) return dep;
|
||||
node.left && queue.push(node.left);
|
||||
node.right && queue.push(node.right);
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -348,25 +348,29 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
0112.路径总和
|
||||
```python
|
||||
// 递归法
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
|
||||
// 递归法
|
||||
|
||||
class Solution:
|
||||
def hasPathSum(self, root: TreeNode, targetSum: int) -> bool:
|
||||
def isornot(root,targetSum)->bool:
|
||||
if (not root.left) and (not root.right) and targetSum == 0:return True // 遇到叶子节点,并且计数为0
|
||||
if (not root.left) and (not root.right):return False //遇到叶子节点,计数不为0
|
||||
if root.left:
|
||||
targetSum -= root.left.val //只有左节点
|
||||
if isornot(root.left,targetSum):return True //递归,处理节点
|
||||
targetSum -= root.left.val //左节点
|
||||
if isornot(root.left,targetSum):return True //递归,处理左节点
|
||||
targetSum += root.left.val //回溯
|
||||
if root.right:
|
||||
targetSum -= root.right.val //只有右节点
|
||||
targetSum -= root.right.val //右节点
|
||||
if isornot(root.right,targetSum):return True //递归,处理右节点
|
||||
targetSum += root.right.val //回溯
|
||||
return False
|
||||
@ -374,6 +378,46 @@ class Solution:
|
||||
if root == None:return False //别忘记处理空TreeNode
|
||||
else:return isornot(root,targetSum-root.val)
|
||||
```
|
||||
|
||||
0113.路径总和-ii
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
//递归法
|
||||
class Solution:
|
||||
def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
|
||||
path=[]
|
||||
res=[]
|
||||
def pathes(root,targetSum):
|
||||
if (not root.left) and (not root.right) and targetSum == 0: // 遇到叶子节点,并且计数为0
|
||||
res.append(path[:]) //找到一种路径,记录到res中,注意必须是path[:]而不是path
|
||||
return
|
||||
if (not root.left) and (not root.right):return // 遇到叶子节点直接返回
|
||||
if root.left: //左
|
||||
targetSum -= root.left.val
|
||||
path.append(root.left.val) //递归前记录节点
|
||||
pathes(root.left,targetSum) //递归
|
||||
targetSum += root.left.val //回溯
|
||||
path.pop() //回溯
|
||||
if root.right: //右
|
||||
targetSum -= root.right.val
|
||||
path.append(root.right.val) //递归前记录节点
|
||||
pathes(root.right,targetSum) //递归
|
||||
targetSum += root.right.val //回溯
|
||||
path.pop() //回溯
|
||||
return
|
||||
|
||||
if root == None:return [] //处理空TreeNode
|
||||
else:
|
||||
path.append(root.val) //首先处理根节点
|
||||
pathes(root,targetSum-root.val)
|
||||
return res
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
JavaScript:
|
||||
|
@ -196,9 +196,9 @@ public:
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
Java:
|
||||
```java
|
||||
// 贪心思路
|
||||
class Solution {
|
||||
public int maxProfit(int[] prices) {
|
||||
int minprice = Integer.MAX_VALUE;
|
||||
@ -215,6 +215,33 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
``` java
|
||||
class Solution { // 动态规划解法
|
||||
public int maxProfit(int[] prices) {
|
||||
// 可交易次数
|
||||
int k = 1;
|
||||
// [天数][交易次数][是否持有股票]
|
||||
int[][][] dp = new int[prices.length][k + 1][2];
|
||||
|
||||
// bad case
|
||||
dp[0][0][0] = 0;
|
||||
dp[0][0][1] = Integer.MIN_VALUE;
|
||||
dp[0][1][0] = Integer.MIN_VALUE;
|
||||
dp[0][1][1] = -prices[0];
|
||||
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
for (int j = k; j >= 1; j--) {
|
||||
// dp公式
|
||||
dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
|
||||
dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return dp[prices.length - 1][k][0] > 0 ? dp[prices.length - 1][k][0] : 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
|
||||
|
@ -133,9 +133,10 @@ public:
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
// 贪心思路
|
||||
class Solution {
|
||||
public int maxProfit(int[] prices) {
|
||||
int sum = 0;
|
||||
@ -153,6 +154,29 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
class Solution { // 动态规划
|
||||
public int maxProfit(int[] prices) {
|
||||
// [天数][是否持有股票]
|
||||
int[][] dp = new int[prices.length][2];
|
||||
|
||||
// bad case
|
||||
dp[0][0] = 0;
|
||||
dp[0][1] = -prices[0];
|
||||
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
// dp公式
|
||||
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
|
||||
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
|
||||
}
|
||||
|
||||
return dp[prices.length - 1][0];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
Python:
|
||||
```python
|
||||
class Solution:
|
||||
|
@ -190,9 +190,42 @@ dp[1] = max(dp[1], dp[0] - prices[i]); 如果dp[1]取dp[1],即保持买入股
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
class Solution { // 动态规划
|
||||
public int maxProfit(int[] prices) {
|
||||
// 可交易次数
|
||||
int k = 2;
|
||||
|
||||
// [天数][交易次数][是否持有股票]
|
||||
int[][][] dp = new int[prices.length][k + 1][2];
|
||||
|
||||
// badcase
|
||||
dp[0][0][0] = 0;
|
||||
dp[0][0][1] = Integer.MIN_VALUE;
|
||||
dp[0][1][0] = 0;
|
||||
dp[0][1][1] = -prices[0];
|
||||
dp[0][2][0] = 0;
|
||||
dp[0][2][1] = Integer.MIN_VALUE;
|
||||
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
for (int j = 2; j >= 1; j--) {
|
||||
// dp公式
|
||||
dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
|
||||
dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
for (int i = 1; i < 3; i++) {
|
||||
res = Math.max(res, dp[prices.length - 1][i][0]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Python:
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
输入:k = 2, prices = [3,2,6,5,0,3]
|
||||
输出:7
|
||||
解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4。随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
|
||||
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
@ -167,9 +167,48 @@ public:
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
class Solution { //动态规划
|
||||
public int maxProfit(int k, int[] prices) {
|
||||
if (prices == null || prices.length < 2 || k == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// [天数][交易次数][是否持有股票]
|
||||
int[][][] dp = new int[prices.length][k + 1][2];
|
||||
|
||||
// bad case
|
||||
dp[0][0][0] = 0;
|
||||
dp[0][0][1] = Integer.MIN_VALUE;
|
||||
dp[0][1][0] = 0;
|
||||
dp[0][1][1] = -prices[0];
|
||||
// dp[0][j][0] 都均为0
|
||||
// dp[0][j][1] 异常值都取Integer.MIN_VALUE;
|
||||
for (int i = 2; i < k + 1; i++) {
|
||||
dp[0][i][0] = 0;
|
||||
dp[0][i][1] = Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
for (int j = k; j >= 1; j--) {
|
||||
// dp公式
|
||||
dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
|
||||
dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
for (int i = 1; i < k + 1; i++) {
|
||||
res = Math.max(res, dp[prices.length - 1][i][0]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Python:
|
||||
|
||||
|
@ -156,6 +156,7 @@ public:
|
||||
|
||||
Java:
|
||||
|
||||
使用两个 Queue 实现
|
||||
```java
|
||||
class MyStack {
|
||||
|
||||
@ -205,7 +206,94 @@ class MyStack {
|
||||
* boolean param_4 = obj.empty();
|
||||
*/
|
||||
```
|
||||
使用两个 Deque 实现
|
||||
```java
|
||||
class MyStack {
|
||||
// Deque 接口继承了 Queue 接口
|
||||
// 所以 Queue 中的 add、poll、peek等效于 Deque 中的 addLast、pollFirst、peekFirst
|
||||
Deque<Integer> que1; // 和栈中保持一样元素的队列
|
||||
Deque<Integer> que2; // 辅助队列
|
||||
/** Initialize your data structure here. */
|
||||
public MyStack() {
|
||||
que1 = new ArrayDeque<>();
|
||||
que2 = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
/** Push element x onto stack. */
|
||||
public void push(int x) {
|
||||
que1.addLast(x);
|
||||
}
|
||||
|
||||
/** Removes the element on top of the stack and returns that element. */
|
||||
public int pop() {
|
||||
int size = que1.size();
|
||||
size--;
|
||||
// 将 que1 导入 que2 ,但留下最后一个值
|
||||
while (size-- > 0) {
|
||||
que2.addLast(que1.peekFirst());
|
||||
que1.pollFirst();
|
||||
}
|
||||
|
||||
int res = que1.pollFirst();
|
||||
// 将 que2 对象的引用赋给了 que1 ,此时 que1,que2 指向同一个队列
|
||||
que1 = que2;
|
||||
// 如果直接操作 que2,que1 也会受到影响,所以为 que2 分配一个新的空间
|
||||
que2 = new ArrayDeque<>();
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Get the top element. */
|
||||
public int top() {
|
||||
return que1.peekLast();
|
||||
}
|
||||
|
||||
/** Returns whether the stack is empty. */
|
||||
public boolean empty() {
|
||||
return que1.isEmpty();
|
||||
}
|
||||
}
|
||||
```
|
||||
优化,使用一个 Deque 实现
|
||||
```java
|
||||
class MyStack {
|
||||
// Deque 接口继承了 Queue 接口
|
||||
// 所以 Queue 中的 add、poll、peek等效于 Deque 中的 addLast、pollFirst、peekFirst
|
||||
Deque<Integer> que1;
|
||||
/** Initialize your data structure here. */
|
||||
public MyStack() {
|
||||
que1 = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
/** Push element x onto stack. */
|
||||
public void push(int x) {
|
||||
que1.addLast(x);
|
||||
}
|
||||
|
||||
/** Removes the element on top of the stack and returns that element. */
|
||||
public int pop() {
|
||||
int size = que1.size();
|
||||
size--;
|
||||
// 将 que1 导入 que2 ,但留下最后一个值
|
||||
while (size-- > 0) {
|
||||
que1.addLast(que1.peekFirst());
|
||||
que1.pollFirst();
|
||||
}
|
||||
|
||||
int res = que1.pollFirst();
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Get the top element. */
|
||||
public int top() {
|
||||
return que1.peekLast();
|
||||
}
|
||||
|
||||
/** Returns whether the stack is empty. */
|
||||
public boolean empty() {
|
||||
return que1.isEmpty();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
|
@ -131,6 +131,101 @@ public:
|
||||
|
||||
Java:
|
||||
|
||||
使用Stack(堆栈)同名方法:
|
||||
```java
|
||||
class MyQueue {
|
||||
// java中的 Stack 有设计上的缺陷,官方推荐使用 Deque(双端队列) 代替 Stack
|
||||
Deque<Integer> stIn;
|
||||
Deque<Integer> stOut;
|
||||
/** Initialize your data structure here. */
|
||||
public MyQueue() {
|
||||
stIn = new ArrayDeque<>();
|
||||
stOut = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
/** Push element x to the back of queue. */
|
||||
public void push(int x) {
|
||||
stIn.push(x);
|
||||
}
|
||||
|
||||
/** Removes the element from in front of queue and returns that element. */
|
||||
public int pop() {
|
||||
// 只要 stOut 为空,那么就应该将 stIn 中所有的元素倒腾到 stOut 中
|
||||
if (stOut.isEmpty()) {
|
||||
while (!stIn.isEmpty()) {
|
||||
stOut.push(stIn.pop());
|
||||
}
|
||||
}
|
||||
// 再返回 stOut 中的元素
|
||||
return stOut.pop();
|
||||
}
|
||||
|
||||
/** Get the front element. */
|
||||
public int peek() {
|
||||
// 直接使用已有的pop函数
|
||||
int res = this.pop();
|
||||
// 因为pop函数弹出了元素res,所以再添加回去
|
||||
stOut.push(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Returns whether the queue is empty. */
|
||||
public boolean empty() {
|
||||
// 当 stIn 栈为空时,说明没有元素可以倒腾到 stOut 栈了
|
||||
// 并且 stOut 栈也为空时,说明没有以前从 stIn 中倒腾到的元素了
|
||||
return stIn.isEmpty() && stOut.isEmpty();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
个人习惯写法,使用Deque通用api:
|
||||
```java
|
||||
class MyQueue {
|
||||
// java中的 Stack 有设计上的缺陷,官方推荐使用 Deque(双端队列) 代替 Stack
|
||||
// Deque 中的 addFirst、removeFirst、peekFirst 等方法等效于 Stack(堆栈) 中的 push、pop、peek
|
||||
Deque<Integer> stIn;
|
||||
Deque<Integer> stOut;
|
||||
/** Initialize your data structure here. */
|
||||
public MyQueue() {
|
||||
stIn = new ArrayDeque<>();
|
||||
stOut = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
/** Push element x to the back of queue. */
|
||||
public void push(int x) {
|
||||
stIn.addLast(x);
|
||||
}
|
||||
|
||||
/** Removes the element from in front of queue and returns that element. */
|
||||
public int pop() {
|
||||
// 只要 stOut 为空,那么就应该将 stIn 中所有的元素倒腾到 stOut 中
|
||||
if (stOut.isEmpty()) {
|
||||
while (!stIn.isEmpty()) {
|
||||
stOut.addLast(stIn.pollLast());
|
||||
}
|
||||
}
|
||||
// 再返回 stOut 中的元素
|
||||
return stOut.pollLast();
|
||||
}
|
||||
|
||||
/** Get the front element. */
|
||||
public int peek() {
|
||||
// 直接使用已有的pop函数
|
||||
int res = this.pop();
|
||||
// 因为pop函数弹出了元素res,所以再添加回去
|
||||
stOut.addLast(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Returns whether the queue is empty. */
|
||||
public boolean empty() {
|
||||
// 当 stIn 栈为空时,说明没有元素可以倒腾到 stOut 栈了
|
||||
// 并且 stOut 栈也为空时,说明没有以前从 stIn 中倒腾到的元素了
|
||||
return stIn.isEmpty() && stOut.isEmpty();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
class MyQueue {
|
||||
|
||||
@ -190,6 +285,73 @@ Python:
|
||||
|
||||
|
||||
Go:
|
||||
```Go
|
||||
type MyQueue struct {
|
||||
stack []int
|
||||
back []int
|
||||
}
|
||||
|
||||
/** Initialize your data structure here. */
|
||||
func Constructor() MyQueue {
|
||||
return MyQueue{
|
||||
stack: make([]int, 0),
|
||||
back: make([]int, 0),
|
||||
}
|
||||
}
|
||||
|
||||
/** Push element x to the back of queue. */
|
||||
func (this *MyQueue) Push(x int) {
|
||||
for len(this.back) != 0 {
|
||||
val := this.back[len(this.back)-1]
|
||||
this.back = this.back[:len(this.back)-1]
|
||||
this.stack = append(this.stack, val)
|
||||
}
|
||||
this.stack = append(this.stack, x)
|
||||
}
|
||||
|
||||
/** Removes the element from in front of queue and returns that element. */
|
||||
func (this *MyQueue) Pop() int {
|
||||
for len(this.stack) != 0 {
|
||||
val := this.stack[len(this.stack)-1]
|
||||
this.stack = this.stack[:len(this.stack)-1]
|
||||
this.back = append(this.back, val)
|
||||
}
|
||||
if len(this.back) == 0 {
|
||||
return 0
|
||||
}
|
||||
val := this.back[len(this.back)-1]
|
||||
this.back = this.back[:len(this.back)-1]
|
||||
return val
|
||||
}
|
||||
|
||||
/** Get the front element. */
|
||||
func (this *MyQueue) Peek() int {
|
||||
for len(this.stack) != 0 {
|
||||
val := this.stack[len(this.stack)-1]
|
||||
this.stack = this.stack[:len(this.stack)-1]
|
||||
this.back = append(this.back, val)
|
||||
}
|
||||
if len(this.back) == 0 {
|
||||
return 0
|
||||
}
|
||||
val := this.back[len(this.back)-1]
|
||||
return val
|
||||
}
|
||||
|
||||
/** Returns whether the queue is empty. */
|
||||
func (this *MyQueue) Empty() bool {
|
||||
return len(this.stack) == 0 && len(this.back) == 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Your MyQueue object will be instantiated and called as such:
|
||||
* obj := Constructor();
|
||||
* obj.Push(x);
|
||||
* param_2 := obj.Pop();
|
||||
* param_3 := obj.Peek();
|
||||
* param_4 := obj.Empty();
|
||||
*/
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -267,7 +267,30 @@ Python:
|
||||
|
||||
Go:
|
||||
|
||||
|
||||
Javascript:
|
||||
```javascript
|
||||
var maxSlidingWindow = function (nums, k) {
|
||||
// 队列数组(存放的是元素下标,为了取值方便)
|
||||
const q = [];
|
||||
// 结果数组
|
||||
const ans = [];
|
||||
for (let i = 0; i < nums.length; i++) {
|
||||
// 若队列不为空,且当前元素大于等于队尾所存下标的元素,则弹出队尾
|
||||
while (q.length && nums[i] >= nums[q[q.length - 1]]) {
|
||||
q.pop();
|
||||
}
|
||||
// 入队当前元素下标
|
||||
q.push(i);
|
||||
// 判断当前最大值(即队首元素)是否在窗口中,若不在便将其出队
|
||||
while (q[0] <= i - k) {
|
||||
q.shift();
|
||||
}
|
||||
// 当达到窗口大小时便开始向结果中添加数据
|
||||
if (i >= k - 1) ans.push(nums[q[0]]);
|
||||
}
|
||||
return ans;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -159,9 +159,33 @@ public:
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public int maxProfit(int[] prices) {
|
||||
if (prices == null || prices.length < 2) {
|
||||
return 0;
|
||||
}
|
||||
int[][] dp = new int[prices.length][2];
|
||||
|
||||
// bad case
|
||||
dp[0][0] = 0;
|
||||
dp[0][1] = -prices[0];
|
||||
dp[1][0] = Math.max(dp[0][0], dp[0][1] + prices[1]);
|
||||
dp[1][1] = Math.max(dp[0][1], -prices[1]);
|
||||
|
||||
for (int i = 2; i < prices.length; i++) {
|
||||
// dp公式
|
||||
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
|
||||
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 2][0] - prices[i]);
|
||||
}
|
||||
|
||||
return dp[prices.length - 1][0];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Python:
|
||||
|
||||
|
@ -157,7 +157,18 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
```python3
|
||||
class Solution:
|
||||
def reverseString(self, s: List[str]) -> None:
|
||||
"""
|
||||
Do not return anything, modify s in-place instead.
|
||||
"""
|
||||
left, right = 0, len(s) - 1
|
||||
while(left < right):
|
||||
s[left], s[right] = s[right], s[left]
|
||||
left += 1
|
||||
right -= 1
|
||||
```
|
||||
|
||||
Go:
|
||||
```Go
|
||||
|
@ -136,7 +136,34 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
```
|
||||
class Solution(object):
|
||||
def canConstruct(self, ransomNote, magazine):
|
||||
"""
|
||||
:type ransomNote: str
|
||||
:type magazine: str
|
||||
:rtype: bool
|
||||
"""
|
||||
|
||||
# use a dict to store the number of letter occurance in ransomNote
|
||||
hashmap = dict()
|
||||
for s in ransomNote:
|
||||
if s in hashmap:
|
||||
hashmap[s] += 1
|
||||
else:
|
||||
hashmap[s] = 1
|
||||
|
||||
# check if the letter we need can be found in magazine
|
||||
for l in magazine:
|
||||
if l in hashmap:
|
||||
hashmap[l] -= 1
|
||||
|
||||
for key in hashmap:
|
||||
if hashmap[key] > 0:
|
||||
return False
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
|
@ -121,6 +121,37 @@ class Solution {
|
||||
|
||||
Python:
|
||||
|
||||
```
|
||||
class Solution(object):
|
||||
def fourSumCount(self, nums1, nums2, nums3, nums4):
|
||||
"""
|
||||
:type nums1: List[int]
|
||||
:type nums2: List[int]
|
||||
:type nums3: List[int]
|
||||
:type nums4: List[int]
|
||||
:rtype: int
|
||||
"""
|
||||
# use a dict to store the elements in nums1 and nums2 and their sum
|
||||
hashmap = dict()
|
||||
for n1 in nums1:
|
||||
for n2 in nums2:
|
||||
if n1 + n2 in hashmap:
|
||||
hashmap[n1+n2] += 1
|
||||
else:
|
||||
hashmap[n1+n2] = 1
|
||||
|
||||
# if the -(a+b) exists in nums3 and nums4, we shall add the count
|
||||
count = 0
|
||||
for n3 in nums3:
|
||||
for n4 in nums4:
|
||||
key = - n3 - n4
|
||||
if key in hashmap:
|
||||
count += hashmap[key]
|
||||
return count
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
Go:
|
||||
|
||||
|
@ -187,7 +187,24 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
```python3
|
||||
class Solution:
|
||||
def fib(self, n: int) -> int:
|
||||
if n < 2:
|
||||
return n
|
||||
a, b, c = 0, 1, 0
|
||||
for i in range(1, n):
|
||||
c = a + b
|
||||
a, b = b, c
|
||||
return c
|
||||
|
||||
# 递归实现
|
||||
class Solution:
|
||||
def fib(self, n: int) -> int:
|
||||
if n < 2:
|
||||
return n
|
||||
return self.fib(n - 1) + self.fib(n - 2)
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
|
@ -173,6 +173,33 @@ Python:
|
||||
|
||||
|
||||
Go:
|
||||
```Go
|
||||
func longestPalindromeSubseq(s string) int {
|
||||
lenth:=len(s)
|
||||
dp:=make([][]int,lenth)
|
||||
for i:=0;i<lenth;i++{
|
||||
for j:=0;j<lenth;j++{
|
||||
if dp[i]==nil{
|
||||
dp[i]=make([]int,lenth)
|
||||
}
|
||||
if i==j{
|
||||
dp[i][j]=1
|
||||
}
|
||||
}
|
||||
}
|
||||
for i:=lenth-1;i>=0;i--{
|
||||
for j:=i+1;j<lenth;j++{
|
||||
if s[i]==s[j]{
|
||||
dp[i][j]=dp[i+1][j-1]+2
|
||||
}else {
|
||||
dp[i][j]=max(dp[i+1][j],dp[i][j-1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[0][lenth-1]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -177,8 +177,29 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
class Solution:
|
||||
def getMinimumDifference(self, root: TreeNode) -> int:
|
||||
res = []
|
||||
r = float("inf")
|
||||
def buildaList(root): //把二叉搜索树转换成有序数组
|
||||
if not root: return None
|
||||
if root.left: buildaList(root.left) //左
|
||||
res.append(root.val) //中
|
||||
if root.right: buildaList(root.right) //右
|
||||
return res
|
||||
|
||||
|
||||
buildaList(root)
|
||||
for i in range(len(res)-1): // 统计有序数组的最小差值
|
||||
r = min(abs(res[i]-res[i+1]),r)
|
||||
return r
|
||||
```
|
||||
Go:
|
||||
|
||||
|
||||
|
@ -312,7 +312,23 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
//递归法*前序遍历
|
||||
class Solution:
|
||||
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
|
||||
if not root1: return root2 // 如果t1为空,合并之后就应该是t2
|
||||
if not root2: return root1 // 如果t2为空,合并之后就应该是t1
|
||||
root1.val = root1.val + root2.val //中
|
||||
root1.left = self.mergeTrees(root1.left , root2.left) //左
|
||||
root1.right = self.mergeTrees(root1.right , root2.right) //右
|
||||
return root1 //root1修改了结构和数值
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
|
@ -219,9 +219,68 @@ public:
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
Java:
|
||||
|
||||
动态规划:
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public int countSubstrings(String s) {
|
||||
int len, ans = 0;
|
||||
if (s == null || (len = s.length()) < 1) return 0;
|
||||
//dp[i][j]:s字符串下标i到下标j的字串是否是一个回文串,即s[i, j]
|
||||
boolean[][] dp = new boolean[len][len];
|
||||
for (int j = 0; j < len; j++) {
|
||||
for (int i = 0; i <= j; i++) {
|
||||
//当两端字母一样时,才可以两端收缩进一步判断
|
||||
if (s.charAt(i) == s.charAt(j)) {
|
||||
//i++,j--,即两端收缩之后i,j指针指向同一个字符或者i超过j了,必然是一个回文串
|
||||
if (j - i < 3) {
|
||||
dp[i][j] = true;
|
||||
} else {
|
||||
//否则通过收缩之后的字串判断
|
||||
dp[i][j] = dp[i + 1][j - 1];
|
||||
}
|
||||
} else {//两端字符不一样,不是回文串
|
||||
dp[i][j] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//遍历每一个字串,统计回文串个数
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
if (dp[i][j]) ans++;
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
中心扩散法:
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public int countSubstrings(String s) {
|
||||
int len, ans = 0;
|
||||
if (s == null || (len = s.length()) < 1) return 0;
|
||||
//总共有2 * len - 1个中心点
|
||||
for (int i = 0; i < 2 * len - 1; i++) {
|
||||
//通过遍历每个回文中心,向两边扩散,并判断是否回文字串
|
||||
//有两种情况,left == right,right = left + 1,这两种回文中心是不一样的
|
||||
int left = i / 2, right = left + i % 2;
|
||||
while (left >= 0 && right < len && s.charAt(left) == s.charAt(right)) {
|
||||
//如果当前是一个回文串,则记录数量
|
||||
ans++;
|
||||
left--;
|
||||
right++;
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Python:
|
||||
|
||||
|
@ -256,7 +256,25 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
//递归法
|
||||
class Solution:
|
||||
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
|
||||
if not nums: return None //终止条件
|
||||
root = TreeNode(max(nums)) //新建节点
|
||||
p = nums.index(root.val) //找到最大值位置
|
||||
if p > 0: //保证有左子树
|
||||
root.left = self.constructMaximumBinaryTree(nums[:p]) //递归
|
||||
if p < len(nums): //保证有右子树
|
||||
root.right = self.constructMaximumBinaryTree(nums[p+1:]) //递归
|
||||
return root
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
|
@ -212,13 +212,18 @@ Python:
|
||||
递归法:
|
||||
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
class Solution:
|
||||
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
|
||||
if root is None:
|
||||
return None
|
||||
if val < root.val: return self.searchBST(root.left, val)
|
||||
elif val > root.val: return self.searchBST(root.right, val)
|
||||
else: return root
|
||||
if not root or root.val == val: return root //为空或者已经找到都是直接返回root,所以合并了
|
||||
if root.val > val: return self.searchBST(root.left,val) //注意一定要加return
|
||||
else: return self.searchBST(root.right,val)
|
||||
|
||||
```
|
||||
|
||||
迭代法:
|
||||
|
@ -231,7 +231,165 @@ class MyLinkedList {
|
||||
```
|
||||
|
||||
Python:
|
||||
```python3
|
||||
# 单链表
|
||||
class Node:
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
self.next = None
|
||||
|
||||
|
||||
class MyLinkedList:
|
||||
|
||||
def __init__(self):
|
||||
self._head = Node(0) # 虚拟头部节点
|
||||
self._count = 0 # 添加的节点数
|
||||
|
||||
def get(self, index: int) -> int:
|
||||
"""
|
||||
Get the value of the index-th node in the linked list. If the index is invalid, return -1.
|
||||
"""
|
||||
if 0 <= index < self._count:
|
||||
node = self._head
|
||||
for _ in range(index + 1):
|
||||
node = node.next
|
||||
return node.val
|
||||
else:
|
||||
return -1
|
||||
|
||||
def addAtHead(self, val: int) -> None:
|
||||
"""
|
||||
Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
|
||||
"""
|
||||
self.addAtIndex(0, val)
|
||||
|
||||
def addAtTail(self, val: int) -> None:
|
||||
"""
|
||||
Append a node of value val to the last element of the linked list.
|
||||
"""
|
||||
self.addAtIndex(self._count, val)
|
||||
|
||||
def addAtIndex(self, index: int, val: int) -> None:
|
||||
"""
|
||||
Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
|
||||
"""
|
||||
if index < 0:
|
||||
index = 0
|
||||
elif index > self._count:
|
||||
return
|
||||
|
||||
# 计数累加
|
||||
self._count += 1
|
||||
|
||||
add_node = Node(val)
|
||||
prev_node, current_node = None, self._head
|
||||
for _ in range(index + 1):
|
||||
prev_node, current_node = current_node, current_node.next
|
||||
else:
|
||||
prev_node.next, add_node.next = add_node, current_node
|
||||
|
||||
def deleteAtIndex(self, index: int) -> None:
|
||||
"""
|
||||
Delete the index-th node in the linked list, if the index is valid.
|
||||
"""
|
||||
if 0 <= index < self._count:
|
||||
# 计数-1
|
||||
self._count -= 1
|
||||
prev_node, current_node = None, self._head
|
||||
for _ in range(index + 1):
|
||||
prev_node, current_node = current_node, current_node.next
|
||||
else:
|
||||
prev_node.next, current_node.next = current_node.next, None
|
||||
|
||||
|
||||
# 双链表
|
||||
# 相对于单链表, Node新增了prev属性
|
||||
class Node:
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
self.prev = None
|
||||
self.next = None
|
||||
|
||||
|
||||
class MyLinkedList:
|
||||
|
||||
def __init__(self):
|
||||
self._head, self._tail = Node(0), Node(0) # 虚拟节点
|
||||
self._head.next, self._tail.prev = self._tail, self._head
|
||||
self._count = 0 # 添加的节点数
|
||||
|
||||
def _get_node(self, index: int) -> Node:
|
||||
# 当index小于_count//2时, 使用_head查找更快, 反之_tail更快
|
||||
if index >= self._count // 2:
|
||||
# 使用prev往前找
|
||||
node = self._tail
|
||||
for _ in range(self._count - index):
|
||||
node = node.prev
|
||||
else:
|
||||
# 使用next往后找
|
||||
node = self._head
|
||||
for _ in range(index + 1):
|
||||
node = node.next
|
||||
return node
|
||||
|
||||
def get(self, index: int) -> int:
|
||||
"""
|
||||
Get the value of the index-th node in the linked list. If the index is invalid, return -1.
|
||||
"""
|
||||
if 0 <= index < self._count:
|
||||
node = self._get_node(index)
|
||||
return node.val
|
||||
else:
|
||||
return -1
|
||||
|
||||
def addAtHead(self, val: int) -> None:
|
||||
"""
|
||||
Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
|
||||
"""
|
||||
self._update(self._head, self._head.next, val)
|
||||
|
||||
def addAtTail(self, val: int) -> None:
|
||||
"""
|
||||
Append a node of value val to the last element of the linked list.
|
||||
"""
|
||||
self._update(self._tail.prev, self._tail, val)
|
||||
|
||||
def addAtIndex(self, index: int, val: int) -> None:
|
||||
"""
|
||||
Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
|
||||
"""
|
||||
if index < 0:
|
||||
index = 0
|
||||
elif index > self._count:
|
||||
return
|
||||
node = self._get_node(index)
|
||||
self._update(node.prev, node, val)
|
||||
|
||||
def _update(self, prev: Node, next: Node, val: int) -> None:
|
||||
"""
|
||||
更新节点
|
||||
:param prev: 相对于更新的前一个节点
|
||||
:param next: 相对于更新的后一个节点
|
||||
:param val: 要添加的节点值
|
||||
"""
|
||||
# 计数累加
|
||||
self._count += 1
|
||||
node = Node(val)
|
||||
prev.next, next.prev = node, node
|
||||
node.prev, node.next = prev, next
|
||||
|
||||
def deleteAtIndex(self, index: int) -> None:
|
||||
"""
|
||||
Delete the index-th node in the linked list, if the index is valid.
|
||||
"""
|
||||
if 0 <= index < self._count:
|
||||
node = self._get_node(index)
|
||||
# 计数-1
|
||||
self._count -= 1
|
||||
node.prev.next, node.next.prev = node.next, node.prev
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
|
@ -154,9 +154,9 @@ public:
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
Java:
|
||||
```java
|
||||
// 贪心思路
|
||||
class Solution {
|
||||
public int maxProfit(int[] prices, int fee) {
|
||||
int buy = prices[0] + fee;
|
||||
@ -174,6 +174,30 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
class Solution { // 动态规划
|
||||
public int maxProfit(int[] prices, int fee) {
|
||||
if (prices == null || prices.length < 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int[][] dp = new int[prices.length][2];
|
||||
|
||||
// bad case
|
||||
dp[0][0] = 0;
|
||||
dp[0][1] = -prices[0];
|
||||
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee);
|
||||
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
|
||||
}
|
||||
|
||||
return dp[prices.length - 1][0];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Python:
|
||||
|
||||
|
||||
|
@ -146,7 +146,17 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
```python3
|
||||
class Solution:
|
||||
def removeDuplicates(self, s: str) -> str:
|
||||
t = list()
|
||||
for i in s:
|
||||
if t and t[-1] == i:
|
||||
t.pop(-1)
|
||||
else:
|
||||
t.append(i)
|
||||
return "".join(t) # 字符串拼接
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
|
@ -160,11 +160,175 @@ Java:
|
||||
|
||||
|
||||
Python:
|
||||
```python3
|
||||
# 前序遍历-迭代-LC144_二叉树的前序遍历
|
||||
class Solution:
|
||||
def preorderTraversal(self, root: TreeNode) -> List[int]:
|
||||
# 根结点为空则返回空列表
|
||||
if not root:
|
||||
return []
|
||||
stack = [root]
|
||||
result = []
|
||||
while stack:
|
||||
node = stack.pop()
|
||||
# 中结点先处理
|
||||
result.append(node.val)
|
||||
# 右孩子先入栈
|
||||
if node.right:
|
||||
stack.append(node.right)
|
||||
# 左孩子后入栈
|
||||
if node.left:
|
||||
stack.append(node.left)
|
||||
return result
|
||||
|
||||
# 中序遍历-迭代-LC94_二叉树的中序遍历
|
||||
class Solution:
|
||||
def inorderTraversal(self, root: TreeNode) -> List[int]:
|
||||
if not root:
|
||||
return []
|
||||
stack = [] # 不能提前将root结点加入stack中
|
||||
result = []
|
||||
cur = root
|
||||
while cur or stack:
|
||||
# 先迭代访问最底层的左子树结点
|
||||
if cur:
|
||||
stack.append(cur)
|
||||
cur = cur.left
|
||||
# 到达最左结点后处理栈顶结点
|
||||
else:
|
||||
cur = stack.pop()
|
||||
result.append(cur.val)
|
||||
# 取栈顶元素右结点
|
||||
cur = cur.right
|
||||
return result
|
||||
|
||||
# 后序遍历-迭代-LC145_二叉树的后序遍历
|
||||
class Solution:
|
||||
def postorderTraversal(self, root: TreeNode) -> List[int]:
|
||||
if not root:
|
||||
return []
|
||||
stack = [root]
|
||||
result = []
|
||||
while stack:
|
||||
node = stack.pop()
|
||||
# 中结点先处理
|
||||
result.append(node.val)
|
||||
# 左孩子先入栈
|
||||
if node.left:
|
||||
stack.append(node.left)
|
||||
# 右孩子后入栈
|
||||
if node.right:
|
||||
stack.append(node.right)
|
||||
# 将最终的数组翻转
|
||||
return result[::-1]
|
||||
```
|
||||
|
||||
|
||||
Go:
|
||||
> 迭代法前序遍历
|
||||
|
||||
```go
|
||||
//迭代法前序遍历
|
||||
/**
|
||||
type Element struct {
|
||||
// 元素保管的值
|
||||
Value interface{}
|
||||
// 内含隐藏或非导出字段
|
||||
}
|
||||
|
||||
func (l *List) Back() *Element
|
||||
前序遍历:中左右
|
||||
压栈顺序:右左中
|
||||
**/
|
||||
func preorderTraversal(root *TreeNode) []int {
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
var stack = list.New()
|
||||
stack.PushBack(root.Right)
|
||||
stack.PushBack(root.Left)
|
||||
res:=[]int{}
|
||||
res=append(res,root.Val)
|
||||
for stack.Len()>0 {
|
||||
e:=stack.Back()
|
||||
stack.Remove(e)
|
||||
node := e.Value.(*TreeNode)//e是Element类型,其值为e.Value.由于Value为接口,所以要断言
|
||||
if node==nil{
|
||||
continue
|
||||
}
|
||||
res=append(res,node.Val)
|
||||
stack.PushBack(node.Right)
|
||||
stack.PushBack(node.Left)
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
> 迭代法后序遍历
|
||||
|
||||
```go
|
||||
//迭代法后序遍历
|
||||
//后续遍历:左右中
|
||||
//压栈顺序:中右左(按照前序遍历思路),再反转结果数组
|
||||
func postorderTraversal(root *TreeNode) []int {
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
var stack = list.New()
|
||||
stack.PushBack(root.Left)
|
||||
stack.PushBack(root.Right)
|
||||
res:=[]int{}
|
||||
res=append(res,root.Val)
|
||||
for stack.Len()>0 {
|
||||
e:=stack.Back()
|
||||
stack.Remove(e)
|
||||
node := e.Value.(*TreeNode)//e是Element类型,其值为e.Value.由于Value为接口,所以要断言
|
||||
if node==nil{
|
||||
continue
|
||||
}
|
||||
res=append(res,node.Val)
|
||||
stack.PushBack(node.Left)
|
||||
stack.PushBack(node.Right)
|
||||
}
|
||||
for i:=0;i<len(res)/2;i++{
|
||||
res[i],res[len(res)-i-1] = res[len(res)-i-1],res[i]
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
> 迭代法中序遍历
|
||||
|
||||
```go
|
||||
//迭代法中序遍历
|
||||
func inorderTraversal(root *TreeNode) []int {
|
||||
rootRes:=[]int{}
|
||||
if root==nil{
|
||||
return nil
|
||||
}
|
||||
stack:=list.New()
|
||||
node:=root
|
||||
//先将所有左节点找到,加入栈中
|
||||
for node!=nil{
|
||||
stack.PushBack(node)
|
||||
node=node.Left
|
||||
}
|
||||
//其次对栈中的每个节点先弹出加入到结果集中,再找到该节点的右节点的所有左节点加入栈中
|
||||
for stack.Len()>0{
|
||||
e:=stack.Back()
|
||||
node:=e.Value.(*TreeNode)
|
||||
stack.Remove(e)
|
||||
//找到该节点的右节点,再搜索他的所有左节点加入栈中
|
||||
rootRes=append(rootRes,node.Val)
|
||||
node=node.Right
|
||||
for node!=nil{
|
||||
stack.PushBack(node)
|
||||
node=node.Left
|
||||
}
|
||||
}
|
||||
return rootRes
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -7,11 +7,10 @@
|
||||
<p align="center"><strong>欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||
|
||||
|
||||
> 之前链表篇没有做总结,所以是时候总结一波
|
||||
|
||||
# 链表的理论基础
|
||||
## 链表的理论基础
|
||||
|
||||
在这篇文章[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/ntlZbEdKgnFQKZkSUAOSpQ)中,介绍了如下几点:
|
||||
在这篇文章[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw)中,介绍了如下几点:
|
||||
|
||||
* 链表的种类主要为:单链表,双链表,循环链表
|
||||
* 链表的存储方式:链表的节点在内存中是分散存储的,通过指针连在一起。
|
||||
@ -20,21 +19,21 @@
|
||||
|
||||
**可以说把链表基础的知识都概括了,但又不像教科书那样的繁琐**。
|
||||
|
||||
# 链表经典题目
|
||||
## 链表经典题目
|
||||
|
||||
## 虚拟头结点
|
||||
### 虚拟头结点
|
||||
|
||||
在[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/slM1CH5Ew9XzK93YOQYSjA)中,我们讲解了链表操作中一个非常总要的技巧:虚拟头节点。
|
||||
在[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)中,我们讲解了链表操作中一个非常总要的技巧:虚拟头节点。
|
||||
|
||||
链表的一大问题就是操作当前节点必须要找前一个节点才能操作。这就造成了,头结点的尴尬,因为头结点没有前一个节点了。
|
||||
|
||||
**每次对应头结点的情况都要单独处理,所以使用虚拟头结点的技巧,就可以解决这个问题**。
|
||||
|
||||
在[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/slM1CH5Ew9XzK93YOQYSjA)中,我给出了用虚拟头结点和没用虚拟头结点的代码,大家对比一下就会发现,使用虚拟头结点的好处。
|
||||
在[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)中,我给出了用虚拟头结点和没用虚拟头结点的代码,大家对比一下就会发现,使用虚拟头结点的好处。
|
||||
|
||||
## 链表的基本操作
|
||||
### 链表的基本操作
|
||||
|
||||
在[链表:一道题目考察了常见的五个操作!](https://mp.weixin.qq.com/s/Cf95Lc6brKL4g2j8YyF3Mg)中,我们通设计链表把链表常见的五个操作练习了一遍。
|
||||
在[链表:一道题目考察了常见的五个操作!](https://mp.weixin.qq.com/s/jnC_LAD0ZKCsj-FZc57F1g)中,我们通设计链表把链表常见的五个操作练习了一遍。
|
||||
|
||||
这是练习链表基础操作的非常好的一道题目,考察了:
|
||||
|
||||
@ -48,103 +47,49 @@
|
||||
|
||||
这里我依然使用了虚拟头结点的技巧,大家复习的时候,可以去看一下代码。
|
||||
|
||||
## 反转链表
|
||||
### 反转链表
|
||||
|
||||
在[链表:听说过两天反转链表又写不出来了?](https://mp.weixin.qq.com/s/pnvVP-0ZM7epB8y3w_Njwg)中,讲解了如何反转链表。
|
||||
在[链表:听说过两天反转链表又写不出来了?](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)中,讲解了如何反转链表。
|
||||
|
||||
因为反转链表的代码相对简单,有的同学可能直接背下来了,但一写还是容易出问题。
|
||||
|
||||
反转链表是面试中高频题目,很考察面试者对链表操作的熟练程度。
|
||||
|
||||
我在[文章](https://mp.weixin.qq.com/s/pnvVP-0ZM7epB8y3w_Njwg)中,给出了两种反转的方式,迭代法和递归法。
|
||||
我在[文章](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)中,给出了两种反转的方式,迭代法和递归法。
|
||||
|
||||
建议大家先学透迭代法,然后再看递归法,因为递归法比较绕,如果迭代还写不明白,递归基本也写不明白了。
|
||||
|
||||
**可以先通过迭代法,彻底弄清楚链表反转的过程!**
|
||||
|
||||
### 删除倒数第N个节点
|
||||
|
||||
在[链表:删除链表倒数第N个节点,怎么删?](https://mp.weixin.qq.com/s/gxu65X1343xW_sBrkTz0Eg)中我们结合虚拟头结点 和 双指针法来移除链表倒数第N个节点。
|
||||
|
||||
|
||||
### 链表相交
|
||||
|
||||
[链表:链表相交](https://mp.weixin.qq.com/s/BhfFfaGvt9Zs7UmH4YehZw)使用双指针来找到两个链表的交点(引用完全相同,即:内存地址完全相同的交点)
|
||||
|
||||
## 环形链表
|
||||
|
||||
在[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)中,讲解了在链表如何找环,以及如何找环的入口位置。
|
||||
在[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ)中,讲解了在链表如何找环,以及如何找环的入口位置。
|
||||
|
||||
这道题目可以说是链表的比较难的题目了。
|
||||
这道题目可以说是链表的比较难的题目了。 但代码却十分简洁,主要在于一些数学证明。
|
||||
|
||||
很多同学关注的问题是:为什么一定会相遇,快指针就不能跳过慢指针么?
|
||||
|
||||
可以确定如下两点:
|
||||
|
||||
* fast指针一定先进入环中,如果fast 指针和slow指针相遇的话,一定是在环中相遇,这是毋庸置疑的。
|
||||
* fast和slow都进入环里之后,fast相对于slow来说,fast是一个节点一个节点的靠近slow的,**注意是相对运动,所以fast一定可以和slow重合**。
|
||||
|
||||
如果fast是一次走三个节点,那么可能会跳过slow,因为相对于slow来说,fast是两个节点移动的。
|
||||
|
||||
确定有否有环比较容易,但是找到环的入口就不太容易了,需要点数学推理。
|
||||
|
||||
我在[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)中给出了详细的推理,兼顾易懂和简洁了。
|
||||
|
||||
这是一位录友在评论区有一个疑问,感觉这个问题很不错,但评论区根本说不清楚,我就趁着总结篇,补充一下这个证明。
|
||||
|
||||
在推理过程中,**为什么第一次在环中相遇,slow的 步数 是 x+y 而不是 x + 若干环的长度 + y 呢?**
|
||||
|
||||
了解这个问题一定要先把文章[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)看了,即文章中如下的地方:
|
||||
|
||||
<img src='https://code-thinking.cdn.bcebos.com/pics/142%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A85.png' width=600> </img></div>
|
||||
|
||||
|
||||
首先slow进环的时候,fast一定是先进环来了。
|
||||
|
||||
如果slow进环入口,fast也在环入口,那么把这个环展开成直线,就是如下图的样子:
|
||||
|
||||
<img src='https://code-thinking.cdn.bcebos.com/pics/142%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A83.png' width=600> </img></div>
|
||||
|
||||
可以看出如果slow 和 fast同时在环入口开始走,一定会在环入口3相遇,slow走了一圈,fast走了两圈。
|
||||
|
||||
重点来了,slow进环的时候,fast一定是在环的任意一个位置,如图:
|
||||
|
||||
<img src='https://code-thinking.cdn.bcebos.com/pics/142%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A84.png' width=600> </img></div>
|
||||
|
||||
那么fast指针走到环入口3的时候,已经走了k + n 个节点,slow相应的应该走了(k + n) / 2 个节点。
|
||||
|
||||
因为k是小于n的(图中可以看出),所以(k + n) / 2 一定小于n。
|
||||
|
||||
**也就是说slow一定没有走到环入口3,而fast已经到环入口3了**。
|
||||
|
||||
这说明什么呢?
|
||||
|
||||
**在slow开始走的那一环已经和fast相遇了**。
|
||||
|
||||
那有同学又说了,为什么fast不能跳过去呢? 在刚刚已经说过一次了,**fast相对于slow是一次移动一个节点,所以不可能跳过去**。
|
||||
|
||||
好了,这次把为什么第一次在环中相遇,slow的 步数 是 x+y 而不是 x + 若干环的长度 + y ,用数学推理了一下,算是对[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)的补充。
|
||||
|
||||
这次可以说把环形链表这道题目的各个细节,完完整整的证明了一遍,说这是全网最详细讲解不为过吧,哈哈。
|
||||
|
||||
# 总结
|
||||
## 总结
|
||||
|
||||
考察链表的操作其实就是考察指针的操作,是面试中的常见类型。
|
||||
|
||||
链表篇中开头介绍[链表理论知识](https://mp.weixin.qq.com/s/slM1CH5Ew9XzK93YOQYSjA),然后分别通过经典题目介绍了如下知识点:
|
||||
|
||||
* [虚拟头结点的技巧](https://mp.weixin.qq.com/s/slM1CH5Ew9XzK93YOQYSjA)
|
||||
* [链表的增删改查](https://mp.weixin.qq.com/s/Cf95Lc6brKL4g2j8YyF3Mg)
|
||||
* [反转一个链表](https://mp.weixin.qq.com/s/pnvVP-0ZM7epB8y3w_Njwg)
|
||||
* [有否环形,以及环的入口](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)
|
||||
1. [关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw)
|
||||
2. [虚拟头结点的技巧](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)
|
||||
3. [链表的增删改查](https://mp.weixin.qq.com/s/jnC_LAD0ZKCsj-FZc57F1g)
|
||||
4. [反转一个链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)
|
||||
5. [删除倒数第N个节点](https://mp.weixin.qq.com/s/gxu65X1343xW_sBrkTz0Eg)
|
||||
6. [链表相交](https://mp.weixin.qq.com/s/BhfFfaGvt9Zs7UmH4YehZw)
|
||||
7. [有否环形,以及环的入口](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ)
|
||||
|
||||
虽然这几篇文章都是几个月前发的了,但在在文章留言区,可以看到很多录友都在从头打卡!
|
||||
|
||||
如果希望从基础学起来的同学,也可以从头学起来,从头开始打卡,打卡的同时也总结自己的所学所思,一定进步飞快!
|
||||
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
Java:
|
||||
|
||||
|
||||
Python:
|
||||
|
||||
|
||||
Go:
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user