diff --git a/README.md b/README.md index 7eba656d..82c65c7a 100644 --- a/README.md +++ b/README.md @@ -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))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!
@@ -169,10 +170,9 @@
6. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md)
7. [链表:链表相交](./problems/面试题02.07.链表相交.md)
8. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md)
-9. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md)
-10. [哈希表:解决了两数之和,那么能解决三数之和么?](./problems/0015.三数之和.md)
-11. [双指针法:一样的道理,能解决四数之和](./problems/0018.四数之和.md)
-12. [双指针法:总结篇!](./problems/双指针总结.md)
+9. [哈希表:解决了两数之和,那么能解决三数之和么?](./problems/0015.三数之和.md)
+10. [双指针法:一样的道理,能解决四数之和](./problems/0018.四数之和.md)
+11. [双指针法:总结篇!](./problems/双指针总结.md)
## 栈与队列
@@ -409,6 +409,10 @@
(持续更新中....)
+# 贡献者
+
+你可以[点此链接](https://github.com/youngyangyang04/leetcode-master/graphs/contributors)查看LeetCode-Master的所有贡献者。感谢你们补充了LeetCode-Master的其他语言版本,让更多的读者收益于此项目。
+
# 关于作者
大家好,我是程序员Carl,哈工大师兄,ACM 校赛、黑龙江省赛、东北四省赛金牌、亚洲区域赛铜牌获得者,先后在腾讯和百度从事后端技术研发,CSDN博客专家。对算法和C++后端技术有一定的见解,利用工作之余重新刷leetcode。
@@ -420,7 +424,7 @@
-# 我的公众号
+# 公众号
更多精彩文章持续更新,微信搜索:「代码随想录」第一时间围观,关注后回复:「666」可以获得所有算法专题原创PDF。
diff --git a/problems/0001.两数之和.md b/problems/0001.两数之和.md
index 21f798a9..f81c35ca 100644
--- a/problems/0001.两数之和.md
+++ b/problems/0001.两数之和.md
@@ -1,10 +1,10 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 1. 两数之和 @@ -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 []; +}; +``` + @@ -163,4 +178,4 @@ impl Solution { * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -218,8 +218,33 @@ class Solution { ``` Python: - - +```Python +class Solution: + def threeSum(self, nums): + ans = [] + n = len(nums) + nums.sort() + for i in range(n): + left = i + 1 + right = n - 1 + if nums[i] > 0: + break + if i >= 1 and nums[i] == nums[i - 1]: + continue + while left < right: + total = nums[i] + nums[left] + nums[right] + if total > 0: + right -= 1 + elif total < 0: + left += 1 + else: + ans.append([nums[i], nums[left], nums[right]]) + while left != right and nums[left] == nums[left + 1]: left += 1 + while left != right and nums[right] == nums[right - 1]: right -= 1 + left += 1 + right -= 1 + return ans +``` Go: ```Go func threeSum(nums []int)[][]int{ @@ -256,6 +281,59 @@ func threeSum(nums []int)[][]int{ } ``` +javaScript: + +```js +/** + * @param {number[]} nums + * @return {number[][]} + */ + +// 循环内不考虑去重 +var threeSum = function(nums) { + const len = nums.length; + if(len < 3) return []; + nums.sort((a, b) => a - b); + const resSet = new Set(); + for(let i = 0; i < len - 2; i++) { + if(nums[i] > 0) break; + let l = i + 1, r = len - 1; + while(l < r) { + const sum = nums[i] + nums[l] + nums[r]; + if(sum < 0) { l++; continue }; + if(sum > 0) { r--; continue }; + resSet.add(`${nums[i]},${nums[l]},${nums[r]}`); + l++; + r--; + } + } + return Array.from(resSet).map(i => i.split(",")); +}; + +// 去重优化 +var threeSum = function(nums) { + const len = nums.length; + if(len < 3) return []; + nums.sort((a, b) => a - b); + const res = []; + for(let i = 0; i < len - 2; i++) { + if(nums[i] > 0) break; + // a去重 + if(i > 0 && nums[i] === nums[i - 1]) continue; + let l = i + 1, r = len - 1; + while(l < r) { + const sum = nums[i] + nums[l] + nums[r]; + if(sum < 0) { l++; continue }; + if(sum > 0) { r--; continue }; + res.push([nums[i], nums[l], nums[r]]) + // b c 去重 + while(l < r && nums[l] === nums[++l]); + while(l < r && nums[r] === nums[--r]); + } + } + return res; +}; +``` diff --git a/problems/0017.电话号码的字母组合.md b/problems/0017.电话号码的字母组合.md index f06ed80a..ce1f63fb 100644 --- a/problems/0017.电话号码的字母组合.md +++ b/problems/0017.电话号码的字母组合.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 17.电话号码的字母组合 diff --git a/problems/0018.四数之和.md b/problems/0018.四数之和.md index ff441bf7..a1591736 100644 --- a/problems/0018.四数之和.md +++ b/problems/0018.四数之和.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 一样的道理,能解决四数之和 @@ -165,11 +165,75 @@ class Solution { ``` Python: +```python +class Solution(object): + def fourSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[List[int]] + """ + # use a dict to store value:showtimes + hashmap = dict() + for n in nums: + if n in hashmap: + hashmap[n] += 1 + else: + hashmap[n] = 1 + + # good thing about using python is you can use set to drop duplicates. + ans = set() + for i in range(len(nums)): + for j in range(i + 1, len(nums)): + for k in range(j + 1, len(nums)): + val = target - (nums[i] + nums[j] + nums[k]) + if val in hashmap: + # make sure no duplicates. + count = (nums[i] == val) + (nums[j] == val) + (nums[k] == val) + if hashmap[val] > count: + ans.add(tuple(sorted([nums[i], nums[j], nums[k], val]))) + else: + continue + return ans + +``` Go: +javaScript: +```js +/** + * @param {number[]} nums + * @param {number} target + * @return {number[][]} + */ +var fourSum = function(nums, target) { + const len = nums.length; + if(len < 4) return []; + nums.sort((a, b) => a - b); + const res = []; + for(let i = 0; i < len - 3; i++) { + // 去重i + if(i > 0 && nums[i] === nums[i - 1]) continue; + for(let j = i + 1; j < len - 2; j++) { + // 去重j + if(j > i + 1 && nums[j] === nums[j - 1]) continue; + let l = j + 1, r = len - 1; + while(l < r) { + const sum = nums[i] + nums[j] + nums[l] + nums[r]; + if(sum < target) { l++; continue} + if(sum > target) { r--; continue} + res.push([nums[i], nums[j], nums[l], nums[r]]); + while(l < r && nums[l] === nums[++l]); + while(l < r && nums[r] === nums[--r]); + } + } + } + return res; +}; +``` ----------------------- diff --git a/problems/0019.删除链表的倒数第N个节点.md b/problems/0019.删除链表的倒数第N个节点.md index 3b89dabd..65651768 100644 --- a/problems/0019.删除链表的倒数第N个节点.md +++ b/problems/0019.删除链表的倒数第N个节点.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -135,6 +135,28 @@ func removeNthFromEnd(head *ListNode, n int) *ListNode { } ``` +JavaScript: + +```js +/** + * @param {ListNode} head + * @param {number} n + * @return {ListNode} + */ +var removeNthFromEnd = function(head, n) { + let ret = new ListNode(0, head), + slow = fast = ret; + while(n--) fast = fast.next; + if(!fast) return ret.next; + while (fast.next) { + fast = fast.next; + slow = slow.next + }; + slow.next = slow.next.next; + return ret.next; +}; +``` + ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) diff --git a/problems/0020.有效的括号.md b/problems/0020.有效的括号.md index 98cc7cd8..315ff384 100644 --- a/problems/0020.有效的括号.md +++ b/problems/0020.有效的括号.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -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) diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md index 132d65bb..cd8743a7 100644 --- a/problems/0024.两两交换链表中的节点.md +++ b/problems/0024.两两交换链表中的节点.md @@ -1,11 +1,11 @@ - -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+ ## 24. 两两交换链表中的节点 @@ -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) diff --git a/problems/0027.移除元素.md b/problems/0027.移除元素.md index 9481af1f..8da0fb89 100644 --- a/problems/0027.移除元素.md +++ b/problems/0027.移除元素.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 27. 移除元素 diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md index c6463e8b..b8ebcaa1 100644 --- a/problems/0028.实现strStr.md +++ b/problems/0028.实现strStr.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 在一个串中查找是否出现过另一个串,这是KMP的看家本领。 diff --git a/problems/0035.搜索插入位置.md b/problems/0035.搜索插入位置.md index e891e3c5..384e4ad8 100644 --- a/problems/0035.搜索插入位置.md +++ b/problems/0035.搜索插入位置.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -116,7 +116,7 @@ public: **大家要仔细看注释,思考为什么要写while(left <= right), 为什么要写right = middle - 1**。 -``` +```C++ class Solution { public: int searchInsert(vector欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
如果对回溯法理论还不清楚的同学,可以先看这个视频[视频来了!!带你学透回溯算法(理论篇)](https://mp.weixin.qq.com/s/wDd5azGIYWjbU0fdua_qBg) diff --git a/problems/0039.组合总和.md b/problems/0039.组合总和.md index ab118ee0..d025eaef 100644 --- a/problems/0039.组合总和.md +++ b/problems/0039.组合总和.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 39. 组合总和 diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index 50898016..8ff31695 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 这篇可以说是全网把组合问题如何去重,讲的最清晰的了! diff --git a/problems/0045.跳跃游戏II.md b/problems/0045.跳跃游戏II.md index f65ceb9e..31b52b31 100644 --- a/problems/0045.跳跃游戏II.md +++ b/problems/0045.跳跃游戏II.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 相对于[贪心算法:跳跃游戏](https://mp.weixin.qq.com/s/606_N9j8ACKCODoCbV1lSA)难了不少,做好心里准备! @@ -193,6 +193,26 @@ class Solution: ``` Go: +```Go +func jump(nums []int) int { + dp:=make([]int ,len(nums)) + dp[0]=0 + + for i:=1;i欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 46.全排列 @@ -206,14 +206,33 @@ func backtrack(nums,pathNums []int,used []bool){ } } -func permute(nums []int) [][]int { - //var pathNums []int - pathNums:=make([]int,0) - var used=make([]bool,len(nums)) - result=[][]int{} - backtrack(nums,pathNums,used) +Javascript: + +```javascript + +var permute = function(nums) { + let 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 -} +}; + ``` diff --git a/problems/0047.全排列II.md b/problems/0047.全排列II.md index 94bb4df1..b4fb3470 100644 --- a/problems/0047.全排列II.md +++ b/problems/0047.全排列II.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 排列问题(二) ## 47.全排列 II @@ -85,7 +85,7 @@ public: path.clear(); sort(nums.begin(), nums.end()); // 排序 vector欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 第51题. N皇后 diff --git a/problems/0053.最大子序和.md b/problems/0053.最大子序和.md index 6474d01f..0d47a197 100644 --- a/problems/0053.最大子序和.md +++ b/problems/0053.最大子序和.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 53. 最大子序和 @@ -175,31 +175,25 @@ class Solution: ``` 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欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 53. 最大子序和 diff --git a/problems/0055.跳跃游戏.md b/problems/0055.跳跃游戏.md index a25c831a..b4b42a4a 100644 --- a/problems/0055.跳跃游戏.md +++ b/problems/0055.跳跃游戏.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 55. 跳跃游戏 @@ -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欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 56. 合并区间 @@ -168,10 +168,49 @@ class Solution { ``` Python: - +```python +class Solution: + def merge(self, intervals: List[List[int]]) -> List[List[int]]: + if len(intervals) == 0: return intervals + intervals.sort(key=lambda x: x[0]) + result = [] + result.append(intervals[0]) + for i in range(1, len(intervals)): + last = result[-1] + if last[1] >= intervals[i][0]: + result[-1] = [last[0], max(last[1], intervals[i][1])] + else: + result.append(intervals[i]) + return result +``` Go: +```Go +func merge(intervals [][]int) [][]int { + sort.Slice(intervals, func(i, j int) bool { + return intervals[i][0]欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -224,6 +224,49 @@ class Solution: return matrix ``` +javaScript + +```js + +/** + * @param {number} n + * @return {number[][]} + */ +var generateMatrix = function(n) { + // new Array(n).fill(new Array(n)) + // 使用fill --> 填充的是同一个数组地址 + const res = Array.from({length: n}).map(() => new Array(n)); + let loop = n >> 1, i = 0, //循环次数 + count = 1, + startX = startY = 0; // 起始位置 + while(++i <= loop) { + // 定义行列 + let row = startX, column = startY; + // [ startY, n - i) + while(column < n - i) { + res[row][column++] = count++; + } + // [ startX, n - i) + while(row < n - i) { + res[row++][column] = count++; + } + // [n - i , startY) + while(column > startY) { + res[row][column--] = count++; + } + // [n - i , startX) + while(row > startX) { + res[row--][column] = count++; + } + startX = ++startY; + } + if(n & 1) { + res[startX][startY] = count; + } + return res; +}; +``` + ----------------------- diff --git a/problems/0062.不同路径.md b/problems/0062.不同路径.md index e3a6da8c..c4673a23 100644 --- a/problems/0062.不同路径.md +++ b/problems/0062.不同路径.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 62.不同路径 @@ -249,7 +249,24 @@ Python: Go: - +```Go +func uniquePaths(m int, n int) int { + dp := make([][]int, m) + for i := range dp { + dp[i] = make([]int, n) + dp[i][0] = 1 + } + for j := 0; j < n; j++ { + dp[0][j] = 1 + } + for i := 1; i < m; i++ { + for j := 1; j < n; j++ { + dp[i][j] = dp[i-1][j] + dp[i][j-1] + } + } + return dp[m-1][n-1] +} +``` diff --git a/problems/0063.不同路径II.md b/problems/0063.不同路径II.md index 311f712e..72189e0f 100644 --- a/problems/0063.不同路径II.md +++ b/problems/0063.不同路径II.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 63. 不同路径 II @@ -157,8 +157,6 @@ public: * 时间复杂度O(n * m) n m 分别为obstacleGrid 长度和宽度 * 空间复杂度O(n * m) -至于能不能优化空间降为一维dp数组,我感觉不太行,因为要考虑障碍,如果把这些障碍压缩到一行,结果一定就不一样了。 - ## 总结 本题是[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)的障碍版,整体思路大体一致。 diff --git a/problems/0070.爬楼梯.md b/problems/0070.爬楼梯.md index 6cbd6299..f4cb3647 100644 --- a/problems/0070.爬楼梯.md +++ b/problems/0070.爬楼梯.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 70. 爬楼梯 diff --git a/problems/0070.爬楼梯完全背包版本.md b/problems/0070.爬楼梯完全背包版本.md index d6b12450..69750f8f 100644 --- a/problems/0070.爬楼梯完全背包版本.md +++ b/problems/0070.爬楼梯完全背包版本.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:以前我没得选,现在我选择再爬一次! 之前讲这道题目的时候,因为还没有讲背包问题,所以就只是讲了一下爬楼梯最直接的动规方法(斐波那契)。 @@ -157,4 +157,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 72. 编辑距离 diff --git a/problems/0077.组合.md b/problems/0077.组合.md index b0c4941d..82c17494 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -370,8 +370,45 @@ class Solution { Python: +```python +class Solution: + result: List[List[int]] = [] + path: List[int] = [] + def combine(self, n: int, k: int) -> List[List[int]]: + self.result = [] + self.combineHelper(n, k, 1) + return self.result - + def combineHelper(self, n: int, k: int, startIndex: int): + if (l := len(self.path)) == k: + self.result.append(self.path.copy()) + return + for i in range(startIndex, n - (k - l) + 2): + self.path.append(i) + self.combineHelper(n, k, i + 1) + self.path.pop() +``` +javascript +```javascript +let result = [] +let path = [] +var combine = function(n, k) { + result = [] + combineHelper(n, k, 1) + return result +}; +const combineHelper = (n, k, startIndex) => { + if (path.length === k) { + result.push([...path]) + return + } + for (let i = startIndex; i <= n - (k - path.length) + 1; ++i) { + path.push(i) + combineHelper(n, k, i + 1) + path.pop() + } +} +``` Go: ```Go var res [][]int @@ -392,7 +429,7 @@ func backtrack(n,k,start int,track []int){ if len(track)+n-start+1 < k { return } - for i:=start;i<=n;i++{ + for i:=start;i<=n;i++{ track=append(track,i) backtrack(n,k,i+1,track) track=track[:len(track)-1] @@ -401,7 +438,6 @@ func backtrack(n,k,start int,track []int){ ``` - ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) diff --git a/problems/0077.组合优化.md b/problems/0077.组合优化.md index 9994e9eb..52362265 100644 --- a/problems/0077.组合优化.md +++ b/problems/0077.组合优化.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
diff --git a/problems/0078.子集.md b/problems/0078.子集.md index 7166f7fa..a1895eef 100644 --- a/problems/0078.子集.md +++ b/problems/0078.子集.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 第78题. 子集 diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md index 941e3eca..6b12a95b 100644 --- a/problems/0090.子集II.md +++ b/problems/0090.子集II.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 第90题.子集II diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md index 4cea7a3a..3c8e5d9d 100644 --- a/problems/0093.复原IP地址.md +++ b/problems/0093.复原IP地址.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
diff --git a/problems/0096.不同的二叉搜索树.md b/problems/0096.不同的二叉搜索树.md index 7dea8fb0..cee0102f 100644 --- a/problems/0096.不同的二叉搜索树.md +++ b/problems/0096.不同的二叉搜索树.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 96.不同的二叉搜索树 @@ -189,7 +189,18 @@ Python: 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] +} +``` diff --git a/problems/0098.验证二叉搜索树.md b/problems/0098.验证二叉搜索树.md index d8945eff..eb877abb 100644 --- a/problems/0098.验证二叉搜索树.md +++ b/problems/0098.验证二叉搜索树.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 98.验证二叉搜索树 @@ -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" @@ -365,4 +383,4 @@ func isBST(root *TreeNode, min, max int) bool { * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 101. 对称二叉树 diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index 9b5f9ed5..ee93911e 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 二叉树的层序遍历 @@ -79,6 +79,35 @@ public: return result; } }; +``` +javascript代码: + +```javascript +var levelOrder = function(root) { + //二叉树的层序遍历 + let res=[],queue=[]; + queue.push(root); + if(root===null){ + return res; + } + while(queue.length!==0){ + // 记录当前层级节点数 + let length=queue.length; + //存放每一层的节点 + let curLevel=[]; + for(let i=0;i欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
看完本篇可以一起做了如下两道题目: @@ -297,4 +297,4 @@ var maxDepth = function(root) { * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
看完本文,可以一起解决如下两道题目 @@ -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: @@ -643,4 +677,4 @@ var buildTree = function(inorder, postorder) { * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 构造二叉搜索树,一不小心就平衡了 @@ -233,7 +233,27 @@ class Solution { ``` Python: - +```python3 +# 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 sortedArrayToBST(self, nums: List[int]) -> TreeNode: + def buildaTree(left,right): + if left > right: return None #左闭右闭的区间,当区间 left > right的时候,就是空节点,当left = right的时候,不为空 + mid = left + (right - left) // 2 #保证数据不会越界 + val = nums[mid] + root = TreeNode(val) + root.left = buildaTree(left,mid - 1) + root.right = buildaTree(mid + 1,right) + return root + root = buildaTree(0,len(nums) - 1) #左闭右闭区间 + return root +``` Go: @@ -244,4 +264,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 求高度还是求深度,你搞懂了不? diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md index 01b6c89c..8ee15eac 100644 --- a/problems/0111.二叉树的最小深度.md +++ b/problems/0111.二叉树的最小深度.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 和求最大深度一个套路? @@ -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); + } + } +}; +``` + + ----------------------- diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index ecbefd90..65f0fa62 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 递归函数什么时候需要返回值 @@ -349,6 +349,74 @@ 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 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: @@ -427,4 +495,4 @@ let pathSum = function (root, targetSum) { * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 115.不同的子序列 diff --git a/problems/0121.买卖股票的最佳时机.md b/problems/0121.买卖股票的最佳时机.md index a0b35090..0544c93f 100644 --- a/problems/0121.买卖股票的最佳时机.md +++ b/problems/0121.买卖股票的最佳时机.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 121. 买卖股票的最佳时机 @@ -196,9 +196,9 @@ public: ## 其他语言版本 - Java: ```java +// 贪心思路 class Solution { public int maxProfit(int[] prices) { 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: Go: +```Go +func maxProfit(prices []int) int { + length:=len(prices) + if length==0{return 0} + dp:=make([][]int,length) + for i:=0;i欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 122.买卖股票的最佳时机II @@ -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: @@ -172,4 +196,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 122.买卖股票的最佳时机II @@ -136,24 +136,31 @@ Java: ```java // 动态规划 class Solution + // 实现1:二维数组存储 + // 可以将每天持有与否的情况分别用 dp[i][0] 和 dp[i][1] 来进行存储 + // 时间复杂度:O(n),空间复杂度O(n) public int maxProfit(int[] prices) { int n = prices.length; - int[][] dp = new int[n][2]; - dp[0][0] = 0; + int[][] dp = new int[n][2]; // 创建二维数组存储状态 + dp[0][0] = 0; // 初始状态 dp[0][1] = -prices[0]; for (int i = 1; i < n; ++i) { - 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]); + 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]); // 第 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) { int n = prices.length; - int dp0 = 0, dp1 = -prices[0]; + int dp0 = 0, dp1 = -prices[0]; // 定义变量,存储初始状态 for (int i = 1; i < n; ++i) { - int newDp0 = Math.max(dp0, dp1 + prices[i]); - int newDp1 = Math.max(dp1, dp0 - prices[i]); + int newDp0 = Math.max(dp0, dp1 + prices[i]); // 第 i 天,没有股票 + int newDp1 = Math.max(dp1, dp0 - prices[i]); // 第 i 天,持有股票 dp0 = newDp0; dp1 = newDp1; } diff --git a/problems/0123.买卖股票的最佳时机III.md b/problems/0123.买卖股票的最佳时机III.md index 0e718cf1..ecce8dc0 100644 --- a/problems/0123.买卖股票的最佳时机III.md +++ b/problems/0123.买卖股票的最佳时机III.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 123.买卖股票的最佳时机III @@ -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: diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md index 9c86a3bc..9b2401de 100644 --- a/problems/0131.分割回文串.md +++ b/problems/0131.分割回文串.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 切割问题其实是一种组合问题! diff --git a/problems/0134.加油站.md b/problems/0134.加油站.md index 393e4627..5c3f70a8 100644 --- a/problems/0134.加油站.md +++ b/problems/0134.加油站.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 134. 加油站 @@ -223,7 +223,21 @@ class Solution { ``` 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: @@ -234,4 +248,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 135. 分发糖果 @@ -161,7 +161,18 @@ class Solution { ``` 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: @@ -172,4 +183,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:单词拆分 ## 139.单词拆分 @@ -254,7 +254,25 @@ Python: Go: - +```Go +func wordBreak(s string,wordDict []string) bool { + wordDictSet:=make(map[string]bool) + for _,w:=range wordDict{ + wordDictSet[w]=true + } + dp:=make([]bool,len(s)+1) + dp[0]=true + for i:=1;i<=len(s);i++{ + for j:=0;j欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -234,6 +234,73 @@ class Solution: ``` 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 +} +``` + +javaScript + +```js +// 两种循环实现方式 +/** + * @param {ListNode} head + * @return {ListNode} + */ +// 先判断是否是环形链表 +var detectCycle = function(head) { + if(!head || !head.next) return null; + let slow =head.next, fast = head.next.next; + while(fast && fast.next && fast!== slow) { + slow = slow.next; + fast = fast.next.next; + } + if(!fast || !fast.next ) return null; + slow = head; + while (fast !== slow) { + slow = slow.next; + fast = fast.next; + } + return slow; +}; + +var detectCycle = function(head) { + if(!head || !head.next) return null; + let slow =head.next, fast = head.next.next; + while(fast && fast.next) { + slow = slow.next; + fast = fast.next.next; + if(fast == slow) { + slow = head; + while (fast !== slow) { + slow = slow.next; + fast = fast.next; + } + return slow; + } + } + return null; +}; +``` ----------------------- diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md index 12977c39..618a6830 100644 --- a/problems/0150.逆波兰表达式求值.md +++ b/problems/0150.逆波兰表达式求值.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md index 1c567f84..512360fe 100644 --- a/problems/0151.翻转字符串里的单词.md +++ b/problems/0151.翻转字符串里的单词.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -183,7 +183,7 @@ public: int end = 0; // 反转的单词在字符串里终止位置 bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间 for (int i = 0; i < s.size(); i++) { // 开始反转单词 - if ((!entry) || (s[i] != ' ' && s[i - 1] == ' ')) { + if ((!entry))) { start = i; // 确定单词起始位置 entry = true; // 进入单词区间 } diff --git a/problems/0188.买卖股票的最佳时机IV.md b/problems/0188.买卖股票的最佳时机IV.md index 11c5805b..f0adc237 100644 --- a/problems/0188.买卖股票的最佳时机IV.md +++ b/problems/0188.买卖股票的最佳时机IV.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 188.买卖股票的最佳时机IV @@ -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: diff --git a/problems/0198.打家劫舍.md b/problems/0198.打家劫舍.md index 649dd055..8b46a784 100644 --- a/problems/0198.打家劫舍.md +++ b/problems/0198.打家劫舍.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 198.打家劫舍 diff --git a/problems/0202.快乐数.md b/problems/0202.快乐数.md index 8c0dd1e7..06a6914c 100644 --- a/problems/0202.快乐数.md +++ b/problems/0202.快乐数.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -112,6 +112,40 @@ Python: Go: +javaScript: + +```js +function getN(n) { + if (n == 1 || n == 0) return n; + let res = 0; + while (n) { + res += (n % 10) * (n % 10); + n = parseInt(n / 10); + } + return res; +} + +var isHappy = function(n) { + const sumSet = new Set(); + while (n != 1 && !sumSet.has(n)) { + sumSet.add(n); + n = getN(n); + } + return n == 1; +}; + +// 使用环形链表的思想 说明出现闭环 退出循环 +var isHappy = function(n) { + if (getN(n) == 1) return true; + let a = getN(n), b = getN(getN(n)); + // 如果 a === b + while (b !== 1 && getN(b) !== 1 && a !== b) { + a = getN(a); + b = getN(getN(b)); + } + return b === 1 || getN(b) === 1 ; +}; +``` diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md index 9fca1ee0..7735f6c4 100644 --- a/problems/0203.移除链表元素.md +++ b/problems/0203.移除链表元素.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 链表操作中,可以使用原链表来直接进行删除操作,也可以设置一个虚拟头结点在进行删除操作,接下来看一看哪种方式更方便。 @@ -201,6 +201,28 @@ Python: Go: +javaScript: + +```js +/** + * @param {ListNode} head + * @param {number} val + * @return {ListNode} + */ +var removeElements = function(head, val) { + const ret = new ListNode(0, head); + let cur = ret; + while(cur.next) { + if(cur.next.val === val) { + cur.next = cur.next.next; + continue; + } + cur = cur.next; + } + return ret.next; +}; +``` + diff --git a/problems/0206.翻转链表.md b/problems/0206.翻转链表.md index 886bbfcd..52ef6484 100644 --- a/problems/0206.翻转链表.md +++ b/problems/0206.翻转链表.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 反转链表的写法很简单,一些同学甚至可以背下来但过一阵就忘了该咋写,主要是因为没有理解真正的反转过程。 @@ -147,6 +147,90 @@ Python: Go: +```go +//双指针 +func reverseList(head *ListNode) *ListNode { + var pre *ListNode + cur := head + for cur != nil { + next := cur.Next + cur.Next = pre + pre = cur + cur = next + } + return pre +} + +//递归 +func reverseList(head *ListNode) *ListNode { + return help(nil, head) +} + +func help(pre, head *ListNode)*ListNode{ + if head == nil { + return pre + } + next := head.Next + head.Next = pre + return help(head, next) +} + +``` +javaScript: + +```js +/** + * @param {ListNode} head + * @return {ListNode} + */ + +// 双指针: +var reverseList = function(head) { + if(!head || !head.next) return head; + let temp = null, pre = null, cur = head; + while(cur) { + temp = cur.next; + cur.next = pre; + pre = cur; + cur = temp; + } + // temp = cur = null; + return pre; +}; + +// 递归: +var reverse = function(pre, head) { + if(!head) return pre; + const temp = head.next; + head.next = pre; + pre = head + return reverse(pre, temp); +} + +var reverseList = function(head) { + return reverse(null, head); +}; + +// 递归2 +var reverse = function(head) { + if(!head || !head.next) return head; + // 从后往前翻 + const pre = reverse(head.next); + head.next = pre.next; + pre.next = head; + return head; +} + +var reverseList = function(head) { + let cur = head; + while(cur && cur.next) { + cur = cur.next; + } + reverse(head); + return cur; +}; +``` + @@ -154,4 +238,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 209.长度最小的子数组 @@ -172,22 +172,51 @@ Python: Go: +```go +func minSubArrayLen(target int, nums []int) int { + i := 0 + l := len(nums) // 数组长度 + sum := 0 // 子数组之和 + result := l + 1 // 初始化返回长度为l+1,目的是为了判断“不存在符合条件的子数组,返回0”的情况 + for j := 0; j < l; j++ { + sum += nums[j] + for sum >= target { + subLength := j - i + 1 + if subLength < result { + result = subLength + } + sum -= nums[i] + i++ + } + } + if result == l+1 { + return 0 + } else { + return result + } +} +``` JavaScript: -``` -var minSubArrayLen = (target, nums) => { - let left = 0, right = 0,win = Infinity,sum = 0; - while(right < nums.length){ - sum += nums[right]; - while(sum >= target){ - win = right - left + 1 < win? right - left + 1 : win; - sum -= nums[left]; - left++; - } - right++; + +```js + +var minSubArrayLen = function(target, nums) { + // 长度计算一次 + const len = nums.length; + let l = r = sum = 0, + res = len + 1; // 子数组最大不会超过自身 + while(r < len) { + sum += nums[r++]; + // 窗口滑动 + while(sum >= target) { + // r始终为开区间 [l, r) + res = res < r - l ? res : r - l; + sum-=nums[l++]; + } } - return win === Infinity? 0:win; + return res > len ? 0 : res; }; ``` @@ -195,4 +224,4 @@ var minSubArrayLen = (target, nums) => { * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 213.打家劫舍II @@ -122,8 +122,49 @@ class Solution { ``` 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: diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index 21230e0f..67468eb8 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -94,7 +94,7 @@ void backtracking(int targetSum, int k, int sum, int startIndex) 所以 终止代码如下: -``` +```C++ if (path.size() == k) { if (sum == targetSum) result.push_back(path); return; // 如果path.size() == k 但sum != targetSum 直接返回 @@ -112,7 +112,7 @@ if (path.size() == k) { 代码如下: -``` +```C++ for (int i = startIndex; i <= 9; i++) { sum += 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++代码: -``` +```C++ class Solution { private: vector欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 222.完全二叉树的节点个数 @@ -250,4 +250,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -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欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 226.翻转二叉树 @@ -247,10 +247,100 @@ func invertTree(root *TreeNode) *TreeNode { } ``` +JavaScript: +使用递归版本的前序遍历 +```javascript +var invertTree = function(root) { + //1. 首先使用递归版本的前序遍历实现二叉树翻转 + //交换节点函数 + const inverNode=function(left,right){ + let temp=left; + left=right; + right=temp; + //需要重新给root赋值一下 + root.left=left; + root.right=right; + } + //确定递归函数的参数和返回值inverTree=function(root) + //确定终止条件 + if(root===null){ + return root; + } + //确定节点处理逻辑 交换 + inverNode(root.left,root.right); + invertTree(root.left); + invertTree(root.right); + return root; +}; +``` +使用迭代版本(统一模板))的前序遍历: +```javascript +var invertTree = function(root) { + //我们先定义节点交换函数 + const invertNode=function(root,left,right){ + let temp=left; + left=right; + right=temp; + root.left=left; + root.right=right; + } + //使用迭代方法的前序遍历 + let stack=[]; + if(root===null){ + return root; + } + stack.push(root); + while(stack.length){ + let node=stack.pop(); + if(node!==null){ + //前序遍历顺序中左右 入栈顺序是前序遍历的倒序右左中 + node.right&&stack.push(node.right); + node.left&&stack.push(node.left); + stack.push(node); + stack.push(null); + }else{ + node=stack.pop(); + //节点处理逻辑 + invertNode(node,node.left,node.right); + } + } + return root; +}; +``` +使用层序遍历: +```javascript +var invertTree = function(root) { + //我们先定义节点交换函数 + const invertNode=function(root,left,right){ + let temp=left; + left=right; + right=temp; + root.left=left; + root.right=right; + } + //使用层序遍历 + let queue=[]; + if(root===null){ + return root; + } + queue.push(root); + while(queue.length){ + let length=queue.length; + while(length--){ + let node=queue.shift(); + //节点处理逻辑 + invertNode(node,node.left,node.right); + node.left&&queue.push(node.left); + node.right&&queue.push(node.right); + } + } + return root; +}; +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 工作上一定没人这么搞,但是考察对栈、队列理解程度的好题 @@ -131,6 +131,101 @@ public: Java: +使用Stack(堆栈)同名方法: +```java +class MyQueue { + // java中的 Stack 有设计上的缺陷,官方推荐使用 Deque(双端队列) 代替 Stack + Deque欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 235. 二叉搜索树的最近公共祖先 @@ -247,8 +247,23 @@ class Solution { ``` Python: +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None - +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + if not root: return root //中 + if root.val >p.val and root.val > q.val: + return self.lowestCommonAncestor(root.left,p,q) //左 + elif root.val < p.val and root.val < q.val: + return self.lowestCommonAncestor(root.right,p,q) //右 + else: return root +``` Go: @@ -258,4 +273,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 本来是打算将二叉树和二叉搜索树的公共祖先问题一起讲,后来发现篇幅过长了,只能先说一说二叉树的公共祖先问题。 @@ -263,10 +263,53 @@ class Solution { ``` Python: - - +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +//递归 +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + if not root or root == p or root == q: return root //找到了节点p或者q,或者遇到空节点 + left = self.lowestCommonAncestor(root.left,p,q) //左 + right = self.lowestCommonAncestor(root.right,p,q) //右 + if left and right: return root //中: left和right不为空,root就是最近公共节点 + elif left and not right: return left //目标节点是通过left返回的 + elif not left and right: return right //目标节点是通过right返回的 + else: return None //没找到 +``` 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 +} +``` @@ -274,4 +317,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -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; +}; +``` ----------------------- diff --git a/problems/0242.有效的字母异位词.md b/problems/0242.有效的字母异位词.md index 1927f476..6a6faf63 100644 --- a/problems/0242.有效的字母异位词.md +++ b/problems/0242.有效的字母异位词.md @@ -1,26 +1,33 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 数组就是简单的哈希表,但是数组的大小可不是无限开辟的 -# 242.有效的字母异位词 +## 242.有效的字母异位词 https://leetcode-cn.com/problems/valid-anagram/ 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 - +示例 1: +输入: s = "anagram", t = "nagaram" +输出: true + +示例 2: +输入: s = "rat", t = "car" +输出: false + **说明:** 你可以假设字符串只包含小写字母。 -# 思路 +## 思路 先看暴力的解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 O(n^2)。 @@ -52,7 +59,6 @@ https://leetcode-cn.com/problems/valid-anagram/ 时间复杂度为O(n),空间上因为定义是的一个常量大小的辅助数组,所以空间复杂度为O(1)。 -看完这篇哈希表总结:[哈希表:总结篇!(每逢总结必经典)](https://mp.weixin.qq.com/s/1s91yXtarL-PkX07BfnwLg),详细就可以哈希表的各种用法非常清晰了。 C++ 代码如下: ```C++ @@ -134,9 +140,38 @@ func isAnagram(s string, t string) bool { } ``` +javaScript: + +```js +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +var isAnagram = function(s, t) { + if(s.length !== t.length) return false; + const resSet = new Array(26).fill(0); + const base = "a".charCodeAt(); + for(const i of s) { + resSet[i.charCodeAt() - base]++; + } + for(const i of t) { + if(!resSet[i.charCodeAt() - base]) return false; + resSet[i.charCodeAt() - base]--; + } + return true; +}; +``` + +## 相关题目 + +* 383.赎金信 +* 49.字母异位词分组 +* 438.找到字符串中所有字母异位词 + ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 以为只用了递归,其实还用了回溯 @@ -77,7 +77,7 @@ if (cur->left == NULL && cur->right == NULL) { 这里我们先使用vector欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:一样的套路,再求一次完全平方数 ## 279.完全平方数 diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md index 1cdc48b9..02105a7c 100644 --- a/problems/0300.最长上升子序列.md +++ b/problems/0300.最长上升子序列.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 300.最长递增子序列 @@ -98,8 +98,6 @@ public: }; ``` -杨老师的这个专栏很不错,他本身也是Oracle 首席工程师,对Java有极其深刻的理解,讲的内容很硬核,适合使用Java语言的录友们用来进阶!作为面试突击手册非常合适, 所以推荐给大家!现在下单输入口令:javahexin,可以省40元那[机智] - ## 总结 本题最关键的是要想到dp[i]由哪些状态可以推出来,并取最大值,那么很自然就能想到递推公式:dp[i] = max(dp[i], dp[j] + 1); @@ -135,8 +133,33 @@ Python: 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 数组。 ----------------------- diff --git a/problems/0309.最佳买卖股票时机含冷冻期.md b/problems/0309.最佳买卖股票时机含冷冻期.md index 15bba0b7..44ca2b26 100644 --- a/problems/0309.最佳买卖股票时机含冷冻期.md +++ b/problems/0309.最佳买卖股票时机含冷冻期.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 309.最佳买卖股票时机含冷冻期 @@ -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: diff --git a/problems/0322.零钱兑换.md b/problems/0322.零钱兑换.md index e67695d8..ddcd739b 100644 --- a/problems/0322.零钱兑换.md +++ b/problems/0322.零钱兑换.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划: 给我个机会,我再兑换一次零钱 ## 322. 零钱兑换 diff --git a/problems/0332.重新安排行程.md b/problems/0332.重新安排行程.md index 756ecc86..97059e4a 100644 --- a/problems/0332.重新安排行程.md +++ b/problems/0332.重新安排行程.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 这也可以用回溯法? 其实深搜和回溯也是相辅相成的,毕竟都用递归。 @@ -399,6 +399,49 @@ char ** findItinerary(char *** tickets, int ticketsSize, int* ticketsColSize, in } ``` +Javascript: +```Javascript + +var findItinerary = function(tickets) { + let result = ['JFK'] + let map = {} + + for (const tickt of tickets) { + const [from, to] = tickt + if (!map[from]) { + map[from] = [] + } + map[from].push(to) + } + + for (const city in map) { + // 对到达城市列表排序 + map[city].sort() + } + function backtracing() { + if (result.length === tickets.length + 1) { + return true + } + if (!map[result[result.length - 1]] || !map[result[result.length - 1]].length) { + return false + } + for(let i = 0 ; i < map[result[result.length - 1]].length; i++) { + let city = map[result[result.length - 1]][i] + // 删除已走过航线,防止死循环 + map[result[result.length - 1]].splice(i, 1) + result.push(city) + if (backtracing()) { + return true + } + result.pop() + map[result[result.length - 1]].splice(i, 0, city) + } + } + backtracing() + return result +}; + +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0337.打家劫舍III.md b/problems/0337.打家劫舍III.md index 20eea817..58d0e640 100644 --- a/problems/0337.打家劫舍III.md +++ b/problems/0337.打家劫舍III.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 337.打家劫舍 III diff --git a/problems/0343.整数拆分.md b/problems/0343.整数拆分.md index e7550285..a6bd7211 100644 --- a/problems/0343.整数拆分.md +++ b/problems/0343.整数拆分.md @@ -1,13 +1,15 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 343. 整数拆分 +题目链接:https://leetcode-cn.com/problems/integer-break/ + 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 示例 1: @@ -51,9 +53,16 @@ dp[i]的定义讲贯彻整个解题过程,下面哪一步想不懂了,就想 j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。 -那么从1遍历j,比较(i - j) * j和dp[i - j] * j 取最大的。 +**那有同学问了,j怎么就不拆分呢?** + +j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。那么从1遍历j,比较(i - j) * j和dp[i - j] * j 取最大的。递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j)); + +也可以这么理解,j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘。 + +如果定义dp[i - j] * dp[j] 也是默认将一个数强制拆成4份以及4份以上了。 + +所以递推公式:dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j}); -递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j)); 3. dp的初始化 diff --git a/problems/0344.反转字符串.md b/problems/0344.反转字符串.md index b4c843b7..59688e44 100644 --- a/problems/0344.反转字符串.md +++ b/problems/0344.反转字符串.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -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 diff --git a/problems/0347.前K个高频元素.md b/problems/0347.前K个高频元素.md index 0e70f553..841584b4 100644 --- a/problems/0347.前K个高频元素.md +++ b/problems/0347.前K个高频元素.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index b5116ee1..46e15482 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -1,17 +1,18 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费! -# 349. 两个数组的交集 + +## 349. 两个数组的交集 https://leetcode-cn.com/problems/intersection-of-two-arrays/ @@ -23,7 +24,7 @@ https://leetcode-cn.com/problems/intersection-of-two-arrays/ 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。 -# 思路 +## 思路 这道题目,主要要学会使用一种哈希数据结构:unordered_set,这个数据结构可以解决很多类似的问题。 @@ -31,7 +32,7 @@ https://leetcode-cn.com/problems/intersection-of-two-arrays/ 这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。 -那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig),[0383.赎金信](https://mp.weixin.qq.com/s/sYZIR4dFBrw_lr3eJJnteQ) +那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA) 但是要注意,**使用数组来做哈希的题目,是因为题目都限制了数值的大小。** @@ -52,6 +53,7 @@ std::set和std::multiset底层实现都是红黑树,std::unordered_set的底  C++代码如下: + ```C++ class Solution { public: @@ -69,6 +71,13 @@ public: }; ``` +## 拓展 + +那有同学可能问了,遇到哈希问题我直接都用set不就得了,用什么数组啊。 + +直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。 + +不要小瞧 这个耗时,在数据量大的情况,差距是很明显的。 ## 其他语言版本 @@ -113,7 +122,38 @@ Python: Go: +javaScript: +```js +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number[]} + */ +var intersection = function(nums1, nums2) { + // 根据数组大小交换操作的数组 + if(nums1.length < nums2.length) { + const _ = nums1; + nums1 = nums2; + nums2 = _; + } + const nums1Set = new Set(nums1); + const resSet = new Set(); + // for(const n of nums2) { + // nums1Set.has(n) && resSet.add(n); + // } + // 循环 比 迭代器快 + for(let i = nums2.length - 1; i >= 0; i--) { + nums1Set.has(nums2[i]) && resSet.add(nums2[i]); + } + return Array.from(resSet); +}; +``` + + +## 相关题目 + +* 350.两个数组的交集 II ----------------------- diff --git a/problems/0376.摆动序列.md b/problems/0376.摆动序列.md index fa90142d..db80a3e5 100644 --- a/problems/0376.摆动序列.md +++ b/problems/0376.摆动序列.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 本周讲解了[贪心理论基础](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg),以及第一道贪心的题目:[贪心算法:分发饼干](https://mp.weixin.qq.com/s/YSuLIAYyRGlyxbp9BNC1uw),可能会给大家一种贪心算法比较简单的错觉,好了,接下来几天的题目难度要上来了,哈哈。 diff --git a/problems/0377.组合总和Ⅳ.md b/problems/0377.组合总和Ⅳ.md index eca9a13b..6813f13c 100644 --- a/problems/0377.组合总和Ⅳ.md +++ b/problems/0377.组合总和Ⅳ.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:Carl称它为排列总和! ## 377. 组合总和 Ⅳ @@ -191,4 +191,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -26,7 +26,7 @@ canConstruct("a", "b") -> false canConstruct("aa", "ab") -> false 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。 @@ -36,7 +36,7 @@ canConstruct("aa", "aab") -> true * 第二点 “你可以假设两个字符串均只含有小写字母。” *说明只有小写字母*,这一点很重要 -# 暴力解法 +## 暴力解法 那么第一个思路其实就是暴力枚举了,两层for循环,不断去寻找,代码如下: @@ -67,7 +67,7 @@ public: 这里时间复杂度是比较高的,而且里面还有一个字符串删除也就是erase的操作,也是费时的,当然这段代码也可以过这道题。 -# 哈希解法 +## 哈希解法 因为题目所只有小写字母,那可以采用空间换取时间的哈希策略, 用一个长度为26的数组还记录magazine里字母出现的次数。 @@ -105,8 +105,6 @@ public: - - ## 其他语言版本 @@ -138,10 +136,59 @@ class Solution { ``` Python: - +```py +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: +javaScript: + +```js +/** + * @param {string} ransomNote + * @param {string} magazine + * @return {boolean} + */ +var canConstruct = function(ransomNote, magazine) { + const strArr = new Array(26).fill(0), + base = "a".charCodeAt(); + for(const s of magazine) { + strArr[s.charCodeAt() - base]++; + } + for(const s of ransomNote) { + const index = s.charCodeAt() - base; + if(!strArr[index]) return false; + strArr[index]--; + } + return true; +}; +``` diff --git a/problems/0392.判断子序列.md b/problems/0392.判断子序列.md index 95e0b124..512ebc82 100644 --- a/problems/0392.判断子序列.md +++ b/problems/0392.判断子序列.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 392.判断子序列 diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md index 0290dccd..30d702b4 100644 --- a/problems/0404.左叶子之和.md +++ b/problems/0404.左叶子之和.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 404.左叶子之和 @@ -205,17 +205,34 @@ 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 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: + + ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 406.根据身高重建队列 @@ -211,7 +211,18 @@ class Solution { ``` 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: @@ -222,4 +233,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:分割等和子集可以用01背包! ## 416. 分割等和子集 diff --git a/problems/0435.无重叠区间.md b/problems/0435.无重叠区间.md index 4341f3b8..248526a1 100644 --- a/problems/0435.无重叠区间.md +++ b/problems/0435.无重叠区间.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 435. 无重叠区间 @@ -212,7 +212,19 @@ class Solution { ``` Python: - +```python +class Solution: + def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int: + if len(intervals) == 0: return 0 + intervals.sort(key=lambda x: x[1]) + count = 1 # 记录非交叉区间的个数 + end = intervals[0][1] # 记录区间分割点 + for i in range(1, len(intervals)): + if end <= intervals[i][0]: + count += 1 + end = intervals[i][1] + return len(intervals) - count +``` Go: @@ -223,4 +235,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 二叉搜索树删除节点就涉及到结构调整了 @@ -281,7 +281,43 @@ 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 deleteNode(self, root: TreeNode, key: int) -> TreeNode: + if not root: return root #第一种情况:没找到删除的节点,遍历到空节点直接返回了 + if root.val == key: + if not root.left and not root.right: #第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点 + del root + return None + if not root.left and root.right: #第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点 + tmp = root + root = root.right + del tmp + return root + if root.left and not root.right: #第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点 + tmp = root + root = root.left + del tmp + return root + else: #第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置 + v = root.right + while v.left: + v = v.left + v.left = root.left + tmp = root + root = root.right + del tmp + return root + if root.val > key: root.left = self.deleteNode(root.left,key) #左递归 + if root.val < key: root.right = self.deleteNode(root.right,key) #右递归 + return root +``` Go: ```Go @@ -330,4 +366,4 @@ func deleteNode1(root *TreeNode)*TreeNode{ * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 452. 用最少数量的箭引爆气球 @@ -70,7 +70,7 @@ 其实都可以!只不过对应的遍历顺序不同,我就按照气球的起始位置排序了。 -既然按照其实位置排序,那么就从前向后遍历气球数组,靠左尽可能让气球重复。 +既然按照起始位置排序,那么就从前向后遍历气球数组,靠左尽可能让气球重复。 从前向后遍历遇到重叠的气球了怎么办? @@ -167,7 +167,19 @@ class Solution { ``` Python: - +```python +class Solution: + def findMinArrowShots(self, points: List[List[int]]) -> int: + if len(points) == 0: return 0 + points.sort(key=lambda x: x[0]) + result = 1 + for i in range(1, len(points)): + if points[i][0] > points[i - 1][1]: # 气球i和气球i-1不挨着,注意这里不是>= + result += 1 + else: + points[i][1] = min(points[i - 1][1], points[i][1]) # 更新重叠气球最小右边界 + return result +``` Go: @@ -178,4 +190,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 需要哈希的地方都能找到map的身影 @@ -121,9 +121,72 @@ 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: +javaScript: + +```js +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number[]} nums3 + * @param {number[]} nums4 + * @return {number} + */ +var fourSumCount = function(nums1, nums2, nums3, nums4) { + const twoSumMap = new Map(); + let count = 0; + + for(const n1 of nums1) { + for(const n2 of nums2) { + const sum = n1 + n2; + twoSumMap.set(sum, (twoSumMap.get(sum) || 0) + 1) + } + } + + for(const n3 of nums3) { + for(const n4 of nums4) { + const sum = n3 + n4; + count += (twoSumMap.get(0 - sum) || 0) + } + } + + return count; +}; +``` + diff --git a/problems/0455.分发饼干.md b/problems/0455.分发饼干.md index f57a7fa6..2e70b459 100644 --- a/problems/0455.分发饼干.md +++ b/problems/0455.分发饼干.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 455.分发饼干 @@ -145,4 +145,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -149,9 +149,38 @@ public: ## 其他语言版本 - Java: +```java +class Solution { + public boolean repeatedSubstringPattern(String s) { + if (s.equals("")) return false; + + int len = s.length(); + // 原串加个空格(哨兵),使下标从1开始,这样j从0开始,也不用初始化了 + s = " " + s; + char[] chars = s.toCharArray(); + int[] next = new int[len + 1]; + + // 构造 next 数组过程,j从0开始(空格),i从2开始 + for (int i = 2, j = 0; i <= len; i++) { + // 匹配不成功,j回到前一位置 next 数组所对应的值 + while (j > 0 && chars[i] != chars[j + 1]) j = next[j]; + // 匹配成功,j往后移 + if (chars[i] == chars[j + 1]) j++; + // 更新 next 数组的值 + next[i] = j; + } + + // 最后判断是否是重复的子字符串,这里 next[len] 即代表next数组末尾的值 + if (next[len] > 0 && len % (len - next[len]) == 0) { + return true; + } + return false; + } +} +``` + Python: diff --git a/problems/0474.一和零.md b/problems/0474.一和零.md index 4ec5fd4d..e158ca63 100644 --- a/problems/0474.一和零.md +++ b/problems/0474.一和零.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:一和零! ## 474.一和零 diff --git a/problems/0491.递增子序列.md b/problems/0491.递增子序列.md index ebcd9541..691f7aef 100644 --- a/problems/0491.递增子序列.md +++ b/problems/0491.递增子序列.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 和子集问题有点像,但又处处是陷阱 @@ -268,4 +268,4 @@ var findSubsequences = function(nums) { * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:目标和! ## 494. 目标和 @@ -225,7 +225,7 @@ public: 是的,如果仅仅是求个数的话,就可以用dp,但[回溯算法:39. 组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)要求的是把所有组合列出来,还是要使用回溯法爆搜的。 -本地还是有点难度,大家也可以记住,在求装满背包有几种方法的情况下,递推公式一般为: +本题还是有点难度,大家也可以记住,在求装满背包有几种方法的情况下,递推公式一般为: ``` dp[j] += dp[j - nums[i]]; @@ -272,4 +272,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 二叉树上应该怎么求,二叉搜索树上又应该怎么求? @@ -394,8 +394,39 @@ 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 findMode(self, root: TreeNode) -> List[int]: + if not root: return + self.pre = root + self.count = 0 //统计频率 + self.countMax = 0 //最大频率 + self.res = [] + def findNumber(root): + if not root: return None // 第一个节点 + findNumber(root.left) //左 + if self.pre.val == root.val: //中: 与前一个节点数值相同 + self.count += 1 + else: // 与前一个节点数值不同 + self.pre = root + self.count = 1 + if self.count > self.countMax: // 如果计数大于最大值频率 + self.countMax = self.count // 更新最大频率 + self.res = [root.val] //更新res + elif self.count == self.countMax: // 如果和最大值相同,放进res中 + self.res.append(root.val) + findNumber(root.right) //右 + return + findNumber(root) + return self.res +``` Go: @@ -405,4 +436,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 509. 斐波那契数 @@ -187,9 +187,39 @@ 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: +```Go +func fib(n int) int { + if n < 2 { + return n + } + a, b, c := 0, 1, 0 + for i := 1; i < n; i++ { + c = a + b + a, b = b, c + } + return c +} +``` diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index ac21dc68..5c9613e5 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 513.找树左下角的值 @@ -274,8 +274,28 @@ 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 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: @@ -285,4 +305,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 516.最长回文子序列 题目链接:https://leetcode-cn.com/problems/longest-palindromic-subsequence/ @@ -173,6 +173,33 @@ Python: Go: +```Go +func longestPalindromeSubseq(s string) int { + lenth:=len(s) + dp:=make([][]int,lenth) + for i:=0;i欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:给你一些零钱,你要怎么凑? ## 518. 零钱兑换 II diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md index 903ebf78..143bd053 100644 --- a/problems/0530.二叉搜索树的最小绝对差.md +++ b/problems/0530.二叉搜索树的最小绝对差.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 利用二叉搜索树的特性搞起! @@ -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: @@ -188,4 +209,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 538.把二叉搜索树转换为累加树 @@ -196,8 +196,26 @@ class Solution { ``` Python: - - +```python3 +# 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 convertBST(self, root: TreeNode) -> TreeNode: + def buildalist(root): + if not root: return None + buildalist(root.right) #右中左遍历 + root.val += self.pre + self.pre = root.val + buildalist(root.left) + self.pre = 0 #记录前一个节点的数值 + buildalist(root) + return root +``` Go: @@ -207,4 +225,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -134,6 +134,36 @@ class Solution { ``` Python: +```python + +class Solution(object): + def reverseStr(self, s, k): + """ + :type s: str + :type k: int + :rtype: str + """ + from functools import reduce + # turn s into a list + s = list(s) + + # another way to simply use a[::-1], but i feel this is easier to understand + def reverse(s): + left, right = 0, len(s) - 1 + while left < right: + s[left], s[right] = s[right], s[left] + left += 1 + right -= 1 + return s + + # make sure we reverse each 2k elements + for i in range(0, len(s), 2*k): + s[i:(i+k)] = reverse(s[i:(i+k)]) + + # combine list into str. + return reduce(lambda a, b: a+b, s) + +``` Go: diff --git a/problems/0583.两个字符串的删除操作.md b/problems/0583.两个字符串的删除操作.md index 9679347a..cd550d65 100644 --- a/problems/0583.两个字符串的删除操作.md +++ b/problems/0583.两个字符串的删除操作.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 583. 两个字符串的删除操作 diff --git a/problems/0617.合并二叉树.md b/problems/0617.合并二叉树.md index 848454de..d65275f0 100644 --- a/problems/0617.合并二叉树.md +++ b/problems/0617.合并二叉树.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 617.合并二叉树 @@ -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: @@ -323,4 +339,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 647. 回文子串 @@ -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: diff --git a/problems/0654.最大二叉树.md b/problems/0654.最大二叉树.md index 905bcbae..ea8c15cd 100644 --- a/problems/0654.最大二叉树.md +++ b/problems/0654.最大二叉树.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 654.最大二叉树 @@ -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: @@ -267,4 +285,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 如果不对递归有深刻的理解,本题有点难 @@ -265,8 +265,24 @@ class Solution { ``` Python: - - +```python3 +# 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 trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode: + if not root: return root + if root.val < low: + return self.trimBST(root.right,low,high) // 寻找符合区间[low, high]的节点 + if root.val > high: + return self.trimBST(root.left,low,high) // 寻找符合区间[low, high]的节点 + root.left = self.trimBST(root.left,low,high) // root->left接入符合条件的左孩子 + root.right = self.trimBST(root.right,low,high) // root->right接入符合条件的右孩子 + return root +``` Go: @@ -276,4 +292,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 674. 最长连续递增序列 diff --git a/problems/0700.二叉搜索树中的搜索.md b/problems/0700.二叉搜索树中的搜索.md index 277ef681..25a06617 100644 --- a/problems/0700.二叉搜索树中的搜索.md +++ b/problems/0700.二叉搜索树中的搜索.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 700.二叉搜索树中的搜索 @@ -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) + ``` 迭代法: @@ -243,4 +248,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 701.二叉搜索树中的插入操作 @@ -271,6 +271,20 @@ class Solution: 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 +} +``` @@ -279,4 +293,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 704. 二分查找 @@ -14,17 +14,17 @@ 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 -示例 1: -输入: nums = [-1,0,3,5,9,12], target = 9 -输出: 4 -解释: 9 出现在 nums 中并且下标为 4 +示例 1: +输入: nums = [-1,0,3,5,9,12], target = 9 +输出: 4 +解释: 9 出现在 nums 中并且下标为 4 -示例 2: -输入: nums = [-1,0,3,5,9,12], target = 2 -输出: -1 -解释: 2 不存在 nums 中因此返回 -1 +示例 2: +输入: nums = [-1,0,3,5,9,12], target = 2 +输出: -1 +解释: 2 不存在 nums 中因此返回 -1 -提示: +提示: * 你可以假设 nums 中的所有元素是不重复的。 * n 将在 [1, 10000]之间。 @@ -153,6 +153,10 @@ Java: ```java class Solution { public int search(int[] nums, int target) { + // 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算 + if (target < nums[0] || target > nums[nums.length - 1]) { + return -1; + } int left = 0, right = nums.length - 1; while (left <= right) { int mid = left + ((right - left) >> 1); @@ -210,6 +214,84 @@ class Solution: Go: +(版本一)左闭右闭区间 + +```go +func search(nums []int, target int) int { + high := len(nums)-1 + low := 0 + for low <= high { + mid := low + (high-low)/2 + if nums[mid] == target { + return mid + } else if nums[mid] > target { + high = mid-1 + } else { + low = mid+1 + } + } + return -1 +} +``` + +(版本二)左闭右开区间 + +```go +func search(nums []int, target int) int { + high := len(nums) + low := 0 + for low < high { + mid := low + (high-low)/2 + if nums[mid] == target { + return mid + } else if nums[mid] > target { + high = mid + } else { + low = mid+1 + } + } + return -1 +} +``` + +javaScript + +```js + +// (版本一)左闭右闭区间 + +var search = function(nums, target) { + let l = 0, r = nums.length - 1; + // 区间 [l, r] + while(l <= r) { + let mid = (l + r) >> 1; + if(nums[mid] === target) return mid; + let isSmall = nums[mid] < target; + l = isSmall ? mid + 1 : l; + r = isSmall ? r : mid - 1; + } + return -1; +}; + +// (版本二)左闭右开区间 + +var search = function(nums, target) { + let l = 0, r = nums.length; + // 区间 [l, r) + while(l < r) { + let mid = (l + r) >> 1; + if(nums[mid] === target) return mid; + let isSmall = nums[mid] < target; + l = isSmall ? mid + 1 : l; + // 所以 mid 不会被取到 + r = isSmall ? r : mid; + } + return -1; +}; + +``` + + @@ -217,4 +299,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 听说这道题目把链表常见的五个操作都覆盖了? @@ -231,10 +231,425 @@ 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: +```go +//循环双链表 +type MyLinkedList struct { + dummy *Node +} + +type Node struct { + Val int + Next *Node + Pre *Node +} + +//仅保存哑节点,pre-> rear, next-> head +/** Initialize your data structure here. */ +func Constructor() MyLinkedList { + rear := &Node{ + Val: -1, + Next: nil, + Pre: nil, + } + rear.Next = rear + rear.Pre = rear + return MyLinkedList{rear} +} + +/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */ +func (this *MyLinkedList) Get(index int) int { + head := this.dummy.Next + //head == this, 遍历完全 + for head != this.dummy && index > 0 { + index-- + head = head.Next + } + //否则, head == this, 索引无效 + if 0 != index { + return -1 + } + return head.Val +} + +/** 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. */ +func (this *MyLinkedList) AddAtHead(val int) { + dummy := this.dummy + node := &Node{ + Val: val, + //head.Next指向原头节点 + Next: dummy.Next, + //head.Pre 指向哑节点 + Pre: dummy, + } + + //更新原头节点 + dummy.Next.Pre = node + //更新哑节点 + dummy.Next = node + //以上两步不能反 +} + +/** Append a node of value val to the last element of the linked list. */ +func (this *MyLinkedList) AddAtTail(val int) { + dummy := this.dummy + rear := &Node{ + Val: val, + //rear.Next = dummy(哑节点) + Next: dummy, + //rear.Pre = ori_rear + Pre: dummy.Pre, + } + + //ori_rear.Next = rear + dummy.Pre.Next = rear + //update dummy + dummy.Pre = rear + //以上两步不能反 +} + +/** 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. */ +func (this *MyLinkedList) AddAtIndex(index int, val int) { + head := this.dummy.Next + //head = MyLinkedList[index] + for head != this.dummy && index > 0 { + head = head.Next + index-- + } + node := &Node{ + Val: val, + //node.Next = MyLinkedList[index] + Next: head, + //node.Pre = MyLinkedList[index-1] + Pre: head.Pre, + } + //MyLinkedList[index-1].Next = node + head.Pre.Next = node + //MyLinkedList[index].Pre = node + head.Pre = node + //以上两步不能反 +} + +/** Delete the index-th node in the linked list, if the index is valid. */ +func (this *MyLinkedList) DeleteAtIndex(index int) { + //链表为空 + if this.dummy.Next == this.dummy { + return + } + head := this.dummy.Next + //head = MyLinkedList[index] + for head.Next != this.dummy && index > 0 { + head = head.Next + index-- + } + //验证index有效 + if index == 0 { + //MyLinkedList[index].Pre = index[index-2] + head.Next.Pre = head.Pre + //MyLinedList[index-2].Next = index[index] + head.Pre.Next = head.Next + //以上两步顺序无所谓 + } +} +``` + +javaScript: + +```js + +class LinkNode { + constructor(val, next) { + this.val = val; + this.next = next; + } +} + +/** + * Initialize your data structure here. + * 单链表 储存头尾节点 和 节点数量 + */ +var MyLinkedList = function() { + this._size = 0; + this._tail = null; + this._head = null; +}; + +/** + * Get the value of the index-th node in the linked list. If the index is invalid, return -1. + * @param {number} index + * @return {number} + */ +MyLinkedList.prototype.getNode = function(index) { + if(index < 0 || index >= this._size) return null; + // 创建虚拟头节点 + let cur = new LinkNode(0, this._head); + // 0 -> head + while(index-- >= 0) { + cur = cur.next; + } + return cur; +}; +MyLinkedList.prototype.get = function(index) { + if(index < 0 || index >= this._size) return -1; + // 获取当前节点 + return this.getNode(index).val; +}; + +/** + * 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. + * @param {number} val + * @return {void} + */ +MyLinkedList.prototype.addAtHead = function(val) { + const node = new LinkNode(val, this._head); + this._head = node; + this._size++; + if(!this._tail) { + this._tail = node; + } +}; + +/** + * Append a node of value val to the last element of the linked list. + * @param {number} val + * @return {void} + */ +MyLinkedList.prototype.addAtTail = function(val) { + const node = new LinkNode(val, null); + this._size++; + if(this._tail) { + this._tail.next = node; + this._tail = node; + return; + } + this._tail = node; + this._head = node; +}; + +/** + * 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. + * @param {number} index + * @param {number} val + * @return {void} + */ +MyLinkedList.prototype.addAtIndex = function(index, val) { + if(index > this._size) return; + if(index <= 0) { + this.addAtHead(val); + return; + } + if(index === this._size) { + this.addAtTail(val); + return; + } + // 获取目标节点的上一个的节点 + const node = this.getNode(index - 1); + node.next = new LinkNode(val, node.next); + this._size++; +}; + +/** + * Delete the index-th node in the linked list, if the index is valid. + * @param {number} index + * @return {void} + */ +MyLinkedList.prototype.deleteAtIndex = function(index) { + if(index < 0 || index >= this._size) return; + if(index === 0) { + this._head = this._head.next; + this._size--; + return; + } + // 获取目标节点的上一个的节点 + const node = this.getNode(index - 1); + node.next = node.next.next; + // 处理尾节点 + if(index === this._size - 1) { + this._tail = node; + } + this._size--; +}; + +// MyLinkedList.prototype.out = function() { +// let cur = this._head; +// const res = []; +// while(cur) { +// res.push(cur.val); +// cur = cur.next; +// } +// }; +/** + * Your MyLinkedList object will be instantiated and called as such: + * var obj = new MyLinkedList() + * var param_1 = obj.get(index) + * obj.addAtHead(val) + * obj.addAtTail(val) + * obj.addAtIndex(index,val) + * obj.deleteAtIndex(index) + */ +``` + diff --git a/problems/0714.买卖股票的最佳时机含手续费.md b/problems/0714.买卖股票的最佳时机含手续费.md index 86954c14..abd20625 100644 --- a/problems/0714.买卖股票的最佳时机含手续费.md +++ b/problems/0714.买卖股票的最佳时机含手续费.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 714. 买卖股票的最佳时机含手续费 @@ -154,9 +154,9 @@ public: ## 其他语言版本 - Java: ```java +// 贪心思路 class Solution { public int maxProfit(int[] prices, int fee) { int buy = prices[0] + fee; @@ -174,8 +174,46 @@ class Solution { } ``` -Python: +```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 +class Solution: # 贪心思路 + def maxProfit(self, prices: List[int], fee: int) -> int: + result = 0 + minPrice = prices[0] + for i in range(1, len(prices)): + if prices[i] < minPrice: + minPrice = prices[i] + elif prices[i] >= minPrice and prices[i] <= minPrice + fee: + continue + else: + result += prices[i] - minPrice - fee + minPrice = prices[i] - fee + return result +``` Go: diff --git a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md index 3926643d..14b5859b 100644 --- a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md +++ b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 714.买卖股票的最佳时机含手续费 @@ -95,7 +95,48 @@ public: 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: diff --git a/problems/0718.最长重复子数组.md b/problems/0718.最长重复子数组.md index c20ea79f..3a377077 100644 --- a/problems/0718.最长重复子数组.md +++ b/problems/0718.最长重复子数组.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 718. 最长重复子数组 @@ -160,7 +160,28 @@ Python: 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 +} +``` diff --git a/problems/0738.单调递增的数字.md b/problems/0738.单调递增的数字.md index dc136028..5bddb234 100644 --- a/problems/0738.单调递增的数字.md +++ b/problems/0738.单调递增的数字.md @@ -1,13 +1,14 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 738.单调递增的数字 +题目链接: https://leetcode-cn.com/problems/monotone-increasing-digits/ 给定一个非负整数 N,找出小于或等于 N 的最大的整数,同时这个整数需要满足其各个位数上的数字是单调递增。 @@ -30,7 +31,7 @@ ## 暴力解法 -题意很简单,那么首先想的就是暴力解法了,来我提大家暴力一波,结果自然是超时! +题意很简单,那么首先想的就是暴力解法了,来我替大家暴力一波,结果自然是超时! 代码如下: ```C++ @@ -146,7 +147,19 @@ class Solution { Python: - +```python +class Solution: + def monotoneIncreasingDigits(self, n: int) -> int: + strNum = list(str(n)) + flag = len(strNum) + for i in range(len(strNum) - 1, 0, -1): + if int(strNum[i]) < int(strNum[i - 1]): + strNum[i - 1] = str(int(strNum[i - 1]) - 1) + flag = i + for i in range(flag, len(strNum)): + strNum[i] = '9' + return int("".join(strNum)) +``` Go: @@ -157,4 +170,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 746. 使用最小花费爬楼梯 @@ -228,7 +228,23 @@ Python: Go: +```Go +func minCostClimbingStairs(cost []int) int { + dp := make([]int, len(cost)) + dp[0], dp[1] = cost[0], cost[1] + for i := 2; i < len(cost); i++ { + dp[i] = min(dp[i-1], dp[i-2]) + cost[i] + } + return min(dp[len(cost)-1], dp[len(cost)-2]) +} +func min(a, b int) int { + if a < b { + return a + } + return b +} +``` diff --git a/problems/0763.划分字母区间.md b/problems/0763.划分字母区间.md index c1474280..bcdd71dc 100644 --- a/problems/0763.划分字母区间.md +++ b/problems/0763.划分字母区间.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 763.划分字母区间 @@ -108,7 +108,23 @@ class Solution { ``` Python: +```python +class Solution: + def partitionLabels(self, s: str) -> List[int]: + hash = [0] * 26 + for i in range(len(s)): + hash[ord(s[i]) - ord('a')] = i + result = [] + left = 0 + right = 0 + for i in range(len(s)): + right = max(right, hash[ord(s[i]) - ord('a')]) + if i == right: + result.append(right - left + 1) + left = i + 1 + return result +``` Go: diff --git a/problems/0860.柠檬水找零.md b/problems/0860.柠檬水找零.md index bf8a3776..faee2e56 100644 --- a/problems/0860.柠檬水找零.md +++ b/problems/0860.柠檬水找零.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 860.柠檬水找零 @@ -156,7 +156,30 @@ class Solution { ``` 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: @@ -167,4 +190,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 968.监控二叉树 @@ -357,4 +357,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 1005.K次取反后最大化的数组和 diff --git a/problems/1035.不相交的线.md b/problems/1035.不相交的线.md index 6f2b6646..039030d2 100644 --- a/problems/1035.不相交的线.md +++ b/problems/1035.不相交的线.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 1035.不相交的线 @@ -73,7 +73,24 @@ public: Java: - + ```java + class Solution { + public int maxUncrossedLines(int[] A, int[] B) { + int [][] dp = new int[A.length+1][B.length+1]; + for(int i=1;i<=A.length;i++) { + for(int j=1;j<=B.length;j++) { + if (A[i-1]==B[j-1]) { + dp[i][j]=dp[i-1][j-1]+1; + } + else { + dp[i][j]=Math.max(dp[i-1][j], dp[i][j-1]); + } + } + } + return dp[A.length][B.length]; + } +} + ``` Python: diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md index d5a8c4ed..8b761be7 100644 --- a/problems/1047.删除字符串中的所有相邻重复项.md +++ b/problems/1047.删除字符串中的所有相邻重复项.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -122,6 +122,8 @@ public: Java: + +使用 Deque 作为堆栈 ```Java class Solution { public String removeDuplicates(String S) { @@ -144,9 +146,43 @@ class Solution { } } ``` +拿字符串直接作为栈,省去了栈还要转为字符串的操作。 +```Java +class Solution { + public String removeDuplicates(String s) { + // 将 res 当做栈 + StringBuffer res = new StringBuffer(); + // top为 res 的长度 + int top = -1; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + // 当 top > 0,即栈中有字符时,当前字符如果和栈中字符相等,弹出栈顶字符,同时 top-- + if (top >= 0 && res.charAt(top) == c) { + res.deleteCharAt(top); + top--; + // 否则,将该字符 入栈,同时top++ + } else { + res.append(c); + top++; + } + } + return res.toString(); + } +} +``` 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: diff --git a/problems/1049.最后一块石头的重量II.md b/problems/1049.最后一块石头的重量II.md index 0ffd6a3e..fcd3712a 100644 --- a/problems/1049.最后一块石头的重量II.md +++ b/problems/1049.最后一块石头的重量II.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:最后一块石头的重量 II ## 1049. 最后一块石头的重量 II diff --git a/problems/1143.最长公共子序列.md b/problems/1143.最长公共子序列.md index 19f4cc72..2ddab584 100644 --- a/problems/1143.最长公共子序列.md +++ b/problems/1143.最长公共子序列.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 1143.最长公共子序列 @@ -166,6 +166,34 @@ class Solution: 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 +} +``` @@ -174,4 +202,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 程序提交之后为什么会超时?O(n)的算法会超时,n究竟是多大? diff --git a/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md b/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md index 60334d1f..353bd68e 100644 --- a/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md +++ b/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划之编辑距离总结篇 diff --git a/problems/二叉树中递归带着回溯.md b/problems/二叉树中递归带着回溯.md index bf15e39b..2adb826c 100644 --- a/problems/二叉树中递归带着回溯.md +++ b/problems/二叉树中递归带着回溯.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 二叉树:以为使用了递归,其实还隐藏着回溯 @@ -175,7 +175,85 @@ if (cur->right) { Java: + 100. 相同的树:递归代码 + ```java + class Solution { + public boolean compare(TreeNode tree1, TreeNode tree2) { + + if(tree1==null && tree2==null)return true; + if(tree1==null || tree2==null)return false; + if(tree1.val!=tree2.val)return false; + // 此时就是:左右节点都不为空,且数值相同的情况 + // 此时才做递归,做下一层的判断 + boolean compareLeft = compare(tree1.left, tree2.left); // 左子树:左、 右子树:左 + boolean compareRight = compare(tree1.right, tree2.right); // 左子树:右、 右子树:右 + boolean isSame = compareLeft && compareRight; // 左子树:中、 右子树:中(逻辑处理) + return isSame; + } + boolean isSameTree(TreeNode p, TreeNode q) { + return compare(p, q); + } +} + ``` + 257. 二叉树的所有路径: 回溯代码 + ```java + class Solution { + public void traversal(TreeNode cur, List欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 二叉树:总结篇!(需要掌握的二叉树技能都在这里了) diff --git a/problems/二叉树理论基础.md b/problems/二叉树理论基础.md index 60e65c69..55383e91 100644 --- a/problems/二叉树理论基础.md +++ b/problems/二叉树理论基础.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 二叉树理论基础篇 我们要开启新的征程了,大家跟上! diff --git a/problems/二叉树的理论基础.md b/problems/二叉树的理论基础.md index 271e1f4e..4b52e511 100644 --- a/problems/二叉树的理论基础.md +++ b/problems/二叉树的理论基础.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 二叉树理论基础 diff --git a/problems/二叉树的统一迭代法.md b/problems/二叉树的统一迭代法.md index 3ea4eeaf..dca5d3e3 100644 --- a/problems/二叉树的统一迭代法.md +++ b/problems/二叉树的统一迭代法.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -153,13 +153,226 @@ public: Java: + 迭代法前序遍历代码如下: + ```java + class Solution { + + public List欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 二叉树的迭代遍历 @@ -160,11 +160,239 @@ 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欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
@@ -170,7 +170,53 @@ class Solution { ``` 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: @@ -180,7 +226,7 @@ func PreorderTraversal(root *TreeNode) (res []int) { var traversal func(node *TreeNode) traversal = func(node *TreeNode) { if node == nil { - return + return } res = append(res,node.Val) traversal(node.Left) @@ -226,6 +272,94 @@ func PostorderTraversal(root *TreeNode) (res []int) { } ``` +javaScript: + +```js + +前序遍历: + +var preorderTraversal = function(root, res = []) { + if (!root) return res; + res.push(root.val); + preorderTraversal(root.left, res) + preorderTraversal(root.right, res) + return res; +}; + +中序遍历: + +var inorderTraversal = function(root, res = []) { + if (!root) return res; + inorderTraversal(root.left, res); + res.push(root.val); + inorderTraversal(root.right, res); + return res; +}; + +后序遍历: + +var postorderTraversal = function(root, res = []) { + if (!root) return res; + postorderTraversal(root.left, res); + postorderTraversal(root.right, res); + res.push(root.val); + return res; +}; +``` +Javascript版本: + +前序遍历: +```Javascript +var preorderTraversal = function(root) { + let res=[]; + const dfs=function(root){ + if(root===null)return ; + //先序遍历所以从父节点开始 + res.push(root.val); + //递归左子树 + dfs(root.left); + //递归右子树 + dfs(root.right); + } + //只使用一个参数 使用闭包进行存储结果 + dfs(root); + return res; +}; +``` +中序遍历 +```javascript +var inorderTraversal = function(root) { + let res=[]; + const dfs=function(root){ + if(root===null){ + return ; + } + dfs(root.left); + res.push(root.val); + dfs(root.right); + } + dfs(root); + return res; +}; +``` + +后序遍历 +```javascript +var postorderTraversal = function(root) { + let res=[]; + const dfs=function(root){ + if(root===null){ + return ; + } + dfs(root.left); + dfs(root.right); + res.push(root.val); + } + dfs(root); + return res; +}; +``` + diff --git a/problems/关于时间复杂度,你不知道的都在这里!.md b/problems/关于时间复杂度,你不知道的都在这里!.md index b4ff89fa..fe378228 100644 --- a/problems/关于时间复杂度,你不知道的都在这里!.md +++ b/problems/关于时间复杂度,你不知道的都在这里!.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
相信每一位录友都接触过时间复杂度,「代码随想录」已经也讲了一百多道经典题目了,是时候对时间复杂度来一个深度的剖析了,很早之前就写过一篇,当时文章还没有人看,Carl感觉有价值的东西值得让更多的人看到,哈哈。 diff --git a/problems/前序/代码风格.md b/problems/前序/代码风格.md index 2be1ac36..e4378b4e 100644 --- a/problems/前序/代码风格.md +++ b/problems/前序/代码风格.md @@ -9,15 +9,17 @@ -------------------------- -# 看了这么多代码,谈一谈代码风格! +# 看了这么多代码,谈一谈代码风格! -其实在交流群里经常能看到大家发出来的代码,可以看出很多录友对代码规范应该不甚了解,代码看起来并不舒服。 +最近看了很多录友在[leetcode-master](https://mp.weixin.qq.com/s/wZRTrA9Rbvgq1yEkSw4vfQ)上提交的代码,发现很多录友的代码其实并不规范,这一点平时在交流群和知识星球里也能看出来。 + +很多录友对代码规范应该不甚了解,代码看起来并不舒服。 所以呢,我给大家讲一讲代码规范,我主要以C++代码为例。 需要强调一下,代码规范并不是仅仅是让代码看着舒服,这是一个很重要的习惯。 -# 题外话 +## 题外话 工作之后,**特别是在大厂,看谁的技术牛不牛逼,不用看谁写出多牛逼的代码,就代码风格扫一眼,立刻就能看出来是正规军还是野生程序员**。 @@ -25,15 +27,15 @@ 现在一些小公司,甚至大公司里的某些技术团队也不注重代码规范,赶进度撸出功能就完事,这种情况就要分两方面看: -* 第一种情况:这个项目在业务上赚到钱了,每年年终好几十万,那项目前期还关心啥代码风格,赶进度把功能撸出来,赚钱就完事了,例如15年的王者荣耀。 +* 第一种情况:这个项目在业务上具有巨大潜力,需要抢占市场,只要先站住市场就能赚到钱,每年年终好几十万,那项目前期还关心啥代码风格,赶进度把功能撸出来,赚钱就完事了,例如12年的微信,15年的王者荣耀。这些项目都是后期在不断优化的。 * 第二种情况:这个项目没赚到钱,半死不活的,代码还没有设计也没有规范,这样对技术人员的伤害就非常大了。 **而不注重代码风格的团队,99.99%都是第二种情况**,如果你赶上了第一种情况,那就恭喜你了,本文下面的内容可以不用看了,哈哈。 -# 代码规范 +## 代码规范 -## 变量命名 +### 变量命名 这里我简单说一说规范问题。 @@ -67,7 +69,7 @@  -## 水平留白(代码空格) +### 水平留白(代码空格) 经常看到有的同学的代码都堆在一起,看起来都费劲,或者是有的间隔有空格,有的没有空格,很不统一,有的同学甚至为了让代码精简,把所有空格都省略掉了。 @@ -89,7 +91,7 @@ int i, j; for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) ``` -花括号和函数保持同一行,并有一个空格例如: +大括号和函数保持同一行,并有一个空格例如: ``` while (n) { @@ -123,9 +125,13 @@ public: }; ``` -当然我并不是说一定要按照Google的规范来,代码风格其实统一就行,没有严格的说谁对谁错。 +这里关于大括号是否要重启一行? -# 总结 +Google规范是 大括号和 控制语句保持同一行的,我个人也很认可这种写法,因为可以缩短代码的行数,特别是项目中代码行数很多的情况下,这种写法是可以提高阅读代码的效率。 + +当然我并不是说一定要按照Google的规范来,**代码风格其实统一就行,没有严格的说谁对谁错**。 + +## 总结 如果还是学生,使用C++的话,可以按照题解中我的代码风格来,还是比较标准的。 diff --git a/problems/剑指Offer05.替换空格.md b/problems/剑指Offer05.替换空格.md index 5f89241b..794f9ac5 100644 --- a/problems/剑指Offer05.替换空格.md +++ b/problems/剑指Offer05.替换空格.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 题目:剑指Offer 05.替换空格 diff --git a/problems/剑指Offer58-II.左旋转字符串.md b/problems/剑指Offer58-II.左旋转字符串.md index 3e9ab11f..648546c1 100644 --- a/problems/剑指Offer58-II.左旋转字符串.md +++ b/problems/剑指Offer58-II.左旋转字符串.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 反转个字符串还有这么多用处? @@ -96,10 +96,27 @@ public: ## 其他语言版本 - Java: - - +```java +class Solution { + public String reverseLeftWords(String s, int n) { + int len=s.length(); + StringBuilder sb=new StringBuilder(s); + reverseString(sb,0,n-1); + reverseString(sb,n,len-1); + return sb.reverse().toString(); + } + public void reverseString(StringBuilder sb, int start, int end) { + while (start < end) { + char temp = sb.charAt(start); + sb.setCharAt(start, sb.charAt(end)); + sb.setCharAt(end, temp); + start++; + end--; + } + } +} +``` Python: diff --git a/problems/动态规划-股票问题总结篇.md b/problems/动态规划-股票问题总结篇.md index 370eea58..cac77b65 100644 --- a/problems/动态规划-股票问题总结篇.md +++ b/problems/动态规划-股票问题总结篇.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
之前我们已经把力扣上股票系列的题目都讲过的,但没有来一篇股票总结,来帮大家高屋建瓴,所以总结篇这就来了! diff --git a/problems/动态规划理论基础.md b/problems/动态规划理论基础.md index ae02e69a..250fa57d 100644 --- a/problems/动态规划理论基础.md +++ b/problems/动态规划理论基础.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 什么是动态规划 diff --git a/problems/双指针总结.md b/problems/双指针总结.md index 5ee1b4f6..13f2f174 100644 --- a/problems/双指针总结.md +++ b/problems/双指针总结.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 又是一波总结 diff --git a/problems/哈希表总结.md b/problems/哈希表总结.md index d10f934a..a578a203 100644 --- a/problems/哈希表总结.md +++ b/problems/哈希表总结.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 哈希表总结篇如约而至 diff --git a/problems/哈希表理论基础.md b/problems/哈希表理论基础.md index ba097239..f78dc241 100644 --- a/problems/哈希表理论基础.md +++ b/problems/哈希表理论基础.md @@ -1,17 +1,18 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-# 哈希表 + +## 哈希表 首先什么是 哈希表,哈希表(英文名字为Hash table,国内也有一些算法书籍翻译为散列表,大家看到这两个名称知道都是指hash table就可以了)。 -> 哈希表是根据关键码的值而直接进行访问的数据结构。 +> 哈希表是根据关键码的值而直接进行访问的数据结构。 这么这官方的解释可能有点懵,其实直白来讲其实数组就是一张哈希表。 @@ -19,17 +20,17 @@  -那么哈希表能解决什么问题呢,**一般哈希表都是用来快速判断一个元素是否出现集合里。** +那么哈希表能解决什么问题呢,**一般哈希表都是用来快速判断一个元素是否出现集合里。** -例如要查询一个名字是否在这所学校里。 +例如要查询一个名字是否在这所学校里。 -要枚举的话时间复杂度是O(n),但如果使用哈希表的话, 只需要O(1) 就可以做到。 +要枚举的话时间复杂度是O(n),但如果使用哈希表的话, 只需要O(1) 就可以做到。 我们只需要初始化把这所学校里学生的名字都存在哈希表里,在查询的时候通过索引直接就可以知道这位同学在不在这所学校里了。 将学生姓名映射到哈希表上就涉及到了**hash function ,也就是哈希函数**。 -# 哈希函数 +## 哈希函数 哈希函数,把学生的姓名直接映射为哈希表上的索引,然后就可以通过查询索引下表快速知道这位同学是否在这所学校里了。 @@ -37,7 +38,7 @@  -如果hashCode得到的数值大于 哈希表的大小了,也就是大于tableSize了,怎么办呢? +如果hashCode得到的数值大于 哈希表的大小了,也就是大于tableSize了,怎么办呢? 此时为了保证映射出来的索引数值都落在哈希表上,我们会在再次对数值做一个取模的操作,就要我们就保证了学生姓名一定可以映射到哈希表上了。 @@ -47,7 +48,7 @@ 接下来**哈希碰撞**登场 -# 哈希碰撞 +### 哈希碰撞 如图所示,小李和小王都映射到了索引下表 1的位置,**这一现象叫做哈希碰撞**。 @@ -55,7 +56,7 @@ 一般哈希碰撞有两种解决方法, 拉链法和线性探测法。 -## 拉链法 +### 拉链法 刚刚小李和小王在索引1的位置发生了冲突,发生冲突的元素都被存储在链表中。 这样我们就可以通过索引找到小李和小王了 @@ -65,7 +66,7 @@ 其实拉链法就是要选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间。 -## 线性探测法 +### 线性探测法 使用线性探测法,一定要保证tableSize大于dataSize。 我们需要依靠哈希表中的空位来解决碰撞问题。 @@ -75,13 +76,13 @@ 其实关于哈希碰撞还有非常多的细节,感兴趣的同学可以再好好研究一下,这里我就不再赘述了。 -# 常见的三种哈希结构 +## 常见的三种哈希结构 当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构。 * 数组 * set (集合) -* map(映射) +* map(映射) 这里数组就没啥可说的了,我们来看一下set。 @@ -117,7 +118,7 @@ std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底  -# 总结 +## 总结 总结一下,**当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法**。 @@ -125,23 +126,6 @@ std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底 如果在做面试题目的时候遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法! -预告下篇讲解一波哈希表面试题的解题套路,我们下期见! - -都看到这了,还有sei!sei没读懂单独找我! - - - -## 其他语言版本 - - -Java: - - -Python: - - -Go: - diff --git a/problems/回溯总结.md b/problems/回溯总结.md index db9c9c61..793df516 100644 --- a/problems/回溯总结.md +++ b/problems/回溯总结.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 20张树形结构图、14道精选回溯题目,21篇回溯法精讲文章,由浅入深,一气呵成,这是全网最强回溯算法总结! diff --git a/problems/回溯算法去重问题的另一种写法.md b/problems/回溯算法去重问题的另一种写法.md index be69b068..19a4ae3b 100644 --- a/problems/回溯算法去重问题的另一种写法.md +++ b/problems/回溯算法去重问题的另一种写法.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 回溯算法去重问题的另一种写法 diff --git a/problems/回溯算法理论基础.md b/problems/回溯算法理论基础.md index 8bfd101c..35e9db0f 100644 --- a/problems/回溯算法理论基础.md +++ b/problems/回溯算法理论基础.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 可以配合我的B站视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/) 一起学习! diff --git a/problems/字符串总结.md b/problems/字符串总结.md index 11e29c42..21fdc9bc 100644 --- a/problems/字符串总结.md +++ b/problems/字符串总结.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 字符串:总结篇 diff --git a/problems/数组总结篇.md b/problems/数组总结篇.md index d8daa866..2c679493 100644 --- a/problems/数组总结篇.md +++ b/problems/数组总结篇.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
diff --git a/problems/数组理论基础.md b/problems/数组理论基础.md index a2c86ac4..b2837375 100644 --- a/problems/数组理论基础.md +++ b/problems/数组理论基础.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
diff --git a/problems/栈与队列总结.md b/problems/栈与队列总结.md index 754e84aa..b3bb5c47 100644 --- a/problems/栈与队列总结.md +++ b/problems/栈与队列总结.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 栈与队列的理论基础 diff --git a/problems/栈与队列理论基础.md b/problems/栈与队列理论基础.md index 5230fa53..04f99981 100644 --- a/problems/栈与队列理论基础.md +++ b/problems/栈与队列理论基础.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
> 来看看栈和队列不为人知的一面 diff --git a/problems/根据身高重建队列(vector原理讲解).md b/problems/根据身高重建队列(vector原理讲解).md index e7dac2ad..c548f6d8 100644 --- a/problems/根据身高重建队列(vector原理讲解).md +++ b/problems/根据身高重建队列(vector原理讲解).md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 贪心算法:根据身高重建队列(续集) 在讲解[贪心算法:根据身高重建队列](https://mp.weixin.qq.com/s/-2TgZVdOwS-DvtbjjDEbfw)中,我们提到了使用vector(C++中的动态数组)来进行insert操作是费时的。 diff --git a/problems/算法模板.md b/problems/算法模板.md index 133c798d..3b9eee8c 100644 --- a/problems/算法模板.md +++ b/problems/算法模板.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 二分查找法 diff --git a/problems/背包总结篇.md b/problems/背包总结篇.md index 16b84ba5..c04dfbec 100644 --- a/problems/背包总结篇.md +++ b/problems/背包总结篇.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 听说背包问题很难? 这篇总结篇来拯救你了 年前我们已经把背包问题都讲完了,那么现在我们要对背包问题进行总结一番。 diff --git a/problems/背包理论基础01背包-1.md b/problems/背包理论基础01背包-1.md index 8055d481..a78d9232 100644 --- a/problems/背包理论基础01背包-1.md +++ b/problems/背包理论基础01背包-1.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:关于01背包问题,你该了解这些! 这周我们正式开始讲解背包问题! @@ -102,30 +102,13 @@ leetcode上没有纯01背包的问题,都是01背包应用方面的题目, dp[0][j],即:i为0,存放编号0的物品的时候,各个容量的背包所能存放的最大价值。 代码如下: - -``` -// 倒叙遍历 -for (int j = bagWeight; j >= weight[0]; j--) { - dp[0][j] = dp[0][j - weight[0]] + value[0]; // 初始化i为0时候的情况 -} -``` - -**大家应该发现,这个初始化为什么是倒叙的遍历的?正序遍历就不行么?** - -正序遍历还真就不行,dp[0][j]表示容量为j的背包存放物品0时候的最大价值,物品0的价值就是15,因为题目中说了**每个物品只有一个!**所以dp[0][j]如果不是初始值的话,就应该都是物品0的价值,也就是15。 - -但如果一旦正序遍历了,那么物品0就会被重复加入多次! 例如代码如下: ``` // 正序遍历 for (int j = weight[0]; j <= bagWeight; j++) { - dp[0][j] = dp[0][j - weight[0]] + value[0]; + dp[0][j] = value[0]; } ``` -例如dp[0][1] 是15,到了dp[0][2] = dp[0][2 - 1] + 15; 也就是dp[0][2] = 30 了,那么就是物品0被重复放入了。 - -**所以一定要倒叙遍历,保证物品0只被放入一次!这一点对01背包很重要,后面在讲解滚动数组的时候,还会用到倒叙遍历来保证物品使用一次!** - 此时dp数组初始化情况如图所示: @@ -138,16 +121,23 @@ dp[i][j]在推导的时候一定是取价值最大的数,如果题目给的价 如果题目给的价值有负数,那么非0下标就要初始化为负无穷了。例如:一个物品的价值是-2,但对应的位置依然初始化为0,那么取最大值的时候,就会取0而不是-2了,所以要初始化为负无穷。 +而背包问题的物品价值都是正整数,所以初始化为0,就可以了。 + **这样才能让dp数组在递归公式的过程中取最大的价值,而不是被初始值覆盖了**。 +如图: + + + 最后初始化代码如下: ``` // 初始化 dp vector欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:关于01背包问题,你该了解这些!(滚动数组) 昨天[动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)中是用二维dp数组来讲解01背包。 @@ -104,7 +104,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品 为什么呢? -**倒叙遍历是为了保证物品i只被放入一次!**,在[动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)中讲解二维dp数组初始化dp[0][j]时候已经讲解到过一次。 +**倒叙遍历是为了保证物品i只被放入一次!**。但如果一旦正序遍历了,那么物品0就会被重复加入多次! 举一个例子:物品0的重量weight[0] = 1,价值value[0] = 15 @@ -152,7 +152,7 @@ dp[1] = dp[1 - weight[0]] + value[0] = 15 ## 一维dp01背包完整C++测试代码 -``` +```C++ void test_1_wei_bag_problem() { vector欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:关于01背包问题,你该了解这些!(滚动数组) diff --git a/problems/背包理论基础01背包-二维DP.md b/problems/背包理论基础01背包-二维DP.md index b504daa6..2b334dc9 100644 --- a/problems/背包理论基础01背包-二维DP.md +++ b/problems/背包理论基础01背包-二维DP.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 背包问题理论基础 diff --git a/problems/背包问题理论基础多重背包.md b/problems/背包问题理论基础多重背包.md index 1f0ad4c0..26890a2b 100644 --- a/problems/背包问题理论基础多重背包.md +++ b/problems/背包问题理论基础多重背包.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:关于多重背包,你该了解这些! 之前我们已经体统的讲解了01背包和完全背包,如果没有看过的录友,建议先把如下三篇文章仔细阅读一波。 diff --git a/problems/背包问题理论基础完全背包.md b/problems/背包问题理论基础完全背包.md index b91c99fd..02785ad7 100644 --- a/problems/背包问题理论基础完全背包.md +++ b/problems/背包问题理论基础完全背包.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 动态规划:关于完全背包,你该了解这些! ## 完全背包 diff --git a/problems/贪心算法总结篇.md b/problems/贪心算法总结篇.md index 01029d62..999797ad 100644 --- a/problems/贪心算法总结篇.md +++ b/problems/贪心算法总结篇.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
我刚刚开始讲解贪心系列的时候就说了,贪心系列并不打算严格的从简单到困难这么个顺序来讲解。 diff --git a/problems/贪心算法理论基础.md b/problems/贪心算法理论基础.md index 74efad83..5385aa60 100644 --- a/problems/贪心算法理论基础.md +++ b/problems/贪心算法理论基础.md @@ -1,10 +1,10 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 关于贪心算法,你该了解这些! diff --git a/problems/链表总结篇.md b/problems/链表总结篇.md index e709ec9b..6404dd6e 100644 --- a/problems/链表总结篇.md +++ b/problems/链表总结篇.md @@ -1,17 +1,16 @@ -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-> 之前链表篇没有做总结,所以是时候总结一波 -# 链表的理论基础 +## 链表的理论基础 -在这篇文章[关于链表,你该了解这些!](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)看了,即文章中如下的地方: - -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 关于链表,你该了解这些! diff --git a/problems/面试题02.07.链表相交.md b/problems/面试题02.07.链表相交.md index 97045ed2..9e97264c 100644 --- a/problems/面试题02.07.链表相交.md +++ b/problems/面试题02.07.链表相交.md @@ -1,11 +1,11 @@ - -欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+ ## 面试题 02.07. 链表相交 @@ -92,13 +92,105 @@ public: 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: Go: +javaScript: + +```js +/** + * @param {ListNode} headA + * @param {ListNode} headB + * @return {ListNode} + */ +var getListLen = function(head) { + let len = 0, cur = head; + while(cur) { + len++; + cur = cur.next; + } + return len; +} +var getIntersectionNode = function(headA, headB) { + let curA = headA,curB = headB, + lenA = getListLen(headA), + lenB = getListLen(headB); + if(lenA < lenB) { + [curA, curB] = [curB, curA]; + [lenA, lenB] = [lenB, lenA]; + } + let i = lenA - lenB; + while(i-- > 0) { + curA = curA.next + } + while(curA && curA !== curB) { + curA = curA.next; + curB = curB.next; + } + return curA; +}; +``` +