mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-09 19:44:45 +08:00
Merge branch 'master' into 添加0516最长回文子序列Go版本-1
This commit is contained in:
@ -3,7 +3,8 @@
|
|||||||
> 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者)
|
> 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者)
|
||||||
> 2. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ) 。
|
> 2. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ) 。
|
||||||
> 3. **学习社区** : 一起学习打卡/面试技巧/如何选择offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入[「代码随想录」学习社区](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) 。
|
> 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">
|
<p align="center">
|
||||||
<a href="https://github.com/youngyangyang04/leetcode-master" target="_blank">
|
<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。
|
大家好,我是程序员Carl,哈工大师兄,ACM 校赛、黑龙江省赛、东北四省赛金牌、亚洲区域赛铜牌获得者,先后在腾讯和百度从事后端技术研发,CSDN博客专家。对算法和C++后端技术有一定的见解,利用工作之余重新刷leetcode。
|
||||||
@ -420,7 +425,7 @@
|
|||||||
<a name="微信"></a>
|
<a name="微信"></a>
|
||||||
<img src="https://img-blog.csdnimg.cn/20200814140330894.png" data-img="1" width="175" height="175">
|
<img src="https://img-blog.csdnimg.cn/20200814140330894.png" data-img="1" width="175" height="175">
|
||||||
|
|
||||||
# 我的公众号
|
# 公众号
|
||||||
|
|
||||||
更多精彩文章持续更新,微信搜索:「代码随想录」第一时间围观,关注后回复:「666」可以获得所有算法专题原创PDF。
|
更多精彩文章持续更新,微信搜索:「代码随想录」第一时间围观,关注后回复:「666」可以获得所有算法专题原创PDF。
|
||||||
|
|
||||||
|
@ -37,9 +37,9 @@ https://leetcode-cn.com/problems/two-sum/
|
|||||||
本题呢,则要使用map,那么来看一下使用数组和set来做哈希法的局限。
|
本题呢,则要使用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,有三种类型:
|
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
|
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)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
@ -132,6 +132,21 @@ Python:
|
|||||||
|
|
||||||
Go:
|
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)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
@ -116,7 +116,7 @@ public:
|
|||||||
|
|
||||||
**大家要仔细看注释,思考为什么要写while(left <= right), 为什么要写right = middle - 1**。
|
**大家要仔细看注释,思考为什么要写while(left <= right), 为什么要写right = middle - 1**。
|
||||||
|
|
||||||
```
|
```C++
|
||||||
class Solution {
|
class Solution {
|
||||||
public:
|
public:
|
||||||
int searchInsert(vector<int>& nums, int target) {
|
int searchInsert(vector<int>& nums, int target) {
|
||||||
@ -158,7 +158,7 @@ public:
|
|||||||
|
|
||||||
**大家要仔细看注释,思考为什么要写while (left < right), 为什么要写right = middle**。
|
**大家要仔细看注释,思考为什么要写while (left < right), 为什么要写right = middle**。
|
||||||
|
|
||||||
```
|
```C++
|
||||||
class Solution {
|
class Solution {
|
||||||
public:
|
public:
|
||||||
int searchInsert(vector<int>& nums, int target) {
|
int searchInsert(vector<int>& nums, int target) {
|
||||||
|
@ -206,14 +206,33 @@ func backtrack(nums,pathNums []int,used []bool){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func permute(nums []int) [][]int {
|
Javascript:
|
||||||
//var pathNums []int
|
|
||||||
pathNums:=make([]int,0)
|
```javascript
|
||||||
var used=make([]bool,len(nums))
|
|
||||||
result=[][]int{}
|
var permute = function(nums) {
|
||||||
backtrack(nums,pathNums,used)
|
let result = []
|
||||||
return result
|
let path = []
|
||||||
|
function backtracing(used) {
|
||||||
|
if(path.length === nums.length) {
|
||||||
|
result.push(path.slice(0))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
for(let i = 0; i < nums.length; i++) {
|
||||||
|
if(used[nums[i]]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
used[nums[i]] = true
|
||||||
|
path.push(nums[i])
|
||||||
|
backtracing(used)
|
||||||
|
path.pop()
|
||||||
|
used[nums[i]] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backtracing([])
|
||||||
|
return result
|
||||||
|
};
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ public:
|
|||||||
path.clear();
|
path.clear();
|
||||||
sort(nums.begin(), nums.end()); // 排序
|
sort(nums.begin(), nums.end()); // 排序
|
||||||
vector<bool> used(nums.size(), false);
|
vector<bool> used(nums.size(), false);
|
||||||
backtracking(nums, vec, used);
|
backtracking(nums, used);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -220,6 +220,43 @@ class Solution:
|
|||||||
return res
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,31 +175,25 @@ class Solution:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
```Go
|
|
||||||
func maxSubArray(nums []int) int {
|
|
||||||
if len(nums)<1{
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
dp:=make([]int,len(nums))
|
|
||||||
result:=nums[0]
|
|
||||||
dp[0]=nums[0]
|
|
||||||
for i:=1;i<len(nums);i++{
|
|
||||||
dp[i]=max(dp[i-1]+nums[i],nums[i])
|
|
||||||
result=max(dp[i],result)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func max(a,b int)int{
|
```go
|
||||||
if a>b{
|
func maxSubArray(nums []int) int {
|
||||||
return a
|
maxSum := nums[0]
|
||||||
}else{
|
for i := 1; i < len(nums); i++ {
|
||||||
return b
|
if nums[i] + nums[i-1] > nums[i] {
|
||||||
|
nums[i] += nums[i-1]
|
||||||
}
|
}
|
||||||
|
if nums[i] > maxSum {
|
||||||
|
maxSum = nums[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxSum
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
@ -373,6 +373,32 @@ Python:
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
```Go
|
||||||
|
var res [][]int
|
||||||
|
func combine(n int, k int) [][]int {
|
||||||
|
res=[][]int{}
|
||||||
|
if n <= 0 || k <= 0 || k > n {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
backtrack(n, k, 1, []int{})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
func backtrack(n,k,start int,track []int){
|
||||||
|
if len(track)==k{
|
||||||
|
temp:=make([]int,k)
|
||||||
|
copy(temp,track)
|
||||||
|
res=append(res,temp)
|
||||||
|
}
|
||||||
|
if len(track)+n-start+1 < k {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i:=start;i<=n;i++{
|
||||||
|
track=append(track,i)
|
||||||
|
backtrack(n,k,i+1,track)
|
||||||
|
track=track[:len(track)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -189,7 +189,18 @@ Python:
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
```Go
|
||||||
|
func numTrees(n int)int{
|
||||||
|
dp:=make([]int,n+1)
|
||||||
|
dp[0]=1
|
||||||
|
for i:=1;i<=n;i++{
|
||||||
|
for j:=1;j<=i;j++{
|
||||||
|
dp[i]+=dp[j-1]*dp[i-j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[n]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -336,8 +336,26 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
||||||
```Go
|
```Go
|
||||||
import "math"
|
import "math"
|
||||||
|
@ -657,8 +657,56 @@ Python:
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
```Go
|
||||||
|
func levelOrder(root *TreeNode) [][]int {
|
||||||
|
result:=make([][]int,0)
|
||||||
|
if root==nil{
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
queue:=make([]*TreeNode,0)
|
||||||
|
queue=append(queue,root)
|
||||||
|
|
||||||
|
for len(queue)>0{
|
||||||
|
list:=make([]int,0)
|
||||||
|
l:=len(queue)
|
||||||
|
|
||||||
|
for i:=0;i<l;i++{
|
||||||
|
level:=queue[0]
|
||||||
|
queue=queue[1:]
|
||||||
|
list=append(list,level.Val)
|
||||||
|
if level.Left!=nil{
|
||||||
|
queue=append(queue,level.Left)
|
||||||
|
}
|
||||||
|
if level.Right!=nil{
|
||||||
|
queue=append(queue,level.Right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result=append(result,list)
|
||||||
|
}
|
||||||
|
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)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
@ -618,8 +618,42 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
|
||||||
|
@ -349,6 +349,74 @@ class Solution {
|
|||||||
|
|
||||||
Python:
|
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 root.right:
|
||||||
|
targetSum -= root.right.val //右节点
|
||||||
|
if isornot(root.right,targetSum):return True //递归,处理右节点
|
||||||
|
targetSum += root.right.val //回溯
|
||||||
|
return False
|
||||||
|
|
||||||
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -196,9 +196,9 @@ public:
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
```java
|
```java
|
||||||
|
// 贪心思路
|
||||||
class Solution {
|
class Solution {
|
||||||
public int maxProfit(int[] prices) {
|
public int maxProfit(int[] prices) {
|
||||||
int minprice = Integer.MAX_VALUE;
|
int minprice = Integer.MAX_VALUE;
|
||||||
@ -215,10 +215,62 @@ 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:
|
Python:
|
||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
```Go
|
||||||
|
func maxProfit(prices []int) int {
|
||||||
|
length:=len(prices)
|
||||||
|
if length==0{return 0}
|
||||||
|
dp:=make([][]int,length)
|
||||||
|
for i:=0;i<length;i++{
|
||||||
|
dp[i]=make([]int,2)
|
||||||
|
}
|
||||||
|
|
||||||
|
dp[0][0]=-prices[0]
|
||||||
|
dp[0][1]=0
|
||||||
|
for i:=1;i<length;i++{
|
||||||
|
dp[i][0]=max(dp[i-1][0],-prices[i])
|
||||||
|
dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i])
|
||||||
|
}
|
||||||
|
return dp[length-1][1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(a,b int)int {
|
||||||
|
if a>b{
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,9 +133,10 @@ public:
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
// 贪心思路
|
||||||
class Solution {
|
class Solution {
|
||||||
public int maxProfit(int[] prices) {
|
public int maxProfit(int[] prices) {
|
||||||
int sum = 0;
|
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:
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
|
@ -136,24 +136,31 @@ Java:
|
|||||||
```java
|
```java
|
||||||
// 动态规划
|
// 动态规划
|
||||||
class Solution
|
class Solution
|
||||||
|
// 实现1:二维数组存储
|
||||||
|
// 可以将每天持有与否的情况分别用 dp[i][0] 和 dp[i][1] 来进行存储
|
||||||
|
// 时间复杂度:O(n),空间复杂度O(n)
|
||||||
public int maxProfit(int[] prices) {
|
public int maxProfit(int[] prices) {
|
||||||
int n = prices.length;
|
int n = prices.length;
|
||||||
int[][] dp = new int[n][2];
|
int[][] dp = new int[n][2]; // 创建二维数组存储状态
|
||||||
dp[0][0] = 0;
|
dp[0][0] = 0; // 初始状态
|
||||||
dp[0][1] = -prices[0];
|
dp[0][1] = -prices[0];
|
||||||
for (int i = 1; i < n; ++i) {
|
for (int i = 1; i < n; ++i) {
|
||||||
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
|
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); // 第 i 天,没有股票
|
||||||
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
|
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); // 第 i 天,持有股票
|
||||||
}
|
}
|
||||||
return dp[n - 1][0];
|
return dp[n - 1][0]; // 卖出股票收益高于持有股票收益,因此取[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 实现2:变量存储
|
||||||
|
// 第一种方法需要用二维数组存储,有空间开销,其实关心的仅仅是前一天的状态,不关注更多的历史信息
|
||||||
|
// 因此,可以仅保存前一天的信息存入 dp0、dp1 这 2 个变量即可
|
||||||
|
// 时间复杂度:O(n),空间复杂度O(1)
|
||||||
public int maxProfit(int[] prices) {
|
public int maxProfit(int[] prices) {
|
||||||
int n = prices.length;
|
int n = prices.length;
|
||||||
int dp0 = 0, dp1 = -prices[0];
|
int dp0 = 0, dp1 = -prices[0]; // 定义变量,存储初始状态
|
||||||
for (int i = 1; i < n; ++i) {
|
for (int i = 1; i < n; ++i) {
|
||||||
int newDp0 = Math.max(dp0, dp1 + prices[i]);
|
int newDp0 = Math.max(dp0, dp1 + prices[i]); // 第 i 天,没有股票
|
||||||
int newDp1 = Math.max(dp1, dp0 - prices[i]);
|
int newDp1 = Math.max(dp1, dp0 - prices[i]); // 第 i 天,持有股票
|
||||||
dp0 = newDp0;
|
dp0 = newDp0;
|
||||||
dp1 = newDp1;
|
dp1 = newDp1;
|
||||||
}
|
}
|
||||||
|
@ -190,9 +190,42 @@ dp[1] = max(dp[1], dp[0] - prices[i]); 如果dp[1]取dp[1],即保持买入股
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
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:
|
Python:
|
||||||
|
|
||||||
|
@ -223,7 +223,21 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
|
||||||
|
start = 0
|
||||||
|
curSum = 0
|
||||||
|
totalSum = 0
|
||||||
|
for i in range(len(gas)):
|
||||||
|
curSum += gas[i] - cost[i]
|
||||||
|
totalSum += gas[i] - cost[i]
|
||||||
|
if curSum < 0:
|
||||||
|
curSum = 0
|
||||||
|
start = i + 1
|
||||||
|
if totalSum < 0: return -1
|
||||||
|
return start
|
||||||
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
@ -161,7 +161,18 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def candy(self, ratings: List[int]) -> int:
|
||||||
|
candyVec = [1] * len(ratings)
|
||||||
|
for i in range(1, len(ratings)):
|
||||||
|
if ratings[i] > ratings[i - 1]:
|
||||||
|
candyVec[i] = candyVec[i - 1] + 1
|
||||||
|
for j in range(len(ratings) - 2, -1, -1):
|
||||||
|
if ratings[j] > ratings[j + 1]:
|
||||||
|
candyVec[j] = max(candyVec[j], candyVec[j + 1] + 1)
|
||||||
|
return sum(candyVec)
|
||||||
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
@ -234,6 +234,29 @@ class Solution:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
```func detectCycle(head *ListNode) *ListNode {
|
||||||
|
if head ==nil{
|
||||||
|
return head
|
||||||
|
}
|
||||||
|
slow:=head
|
||||||
|
fast:=head.Next
|
||||||
|
|
||||||
|
for fast!=nil&&fast.Next!=nil{
|
||||||
|
if fast==slow{
|
||||||
|
slow=head
|
||||||
|
fast=fast.Next
|
||||||
|
for fast!=slow {
|
||||||
|
fast=fast.Next
|
||||||
|
slow=slow.Next
|
||||||
|
}
|
||||||
|
return slow
|
||||||
|
}
|
||||||
|
fast=fast.Next.Next
|
||||||
|
slow=slow.Next
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -183,7 +183,7 @@ public:
|
|||||||
int end = 0; // 反转的单词在字符串里终止位置
|
int end = 0; // 反转的单词在字符串里终止位置
|
||||||
bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间
|
bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间
|
||||||
for (int i = 0; i < s.size(); i++) { // 开始反转单词
|
for (int i = 0; i < s.size(); i++) { // 开始反转单词
|
||||||
if ((!entry) || (s[i] != ' ' && s[i - 1] == ' ')) {
|
if ((!entry))) {
|
||||||
start = i; // 确定单词起始位置
|
start = i; // 确定单词起始位置
|
||||||
entry = true; // 进入单词区间
|
entry = true; // 进入单词区间
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
输入:k = 2, prices = [3,2,6,5,0,3]
|
输入:k = 2, prices = [3,2,6,5,0,3]
|
||||||
输出:7
|
输出:7
|
||||||
解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4。随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
|
解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4。随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
|
||||||
|
|
||||||
|
|
||||||
提示:
|
提示:
|
||||||
|
|
||||||
@ -167,9 +167,48 @@ public:
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
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:
|
Python:
|
||||||
|
|
||||||
|
@ -122,8 +122,49 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
```Python
|
||||||
|
class Solution:
|
||||||
|
def rob(self, nums: List[int]) -> int:
|
||||||
|
if (n := len(nums)) == 0:
|
||||||
|
return 0
|
||||||
|
if n == 1:
|
||||||
|
return nums[0]
|
||||||
|
result1 = self.robRange(nums, 0, n - 2)
|
||||||
|
result2 = self.robRange(nums, 1, n - 1)
|
||||||
|
return max(result1 , result2)
|
||||||
|
|
||||||
|
def robRange(self, nums: List[int], start: int, end: int) -> int:
|
||||||
|
if end == start: return nums[start]
|
||||||
|
dp = [0] * len(nums)
|
||||||
|
dp[start] = nums[start]
|
||||||
|
dp[start + 1] = max(nums[start], nums[start + 1])
|
||||||
|
for i in range(start + 2, end + 1):
|
||||||
|
dp[i] = max(dp[i -2] + nums[i], dp[i - 1])
|
||||||
|
return dp[end]
|
||||||
|
```
|
||||||
|
|
||||||
|
javascipt:
|
||||||
|
```javascript
|
||||||
|
var rob = function(nums) {
|
||||||
|
const n = nums.length
|
||||||
|
if (n === 0) return 0
|
||||||
|
if (n === 1) return nums[0]
|
||||||
|
const result1 = robRange(nums, 0, n - 2)
|
||||||
|
const result2 = robRange(nums, 1, n - 1)
|
||||||
|
return Math.max(result1, result2)
|
||||||
|
};
|
||||||
|
|
||||||
|
const robRange = (nums, start, end) => {
|
||||||
|
if (end === start) return nums[start]
|
||||||
|
const dp = Array(nums.length).fill(0)
|
||||||
|
dp[start] = nums[start]
|
||||||
|
dp[start + 1] = Math.max(nums[start], nums[start + 1])
|
||||||
|
for (let i = start + 2; i <= end; i++) {
|
||||||
|
dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1])
|
||||||
|
}
|
||||||
|
return dp[end]
|
||||||
|
}
|
||||||
|
```
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ void backtracking(int targetSum, int k, int sum, int startIndex)
|
|||||||
|
|
||||||
所以 终止代码如下:
|
所以 终止代码如下:
|
||||||
|
|
||||||
```
|
```C++
|
||||||
if (path.size() == k) {
|
if (path.size() == k) {
|
||||||
if (sum == targetSum) result.push_back(path);
|
if (sum == targetSum) result.push_back(path);
|
||||||
return; // 如果path.size() == k 但sum != targetSum 直接返回
|
return; // 如果path.size() == k 但sum != targetSum 直接返回
|
||||||
@ -112,7 +112,7 @@ if (path.size() == k) {
|
|||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```
|
```C++
|
||||||
for (int i = startIndex; i <= 9; i++) {
|
for (int i = startIndex; i <= 9; i++) {
|
||||||
sum += i;
|
sum += i;
|
||||||
path.push_back(i);
|
path.push_back(i);
|
||||||
@ -126,7 +126,7 @@ for (int i = startIndex; i <= 9; i++) {
|
|||||||
|
|
||||||
参照[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中的模板,不难写出如下C++代码:
|
参照[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中的模板,不难写出如下C++代码:
|
||||||
|
|
||||||
```
|
```C++
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
vector<vector<int>> result; // 存放结果集
|
vector<vector<int>> result; // 存放结果集
|
||||||
|
@ -156,6 +156,7 @@ public:
|
|||||||
|
|
||||||
Java:
|
Java:
|
||||||
|
|
||||||
|
使用两个 Queue 实现
|
||||||
```java
|
```java
|
||||||
class MyStack {
|
class MyStack {
|
||||||
|
|
||||||
@ -205,7 +206,94 @@ class MyStack {
|
|||||||
* boolean param_4 = obj.empty();
|
* 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:
|
Python:
|
||||||
|
|
||||||
|
@ -131,6 +131,101 @@ public:
|
|||||||
|
|
||||||
Java:
|
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
|
```java
|
||||||
class MyQueue {
|
class MyQueue {
|
||||||
|
|
||||||
@ -190,6 +285,73 @@ Python:
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
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();
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -266,7 +266,34 @@ Python:
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
```Go
|
||||||
|
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
|
||||||
|
// check
|
||||||
|
if root == nil {
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
// 相等 直接返回root节点即可
|
||||||
|
if root == p || root == q {
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
// Divide
|
||||||
|
left := lowestCommonAncestor(root.Left, p, q)
|
||||||
|
right := lowestCommonAncestor(root.Right, p, q)
|
||||||
|
|
||||||
|
// Conquer
|
||||||
|
// 左右两边都不为空,则根节点为祖先
|
||||||
|
if left != nil && right != nil {
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
if left != nil {
|
||||||
|
return left
|
||||||
|
}
|
||||||
|
if right != nil {
|
||||||
|
return right
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -267,7 +267,30 @@ Python:
|
|||||||
|
|
||||||
Go:
|
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;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -77,7 +77,7 @@ if (cur->left == NULL && cur->right == NULL) {
|
|||||||
|
|
||||||
这里我们先使用vector<int>结构的path容器来记录路径,那么终止处理逻辑如下:
|
这里我们先使用vector<int>结构的path容器来记录路径,那么终止处理逻辑如下:
|
||||||
|
|
||||||
```
|
```C++
|
||||||
if (cur->left == NULL && cur->right == NULL) { // 遇到叶子节点
|
if (cur->left == NULL && cur->right == NULL) { // 遇到叶子节点
|
||||||
string sPath;
|
string sPath;
|
||||||
for (int i = 0; i < path.size() - 1; i++) { // 将path里记录的路径转为string格式
|
for (int i = 0; i < path.size() - 1; i++) { // 将path里记录的路径转为string格式
|
||||||
@ -113,7 +113,7 @@ if (cur->right) {
|
|||||||
|
|
||||||
那么回溯要怎么回溯呢,一些同学会这么写,如下:
|
那么回溯要怎么回溯呢,一些同学会这么写,如下:
|
||||||
|
|
||||||
```
|
```C++
|
||||||
if (cur->left) {
|
if (cur->left) {
|
||||||
traversal(cur->left, path, result);
|
traversal(cur->left, path, result);
|
||||||
}
|
}
|
||||||
@ -129,7 +129,7 @@ path.pop_back();
|
|||||||
|
|
||||||
那么代码应该这么写:
|
那么代码应该这么写:
|
||||||
|
|
||||||
```
|
```C++
|
||||||
if (cur->left) {
|
if (cur->left) {
|
||||||
traversal(cur->left, path, result);
|
traversal(cur->left, path, result);
|
||||||
path.pop_back(); // 回溯
|
path.pop_back(); // 回溯
|
||||||
@ -324,8 +324,31 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
```Python
|
||||||
|
# class TreeNode:
|
||||||
|
# def __init__(self, val=0, left=None, right=None):
|
||||||
|
# self.val = val
|
||||||
|
# self.left = left
|
||||||
|
# self.right = right
|
||||||
|
class Solution:
|
||||||
|
def binaryTreePaths(self, root: TreeNode) -> List[str]:
|
||||||
|
path=[]
|
||||||
|
res=[]
|
||||||
|
def backtrace(root, path):
|
||||||
|
if not root:return
|
||||||
|
path.append(root.val)
|
||||||
|
if (not root.left)and (not root.right):
|
||||||
|
res.append(path[:])
|
||||||
|
ways=[]
|
||||||
|
if root.left:ways.append(root.left)
|
||||||
|
if root.right:ways.append(root.right)
|
||||||
|
for way in ways:
|
||||||
|
backtrace(way,path)
|
||||||
|
path.pop()
|
||||||
|
backtrace(root,path)
|
||||||
|
return ["->".join(list(map(str,i))) for i in res]
|
||||||
|
|
||||||
|
```
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,8 +98,6 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
杨老师的这个专栏很不错,他本身也是Oracle 首席工程师,对Java有极其深刻的理解,讲的内容很硬核,适合使用Java语言的录友们用来进阶!作为面试突击手册非常合适, 所以推荐给大家!现在下单输入口令:javahexin,可以省40元那[机智]
|
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
本题最关键的是要想到dp[i]由哪些状态可以推出来,并取最大值,那么很自然就能想到递推公式:dp[i] = max(dp[i], dp[j] + 1);
|
本题最关键的是要想到dp[i]由哪些状态可以推出来,并取最大值,那么很自然就能想到递推公式:dp[i] = max(dp[i], dp[j] + 1);
|
||||||
@ -135,8 +133,33 @@ Python:
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
```go
|
||||||
|
func lengthOfLIS(nums []int ) int {
|
||||||
|
dp := []int{}
|
||||||
|
for _, num := range nums {
|
||||||
|
if len(dp) ==0 || dp[len(dp) - 1] < num {
|
||||||
|
dp = append(dp, num)
|
||||||
|
} else {
|
||||||
|
l, r := 0, len(dp) - 1
|
||||||
|
pos := r
|
||||||
|
for l <= r {
|
||||||
|
mid := (l + r) >> 1
|
||||||
|
if dp[mid] >= num {
|
||||||
|
pos = mid;
|
||||||
|
r = mid - 1
|
||||||
|
} else {
|
||||||
|
l = mid + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dp[pos] = num
|
||||||
|
}//二分查找
|
||||||
|
}
|
||||||
|
return len(dp)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
*复杂度分析*
|
||||||
|
- 时间复杂度:O(nlogn)。数组 nums 的长度为 n,我们依次用数组中的元素去更新 dp 数组,相当于插入最后递增的元素,而更新 dp 数组时需要进行 O(logn) 的二分搜索,所以总时间复杂度为 O(nlogn)。
|
||||||
|
- 空间复杂度:O(n),需要额外使用长度为 n 的 dp 数组。
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -159,9 +159,33 @@ public:
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
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:
|
Python:
|
||||||
|
|
||||||
|
@ -157,7 +157,18 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
||||||
```Go
|
```Go
|
||||||
|
@ -26,7 +26,7 @@ canConstruct("a", "b") -> false
|
|||||||
canConstruct("aa", "ab") -> false
|
canConstruct("aa", "ab") -> false
|
||||||
canConstruct("aa", "aab") -> true
|
canConstruct("aa", "aab") -> true
|
||||||
|
|
||||||
# 思路
|
## 思路
|
||||||
|
|
||||||
这道题目和[242.有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig)很像,[242.有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig)相当于求 字符串a 和 字符串b 是否可以相互组成 ,而这道题目是求 字符串a能否组成字符串b,而不用管字符串b 能不能组成字符串a。
|
这道题目和[242.有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig)很像,[242.有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig)相当于求 字符串a 和 字符串b 是否可以相互组成 ,而这道题目是求 字符串a能否组成字符串b,而不用管字符串b 能不能组成字符串a。
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ canConstruct("aa", "aab") -> true
|
|||||||
|
|
||||||
* 第二点 “你可以假设两个字符串均只含有小写字母。” *说明只有小写字母*,这一点很重要
|
* 第二点 “你可以假设两个字符串均只含有小写字母。” *说明只有小写字母*,这一点很重要
|
||||||
|
|
||||||
# 暴力解法
|
## 暴力解法
|
||||||
|
|
||||||
那么第一个思路其实就是暴力枚举了,两层for循环,不断去寻找,代码如下:
|
那么第一个思路其实就是暴力枚举了,两层for循环,不断去寻找,代码如下:
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ public:
|
|||||||
这里时间复杂度是比较高的,而且里面还有一个字符串删除也就是erase的操作,也是费时的,当然这段代码也可以过这道题。
|
这里时间复杂度是比较高的,而且里面还有一个字符串删除也就是erase的操作,也是费时的,当然这段代码也可以过这道题。
|
||||||
|
|
||||||
|
|
||||||
# 哈希解法
|
## 哈希解法
|
||||||
|
|
||||||
因为题目所只有小写字母,那可以采用空间换取时间的哈希策略, 用一个长度为26的数组还记录magazine里字母出现的次数。
|
因为题目所只有小写字母,那可以采用空间换取时间的哈希策略, 用一个长度为26的数组还记录magazine里字母出现的次数。
|
||||||
|
|
||||||
@ -105,8 +105,6 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
|
@ -205,8 +205,25 @@ class Solution {
|
|||||||
|
|
||||||
|
|
||||||
Python:
|
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 sumOfLeftLeaves(self, root: TreeNode) -> int:
|
||||||
|
self.res=0
|
||||||
|
def areleftleaves(root):
|
||||||
|
if not root:return
|
||||||
|
if root.left and (not root.left.left) and (not root.left.right):self.res+=root.left.val
|
||||||
|
areleftleaves(root.left)
|
||||||
|
areleftleaves(root.right)
|
||||||
|
areleftleaves(root)
|
||||||
|
return self.res
|
||||||
|
```
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
|
||||||
|
@ -211,7 +211,18 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
|
||||||
|
people.sort(key=lambda x: (x[0], -x[1]), reverse=True)
|
||||||
|
que = []
|
||||||
|
for p in people:
|
||||||
|
if p[1] > len(que):
|
||||||
|
que.append(p)
|
||||||
|
else:
|
||||||
|
que.insert(p[1], p)
|
||||||
|
return que
|
||||||
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
@ -187,7 +187,24 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -274,8 +274,28 @@ class Solution {
|
|||||||
|
|
||||||
|
|
||||||
Python:
|
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 findBottomLeftValue(self, root: TreeNode) -> int:
|
||||||
|
depth=0
|
||||||
|
self.res=[]
|
||||||
|
def level(root,depth):
|
||||||
|
if not root:return
|
||||||
|
if depth==len(self.res):
|
||||||
|
self.res.append([])
|
||||||
|
self.res[depth].append(root.val)
|
||||||
|
level(root.left,depth+1)
|
||||||
|
level(root.right,depth+1)
|
||||||
|
level(root,depth)
|
||||||
|
return self.res[-1][0]
|
||||||
|
```
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
|
||||||
|
@ -312,7 +312,23 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -219,9 +219,68 @@ public:
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
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:
|
Python:
|
||||||
|
|
||||||
|
@ -256,7 +256,25 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -212,13 +212,18 @@ Python:
|
|||||||
递归法:
|
递归法:
|
||||||
|
|
||||||
```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:
|
class Solution:
|
||||||
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
|
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
|
||||||
if root is None:
|
if not root or root.val == val: return root //为空或者已经找到都是直接返回root,所以合并了
|
||||||
return None
|
if root.val > val: return self.searchBST(root.left,val) //注意一定要加return
|
||||||
if val < root.val: return self.searchBST(root.left, val)
|
else: return self.searchBST(root.right,val)
|
||||||
elif val > root.val: return self.searchBST(root.right, val)
|
|
||||||
else: return root
|
|
||||||
```
|
```
|
||||||
|
|
||||||
迭代法:
|
迭代法:
|
||||||
|
@ -271,6 +271,20 @@ class Solution:
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
```Go
|
||||||
|
func insertIntoBST(root *TreeNode, val int) *TreeNode {
|
||||||
|
if root == nil {
|
||||||
|
root = &TreeNode{Val: val}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
if root.Val > val {
|
||||||
|
root.Left = insertIntoBST(root.Left, val)
|
||||||
|
} else {
|
||||||
|
root.Right = insertIntoBST(root.Right, val)
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -231,7 +231,165 @@ class MyLinkedList {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -154,9 +154,9 @@ public:
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
```java
|
```java
|
||||||
|
// 贪心思路
|
||||||
class Solution {
|
class Solution {
|
||||||
public int maxProfit(int[] prices, int fee) {
|
public int maxProfit(int[] prices, int fee) {
|
||||||
int buy = prices[0] + 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:
|
Python:
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,7 +95,48 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 卖出时支付手续费
|
||||||
|
* @param prices
|
||||||
|
* @param fee
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int maxProfit(int[] prices, int fee) {
|
||||||
|
int len = prices.length;
|
||||||
|
// 0 : 持股(买入)
|
||||||
|
// 1 : 不持股(售出)
|
||||||
|
// dp 定义第i天持股/不持股 所得最多现金
|
||||||
|
int[][] dp = new int[len][2];
|
||||||
|
dp[0][0] = -prices[0];
|
||||||
|
for (int i = 1; i < len; i++) {
|
||||||
|
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
|
||||||
|
dp[i][1] = Math.max(dp[i - 1][0] + prices[i] - fee, dp[i - 1][1]);
|
||||||
|
}
|
||||||
|
return Math.max(dp[len - 1][0], dp[len - 1][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 买入时支付手续费
|
||||||
|
* @param prices
|
||||||
|
* @param fee
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int maxProfit(int[] prices, int fee) {
|
||||||
|
int len = prices.length;
|
||||||
|
// 0 : 持股(买入)
|
||||||
|
// 1 : 不持股(售出)
|
||||||
|
// dp 定义第i天持股/不持股 所得最多现金
|
||||||
|
int[][] dp = new int[len][2];
|
||||||
|
// 考虑买入的时候就支付手续费
|
||||||
|
dp[0][0] = -prices[0] - fee;
|
||||||
|
for (int i = 1; i < len; 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][0] + prices[i], dp[i - 1][1]);
|
||||||
|
}
|
||||||
|
return Math.max(dp[len - 1][0], dp[len - 1][1]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
|
@ -160,7 +160,28 @@ Python:
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
```Go
|
||||||
|
func findLength(A []int, B []int) int {
|
||||||
|
m, n := len(A), len(B)
|
||||||
|
res := 0
|
||||||
|
dp := make([][]int, m+1)
|
||||||
|
for i := 0; i <= m; i++ {
|
||||||
|
dp[i] = make([]int, n+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i <= m; i++ {
|
||||||
|
for j := 1; j <= n; j++ {
|
||||||
|
if A[i-1] == B[j-1] {
|
||||||
|
dp[i][j] = dp[i-1][j-1] + 1
|
||||||
|
}
|
||||||
|
if dp[i][j] > res {
|
||||||
|
res = dp[i][j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,7 +156,30 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def lemonadeChange(self, bills: List[int]) -> bool:
|
||||||
|
five, ten, twenty = 0, 0, 0
|
||||||
|
for bill in bills:
|
||||||
|
if bill == 5:
|
||||||
|
five += 1
|
||||||
|
elif bill == 10:
|
||||||
|
if five < 1: return False
|
||||||
|
five -= 1
|
||||||
|
ten += 1
|
||||||
|
else:
|
||||||
|
if ten > 0 and five > 0:
|
||||||
|
ten -= 1
|
||||||
|
five -= 1
|
||||||
|
twenty += 1
|
||||||
|
elif five > 2:
|
||||||
|
five -= 3
|
||||||
|
twenty += 1
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
@ -146,7 +146,17 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -166,6 +166,34 @@ class Solution:
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
```Go
|
||||||
|
func longestCommonSubsequence(text1 string, text2 string) int {
|
||||||
|
t1 := len(text1)
|
||||||
|
t2 := len(text2)
|
||||||
|
dp:=make([][]int,t1+1)
|
||||||
|
for i:=range dp{
|
||||||
|
dp[i]=make([]int,t2+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i <= t1; i++ {
|
||||||
|
for j := 1; j <=t2; j++ {
|
||||||
|
if text1[i-1]==text2[j-1]{
|
||||||
|
dp[i][j]=dp[i-1][j-1]+1
|
||||||
|
}else{
|
||||||
|
dp[i][j]=max(dp[i-1][j],dp[i][j-1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[t1][t2]
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(a,b int)int {
|
||||||
|
if a>b{
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -170,7 +170,53 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
```python3
|
||||||
|
# 前序遍历-递归-LC144_二叉树的前序遍历
|
||||||
|
class Solution:
|
||||||
|
def preorderTraversal(self, root: TreeNode) -> List[int]:
|
||||||
|
# 保存结果
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def traversal(root: TreeNode):
|
||||||
|
if root == None:
|
||||||
|
return
|
||||||
|
result.append(root.val) # 前序
|
||||||
|
traversal(root.left) # 左
|
||||||
|
traversal(root.right) # 右
|
||||||
|
|
||||||
|
traversal(root)
|
||||||
|
return result
|
||||||
|
|
||||||
|
# 中序遍历-递归-LC94_二叉树的中序遍历
|
||||||
|
class Solution:
|
||||||
|
def inorderTraversal(self, root: TreeNode) -> List[int]:
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def traversal(root: TreeNode):
|
||||||
|
if root == None:
|
||||||
|
return
|
||||||
|
traversal(root.left) # 左
|
||||||
|
result.append(root.val) # 中序
|
||||||
|
traversal(root.right) # 右
|
||||||
|
|
||||||
|
traversal(root)
|
||||||
|
return result
|
||||||
|
|
||||||
|
# 后序遍历-递归-LC145_二叉树的后序遍历
|
||||||
|
class Solution:
|
||||||
|
def postorderTraversal(self, root: TreeNode) -> List[int]:
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def traversal(root: TreeNode):
|
||||||
|
if root == None:
|
||||||
|
return
|
||||||
|
traversal(root.left) # 左
|
||||||
|
traversal(root.right) # 右
|
||||||
|
result.append(root.val) # 后序
|
||||||
|
|
||||||
|
traversal(root)
|
||||||
|
return result
|
||||||
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
@ -11,13 +11,15 @@
|
|||||||
|
|
||||||
# 看了这么多代码,谈一谈代码风格!
|
# 看了这么多代码,谈一谈代码风格!
|
||||||
|
|
||||||
其实在交流群里经常能看到大家发出来的代码,可以看出很多录友对代码规范应该不甚了解,代码看起来并不舒服。
|
最近看了很多录友在[leetcode-master](https://mp.weixin.qq.com/s/wZRTrA9Rbvgq1yEkSw4vfQ)上提交的代码,发现很多录友的代码其实并不规范,这一点平时在交流群和知识星球里也能看出来。
|
||||||
|
|
||||||
|
很多录友对代码规范应该不甚了解,代码看起来并不舒服。
|
||||||
|
|
||||||
所以呢,我给大家讲一讲代码规范,我主要以C++代码为例。
|
所以呢,我给大家讲一讲代码规范,我主要以C++代码为例。
|
||||||
|
|
||||||
需要强调一下,代码规范并不是仅仅是让代码看着舒服,这是一个很重要的习惯。
|
需要强调一下,代码规范并不是仅仅是让代码看着舒服,这是一个很重要的习惯。
|
||||||
|
|
||||||
# 题外话
|
## 题外话
|
||||||
|
|
||||||
工作之后,**特别是在大厂,看谁的技术牛不牛逼,不用看谁写出多牛逼的代码,就代码风格扫一眼,立刻就能看出来是正规军还是野生程序员**。
|
工作之后,**特别是在大厂,看谁的技术牛不牛逼,不用看谁写出多牛逼的代码,就代码风格扫一眼,立刻就能看出来是正规军还是野生程序员**。
|
||||||
|
|
||||||
@ -25,15 +27,15 @@
|
|||||||
|
|
||||||
现在一些小公司,甚至大公司里的某些技术团队也不注重代码规范,赶进度撸出功能就完事,这种情况就要分两方面看:
|
现在一些小公司,甚至大公司里的某些技术团队也不注重代码规范,赶进度撸出功能就完事,这种情况就要分两方面看:
|
||||||
|
|
||||||
* 第一种情况:这个项目在业务上赚到钱了,每年年终好几十万,那项目前期还关心啥代码风格,赶进度把功能撸出来,赚钱就完事了,例如15年的王者荣耀。
|
* 第一种情况:这个项目在业务上具有巨大潜力,需要抢占市场,只要先站住市场就能赚到钱,每年年终好几十万,那项目前期还关心啥代码风格,赶进度把功能撸出来,赚钱就完事了,例如12年的微信,15年的王者荣耀。这些项目都是后期在不断优化的。
|
||||||
|
|
||||||
* 第二种情况:这个项目没赚到钱,半死不活的,代码还没有设计也没有规范,这样对技术人员的伤害就非常大了。
|
* 第二种情况:这个项目没赚到钱,半死不活的,代码还没有设计也没有规范,这样对技术人员的伤害就非常大了。
|
||||||
|
|
||||||
**而不注重代码风格的团队,99.99%都是第二种情况**,如果你赶上了第一种情况,那就恭喜你了,本文下面的内容可以不用看了,哈哈。
|
**而不注重代码风格的团队,99.99%都是第二种情况**,如果你赶上了第一种情况,那就恭喜你了,本文下面的内容可以不用看了,哈哈。
|
||||||
|
|
||||||
# 代码规范
|
## 代码规范
|
||||||
|
|
||||||
## 变量命名
|
### 变量命名
|
||||||
|
|
||||||
这里我简单说一说规范问题。
|
这里我简单说一说规范问题。
|
||||||
|
|
||||||
@ -67,7 +69,7 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 水平留白(代码空格)
|
### 水平留白(代码空格)
|
||||||
|
|
||||||
经常看到有的同学的代码都堆在一起,看起来都费劲,或者是有的间隔有空格,有的没有空格,很不统一,有的同学甚至为了让代码精简,把所有空格都省略掉了。
|
经常看到有的同学的代码都堆在一起,看起来都费劲,或者是有的间隔有空格,有的没有空格,很不统一,有的同学甚至为了让代码精简,把所有空格都省略掉了。
|
||||||
|
|
||||||
@ -89,7 +91,7 @@ int i, j;
|
|||||||
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++)
|
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++)
|
||||||
```
|
```
|
||||||
|
|
||||||
花括号和函数保持同一行,并有一个空格例如:
|
大括号和函数保持同一行,并有一个空格例如:
|
||||||
|
|
||||||
```
|
```
|
||||||
while (n) {
|
while (n) {
|
||||||
@ -123,9 +125,13 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
当然我并不是说一定要按照Google的规范来,代码风格其实统一就行,没有严格的说谁对谁错。
|
这里关于大括号是否要重启一行?
|
||||||
|
|
||||||
# 总结
|
Google规范是 大括号和 控制语句保持同一行的,我个人也很认可这种写法,因为可以缩短代码的行数,特别是项目中代码行数很多的情况下,这种写法是可以提高阅读代码的效率。
|
||||||
|
|
||||||
|
当然我并不是说一定要按照Google的规范来,**代码风格其实统一就行,没有严格的说谁对谁错**。
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
如果还是学生,使用C++的话,可以按照题解中我的代码风格来,还是比较标准的。
|
如果还是学生,使用C++的话,可以按照题解中我的代码风格来,还是比较标准的。
|
||||||
|
|
||||||
|
@ -7,11 +7,10 @@
|
|||||||
<p align="center"><strong>欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
<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/slM1CH5Ew9XzK93YOQYSjA)
|
1. [关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw)
|
||||||
* [链表的增删改查](https://mp.weixin.qq.com/s/Cf95Lc6brKL4g2j8YyF3Mg)
|
2. [虚拟头结点的技巧](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)
|
||||||
* [反转一个链表](https://mp.weixin.qq.com/s/pnvVP-0ZM7epB8y3w_Njwg)
|
3. [链表的增删改查](https://mp.weixin.qq.com/s/jnC_LAD0ZKCsj-FZc57F1g)
|
||||||
* [有否环形,以及环的入口](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)
|
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:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,7 +92,63 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
|
```Java
|
||||||
|
/**
|
||||||
|
* Definition for singly-linked list.
|
||||||
|
* public class ListNode {
|
||||||
|
* int val;
|
||||||
|
* ListNode next;
|
||||||
|
* ListNode(int x) {
|
||||||
|
* val = x;
|
||||||
|
* next = null;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public class Solution {
|
||||||
|
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
|
||||||
|
ListNode curA = headA;
|
||||||
|
ListNode curB = headB;
|
||||||
|
int lenA = 0, lenB = 0;
|
||||||
|
while (curA != null) { // 求链表A的长度
|
||||||
|
lenA++;
|
||||||
|
curA = curA.next;
|
||||||
|
}
|
||||||
|
while (curB != null) { // 求链表B的长度
|
||||||
|
lenB++;
|
||||||
|
curB = curB.next;
|
||||||
|
}
|
||||||
|
curA = headA;
|
||||||
|
curB = headB;
|
||||||
|
// 让curA为最长链表的头,lenA为其长度
|
||||||
|
if (lenB > lenA) {
|
||||||
|
//1. swap (lenA, lenB);
|
||||||
|
int tmpLen = lenA;
|
||||||
|
lenA = lenB;
|
||||||
|
lenB = tmpLen;
|
||||||
|
//2. swap (curA, curB);
|
||||||
|
ListNode tmpNode = curA;
|
||||||
|
curA = curB;
|
||||||
|
curB = tmpNode;
|
||||||
|
}
|
||||||
|
// 求长度差
|
||||||
|
int gap = lenA - lenB;
|
||||||
|
// 让curA和curB在同一起点上(末尾位置对齐)
|
||||||
|
while (gap-- > 0) {
|
||||||
|
curA = curA.next;
|
||||||
|
}
|
||||||
|
// 遍历curA 和 curB,遇到相同则直接返回
|
||||||
|
while (curA != null) {
|
||||||
|
if (curA == curB) {
|
||||||
|
return curA;
|
||||||
|
}
|
||||||
|
curA = curA.next;
|
||||||
|
curB = curB.next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user