diff --git a/README.md b/README.md index 276c8313..7eba656d 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,17 @@ 很多刚开始刷题的同学都有一个困惑:面对leetcode上近两千道题目,从何刷起。 +大家平时刷题感觉效率低,浪费的时间主要在三点: + +* 找题 +* 找到了不应该现阶段做的题 +* 没有全套的优质题解可以参考 + 其实我之前在知乎上回答过这个问题,回答内容大概是按照如下类型来刷数组-> 链表-> 哈希表->字符串->栈与队列->树->回溯->贪心->动态规划->图论->高级数据结构,再从简单刷起,做了几个类型题目之后,再慢慢做中等题目、困难题目。 但我能设身处地的感受到:即使有这样一个整体规划,对于一位初学者甚至算法老手寻找合适自己的题目也是很困难,时间成本很高,而且题目还不一定就是经典题目。 -对于刷题,我们都是想用最短的时间把经典题目都做一篇,这样效率才是最高的! +对于刷题,我们都是想用最短的时间**按照循序渐进的难度顺序把经典题目都做一遍**,这样效率才是最高的! 所以我整理了leetcode刷题攻略:一个超级详细的刷题顺序,**每道题目都是我精心筛选,都是经典题目高频面试题**,大家只要按照这个顺序刷就可以了,**你没看错,就是题目顺序都排好了,文章顺序就是刷题顺序!挨个刷就可以,不用自己再去题海里选题了!** @@ -49,15 +55,18 @@ **目前已经更新了,数组-> 链表-> 哈希表->字符串->栈与队列->树->回溯->贪心,八个专题了,正在讲解动态规划!** -在刷题指南中,每个专题开始都有理论基础篇,并不像是教科书般的理论介绍,而是从实战中归纳需要的基础知识。每个专题结束都有总结篇,最这个专题的归纳总结。 +在刷题攻略中,每个专题开始都有理论基础篇,并不像是教科书般的理论介绍,而是从实战中归纳需要的基础知识。每个专题结束都有总结篇,最这个专题的归纳总结。 如果你是算法老手,这篇攻略也是复习的最佳资料,如果把每个系列对应的总结篇,快速过一遍,整个算法知识体系以及各种解法就重现脑海了。 -在按照如下顺序刷题的过程中,每一道题解一定要看对应文章下面的留言(留言目前只能在手机端查看)。 -如果你有疑问或者发现文章哪里有不对的地方,都可以在留言区都能找到答案,还有很多录友的总结非常赞,看完之后也很有收获。 +目前「代码随想录」刷题攻略更新了:**200多篇文章,精讲了200道经典算法题目,共60w字的详细图解,部分难点题目还搭配了20分钟左右的视频讲解**。 -目前「代码随想录」刷题指南更新了:**200多篇文章,精讲了200道经典算法题目,共60w字的详细图解,部分难点题目还搭配了20分钟左右的视频讲解**。 +**这里每一篇题解,都是精品,值得仔细琢磨**。 + +我在题目讲解中统一用C++语言,但你会发现下面几乎每篇题解都配有其他语言版本,Java、Python、Go、JavaScript等等,这正是热心小伙们的贡献的代码,当然我也会严格把控代码质量。 + +**所以也欢迎大家参与进来,完善题解的各个语言版本,拥抱开源,让更多小伙伴们收益**。 准备好了么,刷题攻略开始咯,go go go! @@ -66,7 +75,7 @@ ## 前序 * [「代码随想录」后序安排](https://mp.weixin.qq.com/s/4eeGJREy6E-v6D7cR_5A4g) -* [「代码随想录」学习社区](https://mp.weixin.qq.com/s/X1XCH-KevURi3LnakJsCkA) +* [「代码随想录」学习社区](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) * 编程语言 @@ -119,8 +128,9 @@ 4. [链表:听说过两天反转链表又写不出来了?](./problems/0206.翻转链表.md) 5. [链表:两两交换链表中的节点](./problems/0024.两两交换链表中的节点.md) 6. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md) -7. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md) -8. [链表:总结篇!](./problems/链表总结篇.md) +7. [链表:链表相交](./problems/面试题02.07.链表相交.md) +8. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md) +9. [链表:总结篇!](./problems/链表总结篇.md) ## 哈希表 @@ -156,11 +166,13 @@ 3. [字符串:替换空格](./problems/剑指Offer05.替换空格.md) 4. [字符串:花式反转还不够!](./problems/0151.翻转字符串里的单词.md) 5. [链表:听说过两天反转链表又写不出来了?](./problems/0206.翻转链表.md) -6. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md) -7. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md) -8. [哈希表:解决了两数之和,那么能解决三数之和么?](./problems/0015.三数之和.md) -9. [双指针法:一样的道理,能解决四数之和](./problems/0018.四数之和.md) -10. [双指针法:总结篇!](./problems/双指针总结.md) +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) ## 栈与队列 diff --git a/problems/0015.三数之和.md b/problems/0015.三数之和.md index 55e22887..96dc1ac3 100644 --- a/problems/0015.三数之和.md +++ b/problems/0015.三数之和.md @@ -221,6 +221,40 @@ Python: Go: +```Go +func threeSum(nums []int)[][]int{ + sort.Ints(nums) + res:=[][]int{} + + for i:=0;i0{ + break + } + if i>0&&n1==nums[i-1]{ + continue + } + l,r:=i+1,len(nums)-1 + for l list = new ArrayList<>(); + + public List letterCombinations(String digits) { + if (digits == null || digits.length() == 0) { + return list; + } + //初始对应所有的数字,为了直接对应2-9,新增了两个无效的字符串"" + String[] numString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; + //迭代处理 + backTracking(digits, numString, 0); + return list; + + } + + //每次迭代获取一个字符串,所以会设计大量的字符串拼接,所以这里选择更为高效的 StringBuild + StringBuilder temp = new StringBuilder(); + + //比如digits如果为"23",num 为0,则str表示2对应的 abc + public void backTracking(String digits, String[] numString, int num) { + //遍历全部一次记录一次得到的字符串 + if (num == digits.length()) { + list.add(temp.toString()); + return; + } + //str 表示当前num对应的字符串 + String str = numString[digits.charAt(num) - '0']; + for (int i = 0; i < str.length(); i++) { + temp.append(str.charAt(i)); + //回溯 + backTracking(digits, numString, num + 1); + //剔除末尾的继续尝试 + temp.deleteCharAt(temp.length() - 1); + } + } +} +``` Python: diff --git a/problems/0019.删除链表的倒数第N个节点.md b/problems/0019.删除链表的倒数第N个节点.md index 3b6dde1e..3b89dabd 100644 --- a/problems/0019.删除链表的倒数第N个节点.md +++ b/problems/0019.删除链表的倒数第N个节点.md @@ -112,7 +112,28 @@ class Solution { } } ``` +Go: +```Go +func removeNthFromEnd(head *ListNode, n int) *ListNode { + result:=&ListNode{} + result.Next=head + var pre *ListNode + cur:=result + i:=1 + for head!=nil{ + if i>=n{ + pre=cur + cur=cur.Next + } + head=head.Next + i++ + } + pre.Next=pre.Next.Next + return result.Next + +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0020.有效的括号.md b/problems/0020.有效的括号.md index f2d78ade..98cc7cd8 100644 --- a/problems/0020.有效的括号.md +++ b/problems/0020.有效的括号.md @@ -138,7 +138,58 @@ public: Java: +```Java +class Solution { + public boolean isValid(String s) { + Deque deque = new LinkedList<>(); + char ch; + for (int i = 0; i < s.length(); i++) { + ch = s.charAt(i); + //碰到左括号,就把相应的右括号入栈 + if (ch == '(') { + deque.push(')'); + }else if (ch == '{') { + deque.push('}'); + }else if (ch == '[') { + deque.push(']'); + } else if (deque.isEmpty() || deque.peek() != ch) { + return false; + }else {//如果是右括号判断是否和栈顶元素匹配 + deque.pop(); + } + } + //最后判断栈中元素是否匹配 + return deque.isEmpty(); + } +} +// 方法2 +class Solution { + public boolean isValid(String s) { + Stack stack = new Stack<>(); + Map map = new HashMap() { + { + put('}', '{'); + put(']', '['); + put(')', '('); + } + }; + + for (Character c : s.toCharArray()) { // 顺序读取字符 + if (!stack.isEmpty() && map.containsKey(c)) { // 是右括号 && 栈不为空 + if (stack.peek() == map.get(c)) { // 取其对应的左括号直接和栈顶比 + stack.pop(); // 相同则抵消,出栈 + } else { + return false; // 不同则直接返回 + } + } else { + stack.push(c); // 左括号,直接入栈 + } + } + return stack.isEmpty(); // 看左右是否抵消完 + } +} +``` Python: ```python3 @@ -157,8 +208,44 @@ class Solution: ``` Go: +```Go +func isValid(s string) bool { + hash := map[byte]byte{')':'(', ']':'[', '}':'{'} + stack := make([]byte, 0) + if s == "" { + return true + } + for i := 0; i < len(s); i++ { + if s[i] == '(' || s[i] == '[' || s[i] == '{' { + stack = append(stack, s[i]) + } else if len(stack) > 0 && stack[len(stack)-1] == hash[s[i]] { + stack = stack[:len(stack)-1] + } else { + return false + } + } + return len(stack) == 0 +} +``` +Ruby: +```ruby +def is_valid(strs) + symbol_map = {')' => '(', '}' => '{', ']' => '['} + stack = [] + strs.size.times {|i| + c = strs[i] + if symbol_map.has_key?(c) + top_e = stack.shift + return false if symbol_map[c] != top_e + else + stack.unshift(c) + end + } + stack.empty? +end +``` ----------------------- diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md index aa284279..132d65bb 100644 --- a/problems/0024.两两交换链表中的节点.md +++ b/problems/0024.两两交换链表中的节点.md @@ -14,7 +14,7 @@ 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 -![24.两两交换链表中的节点-题意](https://code-thinking.cdn.bcebos.com/pics/24.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9-%E9%A2%98%E6%84%8F.jpg) +24.两两交换链表中的节点-题意 ## 思路 @@ -87,6 +87,46 @@ public: Java: +```Java +// 递归版本 +class Solution { + public ListNode swapPairs(ListNode head) { + // base case 退出提交 + if(head == null || head.next == null) return head; + // 获取当前节点的下一个节点 + ListNode next = head.next; + // 进行递归 + ListNode newNode = swapPairs(next.next); + // 这里进行交换 + next.next = head; + head.next = newNode; + + return next; + } +} +``` + +```java +// 虚拟头结点 +class Solution { + public ListNode swapPairs(ListNode head) { + + ListNode dummyNode = new ListNode(0); + dummyNode.next = head; + ListNode prev = dummyNode; + + while (prev.next != null && prev.next.next != null) { + ListNode temp = head.next.next; // 缓存 next + prev.next = head.next; // 将 prev 的 next 改为 head 的 next + head.next.next = head; // 将 head.next(prev.next) 的next,指向 head + head.next = temp; // 将head 的 next 接上缓存的temp + prev = head; // 步进1位 + head = head.next; // 步进1位 + } + return dummyNode.next; + } +} +``` Python: diff --git a/problems/0027.移除元素.md b/problems/0027.移除元素.md index 144cd5be..9481af1f 100644 --- a/problems/0027.移除元素.md +++ b/problems/0027.移除元素.md @@ -123,10 +123,38 @@ public: Java: +```java +class Solution { + public int removeElement(int[] nums, int val) { + // 快慢指针 + int fastIndex = 0; + int slowIndex; + for (slowIndex = 0; fastIndex < nums.length; fastIndex++) { + if (nums[fastIndex] != val) { + nums[slowIndex] = nums[fastIndex]; + slowIndex++; + } + } + return slowIndex; + + } +} +``` Python: +```python +class Solution: + def removeElement(self, nums: List[int], val: int) -> int: + i,n = 0,len(nums) + for j in range(n): + if nums[j] != val: + nums[i] = nums[j] + i += 1 + return i +``` + Go: ```go diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md index f1de00f8..c6463e8b 100644 --- a/problems/0028.实现strStr.md +++ b/problems/0028.实现strStr.md @@ -565,6 +565,54 @@ public: Java: +```Java +class Solution { + /** + * 基于窗口滑动的算法 + *

+ * 时间复杂度:O(m*n) + * 空间复杂度:O(1) + * 注:n为haystack的长度,m为needle的长度 + */ + public int strStr(String haystack, String needle) { + int m = needle.length(); + // 当 needle 是空字符串时我们应当返回 0 + if (m == 0) { + return 0; + } + int n = haystack.length(); + if (n < m) { + return -1; + } + int i = 0; + int j = 0; + while (i < n - m + 1) { + // 找到首字母相等 + while (i < n && haystack.charAt(i) != needle.charAt(j)) { + i++; + } + if (i == n) {// 没有首字母相等的 + return -1; + } + // 遍历后续字符,判断是否相等 + i++; + j++; + while (i < n && j < m && haystack.charAt(i) == needle.charAt(j)) { + i++; + j++; + } + if (j == m) {// 找到 + return i - j; + } else {// 未找到 + i -= j - 1; + j = 0; + } + } + return -1; + } +} +``` + ```java // 方法一 class Solution { diff --git a/problems/0035.搜索插入位置.md b/problems/0035.搜索插入位置.md index c351e365..a11912b8 100644 --- a/problems/0035.搜索插入位置.md +++ b/problems/0035.搜索插入位置.md @@ -116,7 +116,7 @@ public: **大家要仔细看注释,思考为什么要写while(left <= right), 为什么要写right = middle - 1**。 -``` +```C++ class Solution { public: int searchInsert(vector& nums, int target) { @@ -158,7 +158,7 @@ public: **大家要仔细看注释,思考为什么要写while (left < right), 为什么要写right = middle**。 -``` +```C++ class Solution { public: int searchInsert(vector& nums, int target) { @@ -237,6 +237,22 @@ class Solution { Python: +```python3 +class Solution: + def searchInsert(self, nums: List[int], target: int) -> int: + left, right = 0, len(nums) - 1 + + while left <= right: + middle = (left + right) // 2 + + if nums[middle] < target: + left = middle + 1 + elif nums[middle] > target: + right = middle - 1 + else: + return middle + return right + 1 +``` Go: diff --git a/problems/0045.跳跃游戏II.md b/problems/0045.跳跃游戏II.md index b8e369e6..f65ceb9e 100644 --- a/problems/0045.跳跃游戏II.md +++ b/problems/0045.跳跃游戏II.md @@ -175,7 +175,22 @@ class Solution { ``` Python: - +```python +class Solution: + def jump(self, nums: List[int]) -> int: + if len(nums) == 1: return 0 + ans = 0 + curDistance = 0 + nextDistance = 0 + for i in range(len(nums)): + nextDistance = max(i + nums[i], nextDistance) + if i == curDistance: + if curDistance != len(nums) - 1: + ans += 1 + curDistance = nextDistance + if nextDistance >= len(nums) - 1: break + return ans +``` Go: diff --git a/problems/0046.全排列.md b/problems/0046.全排列.md index 05d86785..5f5aea1f 100644 --- a/problems/0046.全排列.md +++ b/problems/0046.全排列.md @@ -149,6 +149,7 @@ public: Java: ```java class Solution { + List> result = new ArrayList<>();// 存放符合条件结果的集合 LinkedList path = new LinkedList<>();// 用来存放符合条件结果 boolean[] used; @@ -167,9 +168,6 @@ class Solution { return; } for (int i = 0; i < nums.length; i++){ - // if (path.contains(nums[i])){ - // continue; - // } if (used[i]){ continue; } @@ -187,7 +185,55 @@ Python: Go: +```Go +var result [][]int +func backtrack(nums,pathNums []int,used []bool){ + if len(nums)==len(pathNums){ + tmp:=make([]int,len(nums)) + copy(tmp,pathNums) + result=append(result,tmp) + //result=append(result,pathNums) + return + } + for i:=0;i used(nums.size(), false); - backtracking(nums, vec, used); + backtracking(nums, used); return result; } }; @@ -220,6 +220,43 @@ class Solution: return res ``` +Javascript: + +```javascript + +var permuteUnique = function (nums) { + nums.sort((a, b) => { + return a - b + }) + let result = [] + let path = [] + + function backtracing( used) { + if (path.length === nums.length) { + result.push(path.slice()) + return + } + for (let i = 0; i < nums.length; i++) { + if (i > 0 && nums[i] === nums[i - 1] && !used[i - 1]) { + continue + } + if (!used[i]) { + used[i] = true + path.push(nums[i]) + backtracing(used) + path.pop() + used[i] = false + } + + + } + } + backtracing([]) + return result +}; + +``` + diff --git a/problems/0051.N皇后.md b/problems/0051.N皇后.md index ac0235c2..935ea89c 100644 --- a/problems/0051.N皇后.md +++ b/problems/0051.N皇后.md @@ -363,7 +363,72 @@ Python: Go: +```Go +import "strings" +var res [][]string +func isValid(board [][]string, row, col int) (res bool){ + n := len(board) + for i:=0; i < row; i++ { + if board[i][col] == "Q" { + return false + } + } + for i := 0; i < n; i++{ + if board[row][i] == "Q" { + return false + } + } + + for i ,j := row, col; i >= 0 && j >=0 ; i, j = i - 1, j- 1{ + if board[i][j] == "Q"{ + return false + } + } + for i, j := row, col; i >=0 && j < n; i,j = i-1, j+1 { + if board[i][j] == "Q" { + return false + } + } + return true +} + +func backtrack(board [][]string, row int) { + size := len(board) + if row == size{ + temp := make([]string, size) + for i := 0; i int: + result = -float('inf') + count = 0 + for i in range(len(nums)): + count += nums[i] + if count > result: + result = count + if count <= 0: + count = 0 + return result +``` Go: +```go +func maxSubArray(nums []int) int { + maxSum := nums[0] + for i := 1; i < len(nums); i++ { + if nums[i] + nums[i-1] > nums[i] { + nums[i] += nums[i-1] + } + if nums[i] > maxSum { + maxSum = nums[i] + } + } + return maxSum +} +``` + diff --git a/problems/0055.跳跃游戏.md b/problems/0055.跳跃游戏.md index 179ac246..a25c831a 100644 --- a/problems/0055.跳跃游戏.md +++ b/problems/0055.跳跃游戏.md @@ -107,7 +107,19 @@ class Solution { ``` Python: - +```python +class Solution: + def canJump(self, nums: List[int]) -> bool: + cover = 0 + if len(nums) == 1: return True + i = 0 + # python不支持动态修改for循环中变量,使用while循环代替 + while i <= cover: + cover = max(i + nums[i], cover) + if cover >= len(nums) - 1: return True + i += 1 + return False +``` Go: diff --git a/problems/0056.合并区间.md b/problems/0056.合并区间.md index f939325f..e84a1634 100644 --- a/problems/0056.合并区间.md +++ b/problems/0056.合并区间.md @@ -137,7 +137,35 @@ public: Java: +```java +class Solution { + public int[][] merge(int[][] intervals) { + List res = new LinkedList<>(); + Arrays.sort(intervals, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + if (o1[0] != o2[0]) { + return Integer.compare(o1[0],o2[0]); + } else { + return Integer.compare(o1[1],o2[1]); + } + } + }); + int start = intervals[0][0]; + for (int i = 1; i < intervals.length; i++) { + if (intervals[i][0] > intervals[i - 1][1]) { + res.add(new int[]{start, intervals[i - 1][1]}); + start = intervals[i][0]; + } else { + intervals[i][1] = Math.max(intervals[i][1], intervals[i - 1][1]); + } + } + res.add(new int[]{start, intervals[intervals.length - 1][1]}); + return res.toArray(new int[res.size()][]); + } +} +``` Python: @@ -151,4 +179,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -

+
\ No newline at end of file diff --git a/problems/0070.爬楼梯.md b/problems/0070.爬楼梯.md index 6ae6adc7..6cbd6299 100644 --- a/problems/0070.爬楼梯.md +++ b/problems/0070.爬楼梯.md @@ -212,7 +212,45 @@ public: Java: +```Java +class Solution { + public int climbStairs(int n) { + // 跟斐波那契数列一样 + if(n <= 2) return n; + int a = 1, b = 2, sum = 0; + + for(int i = 3; i <= n; i++){ + sum = a + b; + a = b; + b = sum; + } + return b; + } +} +``` +```java +// 常规方式 +public int climbStairs(int n) { + int[] dp = new int[n + 1]; + dp[0] = 1; + dp[1] = 1; + for (int i = 2; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; +} +// 用变量记录代替数组 +public int climbStairs(int n) { + int a = 0, b = 1, c = 0; // 默认需要1次 + for (int i = 1; i <= n; i++) { + c = a + b; // f(i - 1) + f(n - 2) + a = b; // 记录上一轮的值 + b = c; // 向后步进1个数 + } + return c; +} +``` Python: @@ -230,7 +268,20 @@ class Solution: ``` Go: - +```Go +func climbStairs(n int) int { + if n==1{ + return 1 + } + dp:=make([]int,n+1) + dp[1]=1 + dp[2]=2 + for i:=3;i<=n;i++{ + dp[i]=dp[i-1]+dp[i-2] + } + return dp[n] +} +``` diff --git a/problems/0070.爬楼梯完全背包版本.md b/problems/0070.爬楼梯完全背包版本.md index beda45d5..d6b12450 100644 --- a/problems/0070.爬楼梯完全背包版本.md +++ b/problems/0070.爬楼梯完全背包版本.md @@ -127,7 +127,23 @@ public: Java: +```java +class Solution { + public int climbStairs(int n) { + int[] dp = new int[n + 1]; + int[] weight = {1,2}; + dp[0] = 1; + for (int i = 0; i <= n; i++) { + for (int j = 0; j < weight.length; j++) { + if (i >= weight[j]) dp[i] += dp[i - weight[j]]; + } + } + + return dp[n]; + } +} +``` Python: @@ -141,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) -
+
\ No newline at end of file diff --git a/problems/0072.编辑距离.md b/problems/0072.编辑距离.md index 8e6e0187..32c888f1 100644 --- a/problems/0072.编辑距离.md +++ b/problems/0072.编辑距离.md @@ -198,13 +198,71 @@ public: Java: - +```java +public int minDistance(String word1, String word2) { + int m = word1.length(); + int n = word2.length(); + int[][] dp = new int[m + 1][n + 1]; + // 初始化 + for (int i = 1; i <= m; i++) { + dp[i][0] = i; + } + for (int j = 1; j <= n; j++) { + dp[0][j] = j; + } + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + // 因为dp数组有效位从1开始 + // 所以当前遍历到的字符串的位置为i-1 | j-1 + if (word1.charAt(i - 1) == word2.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1; + } + } + } + return dp[m][n]; +} +``` Python: Go: - +```Go +func minDistance(word1 string, word2 string) int { + m, n := len(word1), len(word2) + dp := make([][]int, m+1) + for i := range dp { + dp[i] = make([]int, n+1) + } + for i := 0; i < m+1; i++ { + dp[i][0] = i // word1[i] 变成 word2[0], 删掉 word1[i], 需要 i 部操作 + } + for j := 0; j < n+1; j++ { + dp[0][j] = j // word1[0] 变成 word2[j], 插入 word1[j],需要 j 部操作 + } + for i := 1; i < m+1; i++ { + for j := 1; j < n+1; j++ { + if word1[i-1] == word2[j-1] { + dp[i][j] = dp[i-1][j-1] + } else { // Min(插入,删除,替换) + dp[i][j] = Min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1 + } + } + } + return dp[m][n] +} +func Min(args ...int) int { + min := args[0] + for _, item := range args { + if item < min { + min = item + } + } + return min +} +``` diff --git a/problems/0077.组合.md b/problems/0077.组合.md index f31766e0..1f0d6eb1 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -373,6 +373,32 @@ Python: Go: +```Go +var res [][]int +func combine(n int, k int) [][]int { + res=[][]int{} + if n <= 0 || k <= 0 || k > n { + return res + } + backtrack(n, k, 1, []int{}) + return res +} +func backtrack(n,k,start int,track []int){ + if len(track)==k{ + temp:=make([]int,k) + copy(temp,track) + res=append(res,temp) + } + if len(track)+n-start+1 < k { + return + } + for i:=start;i<=n;i++{ + track=append(track,i) + backtrack(n,k,i+1,track) + track=track[:len(track)-1] + } +} +``` diff --git a/problems/0077.组合优化.md b/problems/0077.组合优化.md index 2af123d1..a8a17858 100644 --- a/problems/0077.组合优化.md +++ b/problems/0077.组合优化.md @@ -147,7 +147,33 @@ public: Java: +``` +class Solution { + List> result = new ArrayList<>(); + LinkedList path = new LinkedList<>(); + public List> combine(int n, int k) { + combineHelper(n, k, 1); + return result; + } + /** + * 每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围,就是要靠startIndex + * @param startIndex 用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] )。 + */ + private void combineHelper(int n, int k, int startIndex){ + //终止条件 + if (path.size() == k){ + result.add(new ArrayList<>(path)); + return; + } + for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){ + path.add(i); + combineHelper(n, k, i + 1); + path.removeLast(); + } + } +} +``` Python: diff --git a/problems/0078.子集.md b/problems/0078.子集.md index 77854133..7166f7fa 100644 --- a/problems/0078.子集.md +++ b/problems/0078.子集.md @@ -209,8 +209,47 @@ Python: Go: +```Go +var res [][]int +func subset(nums []int) [][]int { + res = make([][]int, 0) + sort.Ints(nums) + Dfs([]int{}, nums, 0) + return res +} +func Dfs(temp, nums []int, start int){ + tmp := make([]int, len(temp)) + copy(tmp, temp) + res = append(res, tmp) + for i := start; i < len(nums); i++{ + //if i>start&&nums[i]==nums[i-1]{ + // continue + //} + temp = append(temp, nums[i]) + Dfs(temp, nums, i+1) + temp = temp[:len(temp)-1] + } +} +``` +Javascript: +```Javascript +var subsets = function(nums) { + let result = [] + let path = [] + function backtracking(startIndex) { + result.push(path.slice()) + for(let i = startIndex; i < nums.length; i++) { + path.push(nums[i]) + backtracking(i + 1) + path.pop() + } + } + backtracking(0) + return result +}; +``` ----------------------- diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md index 47db79f7..941e3eca 100644 --- a/problems/0090.子集II.md +++ b/problems/0090.子集II.md @@ -211,7 +211,60 @@ Python: Go: +```Go +var res[][]int +func subsetsWithDup(nums []int)[][]int { + res=make([][]int,0) + sort.Ints(nums) + dfs([]int{},nums,0) + return res +} +func dfs(temp, num []int, start int) { + tmp:=make([]int,len(temp)) + copy(tmp,temp) + res=append(res,tmp) + for i:=start;istart&&num[i]==num[i-1]{ + continue + } + temp=append(temp,num[i]) + dfs(temp,num,i+1) + temp=temp[:len(temp)-1] + } +} +``` + + +Javascript: + +```Javascript + +var subsetsWithDup = function(nums) { + let result = [] + let path = [] + let sortNums = nums.sort((a, b) => { + return a - b + }) + function backtracing(startIndex, sortNums) { + result.push(path.slice(0)) + if(startIndex > nums.length - 1) { + return + } + for(let i = startIndex; i < nums.length; i++) { + if(i > startIndex && nums[i] === nums[i - 1]) { + continue + } + path.push(nums[i]) + backtracing(i + 1, sortNums) + path.pop() + } + } + backtracing(0, sortNums) + return result +}; + +``` diff --git a/problems/0096.不同的二叉搜索树.md b/problems/0096.不同的二叉搜索树.md index 2764277c..dca225bf 100644 --- a/problems/0096.不同的二叉搜索树.md +++ b/problems/0096.不同的二叉搜索树.md @@ -165,13 +165,42 @@ public: Java: - +```Java +class Solution { + public int numTrees(int n) { + //初始化 dp 数组 + int[] dp = new int[n + 1]; + //初始化0个节点和1个节点的情况 + dp[0] = 1; + dp[1] = 1; + for (int i = 2; i <= n; i++) { + for (int j = 1; j <= i; j++) { + //对于第i个节点,需要考虑1作为根节点直到i作为根节点的情况,所以需要累加 + //一共i个节点,对于根节点j时,左子树的节点个数为j-1,右子树的节点个数为i-j + dp[i] += dp[j - 1] * dp[i - j]; + } + } + return dp[n]; + } +} +``` 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 baa3f435..d8945eff 100644 --- a/problems/0098.验证二叉搜索树.md +++ b/problems/0098.验证二叉搜索树.md @@ -255,12 +255,109 @@ public: Java: +```Java +class Solution { + // 递归 + TreeNode max; + public boolean isValidBST(TreeNode root) { + if (root == null) { + return true; + } + // 左 + boolean left = isValidBST(root.left); + if (!left) { + return false; + } + // 中 + if (max != null && root.val <= max.val) { + return false; + } + max = root; + // 右 + boolean right = isValidBST(root.right); + return right; + } +} + +class Solution { + // 迭代 + public boolean isValidBST(TreeNode root) { + if (root == null) { + return true; + } + Stack stack = new Stack<>(); + TreeNode pre = null; + while (root != null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left;// 左 + } + // 中,处理 + TreeNode pop = stack.pop(); + if (pre != null && pop.val <= pre.val) { + return false; + } + pre = pop; + + root = pop.right;// 右 + } + return true; + } +} + +// 简洁实现·递归解法 +class Solution { + public boolean isValidBST(TreeNode root) { + return validBST(Long.MIN_VALUE, Long.MAX_VALUE, root); + } + boolean validBST(long lower, long upper, TreeNode root) { + if (root == null) return true; + if (root.val <= lower || root.val >= upper) return false; + return validBST(lower, root.val, root.left) && validBST(root.val, upper, root.right); + } +} +// 简洁实现·中序遍历 +class Solution { + private long prev = Long.MIN_VALUE; + public boolean isValidBST(TreeNode root) { + if (root == null) { + return true; + } + if (!isValidBST(root.left)) { + return false; + } + if (root.val <= prev) { // 不满足二叉搜索树条件 + return false; + } + prev = root.val; + return isValidBST(root.right); + } +} +``` Python: Go: +```Go +import "math" +func isValidBST(root *TreeNode) bool { + if root == nil { + return true + } + return isBST(root, math.MinInt64, math.MaxFloat64) +} +func isBST(root *TreeNode, min, max int) bool { + if root == nil { + return true + } + if min >= root.Val || max <= root.Val { + return false + } + return isBST(root.Left, min, root.Val) && isBST(root.Right, root.Val, max) +} +``` @@ -268,4 +365,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0101.对称二叉树.md b/problems/0101.对称二叉树.md index 561d0470..b7d41557 100644 --- a/problems/0101.对称二叉树.md +++ b/problems/0101.对称二叉树.md @@ -253,9 +253,110 @@ public: ## 其他语言版本 - Java: +```Java + /** + * 递归法 + */ + public boolean isSymmetric1(TreeNode root) { + return compare(root.left, root.right); + } + + private boolean compare(TreeNode left, TreeNode right) { + + if (left == null && right != null) { + return false; + } + if (left != null && right == null) { + return false; + } + + if (left == null && right == null) { + return true; + } + if (left.val != right.val) { + return false; + } + // 比较外侧 + boolean compareOutside = compare(left.left, right.right); + // 比较内侧 + boolean compareInside = compare(left.right, right.left); + return compareOutside && compareInside; + } + + /** + * 迭代法 + * 使用双端队列,相当于两个栈 + */ + public boolean isSymmetric2(TreeNode root) { + Deque deque = new LinkedList<>(); + deque.offerFirst(root.left); + deque.offerLast(root.right); + while (!deque.isEmpty()) { + TreeNode leftNode = deque.pollFirst(); + TreeNode rightNode = deque.pollLast(); + if (leftNode == null && rightNode == null) { + continue; + } +// if (leftNode == null && rightNode != null) { +// return false; +// } +// if (leftNode != null && rightNode == null) { +// return false; +// } +// if (leftNode.val != rightNode.val) { +// return false; +// } + // 以上三个判断条件合并 + if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) { + return false; + } + deque.offerFirst(leftNode.left); + deque.offerFirst(leftNode.right); + deque.offerLast(rightNode.right); + deque.offerLast(rightNode.left); + } + return true; + } + + /** + * 迭代法 + * 使用普通队列 + */ + public boolean isSymmetric3(TreeNode root) { + Queue deque = new LinkedList<>(); + deque.offer(root.left); + deque.offer(root.right); + while (!deque.isEmpty()) { + TreeNode leftNode = deque.poll(); + TreeNode rightNode = deque.poll(); + if (leftNode == null && rightNode == null) { + continue; + } +// if (leftNode == null && rightNode != null) { +// return false; +// } +// if (leftNode != null && rightNode == null) { +// return false; +// } +// if (leftNode.val != rightNode.val) { +// return false; +// } + // 以上三个判断条件合并 + if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) { + return false; + } + // 这里顺序与使用Deque不同 + deque.offer(leftNode.left); + deque.offer(rightNode.right); + deque.offer(leftNode.right); + deque.offer(rightNode.left); + } + return true; + } + +``` Python: diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index be2e9dca..0ab67b13 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -419,35 +419,237 @@ public: Java: -``` Java - - +```Java +// 102.二叉树的层序遍历 class Solution { - public List> resList=new ArrayList>(); + public List> resList = new ArrayList>(); + public List> levelOrder(TreeNode root) { - checkFun01(root,0); + //checkFun01(root,0); + checkFun02(root); return resList; } - //递归方式 - public void checkFun01(TreeNode node,Integer deep){ - if(node==null) return; + //DFS--递归方式 + public void checkFun01(TreeNode node, Integer deep) { + if (node == null) return; deep++; - if(resList.size() item=new ArrayList(); + List item = new ArrayList(); resList.add(item); } - resList.get(deep-1).add(node.val); - + resList.get(deep - 1).add(node.val); - checkFun01(node.left,deep); - checkFun01(node.right,deep); + checkFun01(node.left, deep); + checkFun01(node.right, deep); } + //BFS--迭代方式--借助队列 + public void checkFun02(TreeNode node) { + if (node == null) return; + Queue que = new LinkedList(); + que.offer(node); + while (!que.isEmpty()) { + List itemList = new ArrayList(); + int len = que.size(); + + while (len > 0) { + TreeNode tmpNode = que.poll(); + itemList.add(tmpNode.val); + + if (tmpNode.left != null) que.offer(tmpNode.left); + if (tmpNode.right != null) que.offer(tmpNode.right); + len--; + } + + resList.add(itemList); + } + + } +} + + +// 107. 二叉树的层序遍历 II +public class N0107 { + + /** + * 解法:队列,迭代。 + * 层序遍历,再翻转数组即可。 + */ + public List> solution1(TreeNode root) { + List> list = new ArrayList<>(); + Deque que = new LinkedList<>(); + + if (root == null) { + return list; + } + + que.offerLast(root); + while (!que.isEmpty()) { + List levelList = new ArrayList<>(); + + int levelSize = que.size(); + for (int i = 0; i < levelSize; i++) { + TreeNode peek = que.peekFirst(); + levelList.add(que.pollFirst().val); + + if (peek.left != null) { + que.offerLast(peek.left); + } + if (peek.right != null) { + que.offerLast(peek.right); + } + } + list.add(levelList); + } + + List> result = new ArrayList<>(); + for (int i = list.size() - 1; i >= 0; i-- ) { + result.add(list.get(i)); + } + + return result; + } +} + +// 199.二叉树的右视图 +public class N0199 { + /** + * 解法:队列,迭代。 + * 每次返回每层的最后一个字段即可。 + * + * 小优化:每层右孩子先入队。代码略。 + */ + public List rightSideView(TreeNode root) { + List list = new ArrayList<>(); + Deque que = new LinkedList<>(); + + if (root == null) { + return list; + } + + que.offerLast(root); + while (!que.isEmpty()) { + int levelSize = que.size(); + + for (int i = 0; i < levelSize; i++) { + TreeNode poll = que.pollFirst(); + + if (poll.left != null) { + que.addLast(poll.left); + } + if (poll.right != null) { + que.addLast(poll.right); + } + + if (i == levelSize - 1) { + list.add(poll.val); + } + } + } + + return list; + } +} + +// 637. 二叉树的层平均值 +public class N0637 { + + /** + * 解法:队列,迭代。 + * 每次返回每层的最后一个字段即可。 + */ + public List averageOfLevels(TreeNode root) { + List list = new ArrayList<>(); + Deque que = new LinkedList<>(); + + if (root == null) { + return list; + } + + que.offerLast(root); + while (!que.isEmpty()) { + TreeNode peek = que.peekFirst(); + + int levelSize = que.size(); + double levelSum = 0.0; + for (int i = 0; i < levelSize; i++) { + TreeNode poll = que.pollFirst(); + + levelSum += poll.val; + + if (poll.left != null) { + que.addLast(poll.left); + } + if (poll.right != null) { + que.addLast(poll.right); + } + } + list.add(levelSum / levelSize); + } + return list; + } +} + +// 429. N 叉树的层序遍历 +public class N0429 { + /** + * 解法1:队列,迭代。 + */ + public List> levelOrder(Node root) { + List> list = new ArrayList<>(); + Deque que = new LinkedList<>(); + + if (root == null) { + return list; + } + + que.offerLast(root); + while (!que.isEmpty()) { + int levelSize = que.size(); + List levelList = new ArrayList<>(); + + for (int i = 0; i < levelSize; i++) { + Node poll = que.pollFirst(); + + levelList.add(poll.val); + + List children = poll.children; + if (children == null || children.size() == 0) { + continue; + } + for (Node child : children) { + if (child != null) { + que.offerLast(child); + } + } + } + list.add(levelList); + } + + return list; + } + + class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } +} ``` @@ -455,9 +657,36 @@ Python: Go: +```Go +func levelOrder(root *TreeNode) [][]int { + result:=make([][]int,0) + if root==nil{ + return result + } + queue:=make([]*TreeNode,0) + queue=append(queue,root) + for len(queue)>0{ + list:=make([]int,0) + l:=len(queue) + for i:=0;i deque = new LinkedList<>(); + deque.offer(root); + int depth = 0; + while (!deque.isEmpty()) { + int size = deque.size(); + depth++; + for (int i = 0; i < size; i++) { + TreeNode poll = deque.poll(); + if (poll.left != null) { + deque.offer(poll.left); + } + if (poll.right != null) { + deque.offer(poll.right); + } + } + } + return depth; + } +} +``` Python: @@ -239,10 +285,16 @@ Python: Go: - +JavaScript +```javascript +var maxDepth = function(root) { + if (!root) return root + return 1 + Math.max(maxDepth(root.left), maxDepth(root.right)) +}; +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index f1f30b71..cfd22288 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -582,15 +582,96 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。 Java: - +```java +class Solution { + public TreeNode buildTree(int[] inorder, int[] postorder) { + return buildTree1(inorder, 0, inorder.length, postorder, 0, postorder.length); + } + public TreeNode buildTree1(int[] inorder, int inLeft, int inRight, + int[] postorder, int postLeft, int postRight) { + // 没有元素了 + if (inRight - inLeft < 1) { + return null; + } + // 只有一个元素了 + if (inRight - inLeft == 1) { + return new TreeNode(inorder[inLeft]); + } + // 后序数组postorder里最后一个即为根结点 + int rootVal = postorder[postRight - 1]; + TreeNode root = new TreeNode(rootVal); + int rootIndex = 0; + // 根据根结点的值找到该值在中序数组inorder里的位置 + for (int i = inLeft; i < inRight; i++) { + if (inorder[i] == rootVal) { + rootIndex = i; + } + } + // 根据rootIndex划分左右子树 + root.left = buildTree1(inorder, inLeft, rootIndex, + postorder, postLeft, postLeft + (rootIndex - inLeft)); + root.right = buildTree1(inorder, rootIndex + 1, inRight, + postorder, postLeft + (rootIndex - inLeft), postRight - 1); + return root; + } +} +``` 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: - +JavaScript +```javascript +var buildTree = function(inorder, postorder) { + if (!postorder.length) return null + + let root = new TreeNode(postorder[postorder.length - 1]) + + let index = inorder.findIndex(number => number === root.val) + + root.left = buildTree(inorder.slice(0, index), postorder.slice(0, index)) + root.right = buildTree(inorder.slice(index + 1, inorder.length), postorder.slice(index, postorder.length - 1)) + + return root +}; +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0108.将有序数组转换为二叉搜索树.md b/problems/0108.将有序数组转换为二叉搜索树.md index 12d47e6a..93dc5fd6 100644 --- a/problems/0108.将有序数组转换为二叉搜索树.md +++ b/problems/0108.将有序数组转换为二叉搜索树.md @@ -209,7 +209,28 @@ public: Java: +```Java +class Solution { + public TreeNode sortedArrayToBST(int[] nums) { + return sortedArrayToBST(nums, 0, nums.length); + } + + public TreeNode sortedArrayToBST(int[] nums, int left, int right) { + if (left >= right) { + return null; + } + if (right - left == 1) { + return new TreeNode(nums[left]); + } + int mid = left + (right - left) / 2; + TreeNode root = new TreeNode(nums[mid]); + root.left = sortedArrayToBST(nums, left, mid); + root.right = sortedArrayToBST(nums, mid + 1, right); + return root; + } +} +``` Python: @@ -223,4 +244,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0110.平衡二叉树.md b/problems/0110.平衡二叉树.md index 5d55910c..da71ccb2 100644 --- a/problems/0110.平衡二叉树.md +++ b/problems/0110.平衡二叉树.md @@ -353,15 +353,187 @@ public: ## 其他语言版本 - Java: +```Java +class Solution { + /** + * 递归法 + */ + public boolean isBalanced(TreeNode root) { + return getHeight(root) != -1; + } + + private int getHeight(TreeNode root) { + if (root == null) { + return 0; + } + int leftHeight = getHeight(root.left); + if (leftHeight == -1) { + return -1; + } + int rightHeight = getHeight(root.right); + if (rightHeight == -1) { + return -1; + } + // 左右子树高度差大于1,return -1表示已经不是平衡树了 + if (Math.abs(leftHeight - rightHeight) > 1) { + return -1; + } + return Math.max(leftHeight, rightHeight) + 1; + } +} + +class Solution { + /** + * 迭代法,效率较低,计算高度时会重复遍历 + * 时间复杂度:O(n^2) + */ + public boolean isBalanced(TreeNode root) { + if (root == null) { + return true; + } + Stack stack = new Stack<>(); + TreeNode pre = null; + while (root!= null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left; + } + TreeNode inNode = stack.peek(); + // 右结点为null或已经遍历过 + if (inNode.right == null || inNode.right == pre) { + // 比较左右子树的高度差,输出 + if (Math.abs(getHeight(inNode.left) - getHeight(inNode.right)) > 1) { + return false; + } + stack.pop(); + pre = inNode; + root = null;// 当前结点下,没有要遍历的结点了 + } else { + root = inNode.right;// 右结点还没遍历,遍历右结点 + } + } + return true; + } + + /** + * 层序遍历,求结点的高度 + */ + public int getHeight(TreeNode root) { + if (root == null) { + return 0; + } + Deque deque = new LinkedList<>(); + deque.offer(root); + int depth = 0; + while (!deque.isEmpty()) { + int size = deque.size(); + depth++; + for (int i = 0; i < size; i++) { + TreeNode poll = deque.poll(); + if (poll.left != null) { + deque.offer(poll.left); + } + if (poll.right != null) { + deque.offer(poll.right); + } + } + } + return depth; + } +} + +class Solution { + /** + * 优化迭代法,针对暴力迭代法的getHeight方法做优化,利用TreeNode.val来保存当前结点的高度,这样就不会有重复遍历 + * 获取高度算法时间复杂度可以降到O(1),总的时间复杂度降为O(n)。 + *

+ * 时间复杂度:O(n) + */ + public boolean isBalanced(TreeNode root) { + if (root == null) { + return true; + } + Stack stack = new Stack<>(); + TreeNode pre = null; + while (root != null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left; + } + TreeNode inNode = stack.peek(); + // 右结点为null或已经遍历过 + if (inNode.right == null || inNode.right == pre) { + // 输出 + if (Math.abs(getHeight(inNode.left) - getHeight(inNode.right)) > 1) { + return false; + } + stack.pop(); + pre = inNode; + root = null;// 当前结点下,没有要遍历的结点了 + } else { + root = inNode.right;// 右结点还没遍历,遍历右结点 + } + } + return true; + } + + /** + * 求结点的高度 + */ + public int getHeight(TreeNode root) { + if (root == null) { + return 0; + } + int leftHeight = root.left != null ? root.left.val : 0; + int rightHeight = root.right != null ? root.right.val : 0; + int height = Math.max(leftHeight, rightHeight) + 1; + root.val = height;// 用TreeNode.val来保存当前结点的高度 + return height; + } +} +// LeetCode题解链接:https://leetcode-cn.com/problems/balanced-binary-tree/solution/110-ping-heng-er-cha-shu-di-gui-fa-bao-l-yqr3/ +``` Python: Go: - +```Go +func isBalanced(root *TreeNode) bool { + if root==nil{ + return true + } + if !isBalanced(root.Left) || !isBalanced(root.Right){ + return false + } + LeftH:=maxdepth(root.Left)+1 + RightH:=maxdepth(root.Right)+1 + if abs(LeftH-RightH)>1{ + return false + } + return true +} +func maxdepth(root *TreeNode)int{ + if root==nil{ + return 0 + } + return max(maxdepth(root.Left),maxdepth(root.Right))+1 +} +func max(a,b int)int{ + if a>b{ + return a + } + return b +} +func abs(a int)int{ + if a<0{ + return -a + } + return a +} +``` diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md index 430cd5d6..01b6c89c 100644 --- a/problems/0111.二叉树的最小深度.md +++ b/problems/0111.二叉树的最小深度.md @@ -195,9 +195,109 @@ public: Java: +```Java +class Solution { + /** + * 递归法,相比求MaxDepth要复杂点 + * 因为最小深度是从根节点到最近**叶子节点**的最短路径上的节点数量 + */ + public int minDepth(TreeNode root) { + if (root == null) { + return 0; + } + int leftDepth = minDepth(root.left); + int rightDepth = minDepth(root.right); + if (root.left == null) { + return rightDepth + 1; + } + if (root.right == null) { + return leftDepth + 1; + } + // 左右结点都不为null + return Math.min(leftDepth, rightDepth) + 1; + } +} +``` + +```Java +class Solution { + /** + * 迭代法,层序遍历 + */ + public int minDepth(TreeNode root) { + if (root == null) { + return 0; + } + Deque deque = new LinkedList<>(); + deque.offer(root); + int depth = 0; + while (!deque.isEmpty()) { + int size = deque.size(); + depth++; + for (int i = 0; i < size; i++) { + TreeNode poll = deque.poll(); + if (poll.left == null && poll.right == null) { + // 是叶子结点,直接返回depth,因为从上往下遍历,所以该值就是最小值 + return depth; + } + if (poll.left != null) { + deque.offer(poll.left); + } + if (poll.right != null) { + deque.offer(poll.right); + } + } + } + return depth; + } +} +``` Python: +递归法: + +```python +class Solution: + def minDepth(self, root: TreeNode) -> int: + if not root: + return 0 + if not root.left and not root.right: + return 1 + + min_depth = 10**9 + if root.left: + min_depth = min(self.minDepth(root.left), min_depth) # 获得左子树的最小高度 + if root.right: + min_depth = min(self.minDepth(root.right), min_depth) # 获得右子树的最小高度 + return min_depth + 1 +``` + +迭代法: + +```python +class Solution: + def minDepth(self, root: TreeNode) -> int: + if not root: + return 0 + que = deque() + que.append(root) + res = 1 + + while que: + for _ in range(len(que)): + node = que.popleft() + # 当左右孩子都为空的时候,说明是最低点的一层了,退出 + if not node.left and not node.right: + return res + if node.left is not None: + que.append(node.left) + if node.right is not None: + que.append(node.right) + res += 1 + return res +``` + Go: diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index 718a2f5b..5ecdf350 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -305,10 +305,118 @@ public: Java: +```Java +class Solution { + public boolean hasPathSum(TreeNode root, int targetSum) { + if (root == null) { + return false; + } + targetSum -= root.val; + // 叶子结点 + if (root.left == null && root.right == null) { + return targetSum == 0; + } + if (root.left != null) { + boolean left = hasPathSum(root.left, targetSum); + if (left) {// 已经找到 + return true; + } + } + if (root.right != null) { + boolean right = hasPathSum(root.right, targetSum); + if (right) {// 已经找到 + return true; + } + } + return false; + } +} +// LC112 简洁方法 +class Solution { + public boolean hasPathSum(TreeNode root, int targetSum) { + + if (root == null) return false; // 为空退出 + + // 叶子节点判断是否符合 + if (root.left == null && root.right == null) return root.val == targetSum; + + // 求两侧分支的路径和 + return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val); + } +} +``` 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: diff --git a/problems/0121.买卖股票的最佳时机.md b/problems/0121.买卖股票的最佳时机.md index 941d4397..9ca08985 100644 --- a/problems/0121.买卖股票的最佳时机.md +++ b/problems/0121.买卖股票的最佳时机.md @@ -197,6 +197,23 @@ public: ## 其他语言版本 Java: +```java +// 贪心思路 +class Solution { + public int maxProfit(int[] prices) { + int minprice = Integer.MAX_VALUE; + int maxprofit = 0; + for (int i = 0; i < prices.length; i++) { + if (prices[i] < minprice) { + minprice = prices[i]; + } else if (prices[i] - minprice > maxprofit) { + maxprofit = prices[i] - minprice; + } + } + return maxprofit; + } +} +``` ``` java class Solution { // 动态规划解法 @@ -225,13 +242,35 @@ class Solution { // 动态规划解法 } ``` - - - Python: Go: +```Go +func maxProfit(prices []int) int { + length:=len(prices) + if length==0{return 0} + dp:=make([][]int,length) + for i:=0;ib{ + return a + } + return b +} +``` diff --git a/problems/0122.买卖股票的最佳时机II.md b/problems/0122.买卖股票的最佳时机II.md index 2e973217..64b8b885 100644 --- a/problems/0122.买卖股票的最佳时机II.md +++ b/problems/0122.买卖股票的最佳时机II.md @@ -135,6 +135,25 @@ public: Java: +```java +// 贪心思路 +class Solution { + public int maxProfit(int[] prices) { + int sum = 0; + int profit = 0; + int buy = prices[0]; + for (int i = 1; i < prices.length; i++) { + profit = prices[i] - buy; + if (profit > 0) { + sum += profit; + } + buy = prices[i]; + } + return sum; + } +} +``` + ```java class Solution { // 动态规划 public int maxProfit(int[] prices) { @@ -157,8 +176,16 @@ class Solution { // 动态规划 ``` -Python: +Python: +```python +class Solution: + def maxProfit(self, prices: List[int]) -> int: + result = 0 + for i in range(1, len(prices)): + result += max(prices[i] - prices[i - 1], 0) + return result +``` Go: @@ -169,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) -

+
\ No newline at end of file diff --git a/problems/0122.买卖股票的最佳时机II(动态规划).md b/problems/0122.买卖股票的最佳时机II(动态规划).md index 3444ca73..e3526ecf 100644 --- a/problems/0122.买卖股票的最佳时机II(动态规划).md +++ b/problems/0122.买卖股票的最佳时机II(动态规划).md @@ -133,7 +133,41 @@ public: 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; // 初始状态 + 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]); // 第 i 天,没有股票 + dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); // 第 i 天,持有股票 + } + 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]; // 定义变量,存储初始状态 + for (int i = 1; i < n; ++i) { + int newDp0 = Math.max(dp0, dp1 + prices[i]); // 第 i 天,没有股票 + int newDp1 = Math.max(dp1, dp0 - prices[i]); // 第 i 天,持有股票 + dp0 = newDp0; + dp1 = newDp1; + } + return dp0; + } +} +``` Python: diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md index 01ff35c5..9c86a3bc 100644 --- a/problems/0131.分割回文串.md +++ b/problems/0131.分割回文串.md @@ -250,7 +250,46 @@ public: Java: +```Java +class Solution { + List> lists = new ArrayList<>(); + Deque deque = new LinkedList<>(); + public List> partition(String s) { + backTracking(s, 0); + return lists; + } + + private void backTracking(String s, int startIndex) { + //如果起始位置大于s的大小,说明找到了一组分割方案 + if (startIndex >= s.length()) { + lists.add(new ArrayList(deque)); + return; + } + for (int i = startIndex; i < s.length(); i++) { + //如果是回文子串,则记录 + if (isPalindrome(s, startIndex, i)) { + String str = s.substring(startIndex, i + 1); + deque.addLast(str); + } else { + continue; + } + //起始位置后移,保证不重复 + backTracking(s, i + 1); + deque.removeLast(); + } + } + //判断是否是回文串 + private boolean isPalindrome(String s, int startIndex, int end) { + for (int i = startIndex, j = end; i < j; i++, j--) { + if (s.charAt(i) != s.charAt(j)) { + return false; + } + } + return true; + } +} +``` Python: diff --git a/problems/0134.加油站.md b/problems/0134.加油站.md index 9c72e84d..52019aec 100644 --- a/problems/0134.加油站.md +++ b/problems/0134.加油站.md @@ -199,10 +199,45 @@ public: Java: +```java +class Solution { + public int canCompleteCircuit(int[] gas, int[] cost) { + int sum = 0; + int min = 0; + for (int i = 0; i < gas.length; i++) { + sum += (gas[i] - cost[i]); + min = Math.min(sum, min); + } + if (sum < 0) return -1; + if (min >= 0) return 0; + + for (int i = gas.length - 1; i > 0; i--) { + min += (gas[i] - cost[i]); + if (min >= 0) return i; + } + + return -1; + } +} +``` 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: diff --git a/problems/0135.分发糖果.md b/problems/0135.分发糖果.md index 0595cff6..51b32965 100644 --- a/problems/0135.分发糖果.md +++ b/problems/0135.分发糖果.md @@ -130,10 +130,49 @@ public: Java: +```java +class Solution { + public int candy(int[] ratings) { + int[] candy = new int[ratings.length]; + for (int i = 0; i < candy.length; i++) { + candy[i] = 1; + } + for (int i = 1; i < ratings.length; i++) { + if (ratings[i] > ratings[i - 1]) { + candy[i] = candy[i - 1] + 1; + } + } + + for (int i = ratings.length - 2; i >= 0; i--) { + if (ratings[i] > ratings[i + 1]) { + candy[i] = Math.max(candy[i],candy[i + 1] + 1); + } + } + + int count = 0; + for (int i = 0; i < candy.length; i++) { + count += candy[i]; + } + + return count; + } +} +``` 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: diff --git a/problems/0139.单词拆分.md b/problems/0139.单词拆分.md index ec996565..c6d8e43b 100644 --- a/problems/0139.单词拆分.md +++ b/problems/0139.单词拆分.md @@ -232,7 +232,23 @@ public: Java: +```java +class Solution { + public boolean wordBreak(String s, List wordDict) { + boolean[] valid = new boolean[s.length() + 1]; + valid[0] = true; + for (int i = 1; i <= s.length(); i++) { + for (int j = 0; j < i; j++) { + if (wordDict.contains(s.substring(j,i)) && valid[j]) { + valid[i] = true; + } + } + } + return valid[s.length()]; + } +} +``` Python: @@ -246,4 +262,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0142.环形链表II.md b/problems/0142.环形链表II.md index 9622affc..b3a53c07 100644 --- a/problems/0142.环形链表II.md +++ b/problems/0142.环形链表II.md @@ -186,6 +186,29 @@ public: Java: +```java +public class Solution { + public ListNode detectCycle(ListNode head) { + ListNode slow = head; + ListNode fast = head; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (slow == fast) {// 有环 + ListNode index1 = fast; + ListNode index2 = head; + // 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口 + while (index1 != index2) { + index1 = index1.next; + index2 = index2.next; + } + return index1; + } + } + return null; + } +} +``` Python: @@ -211,6 +234,29 @@ 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 +} +``` ----------------------- diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md index 4e7365f7..12977c39 100644 --- a/problems/0150.逆波兰表达式求值.md +++ b/problems/0150.逆波兰表达式求值.md @@ -170,7 +170,32 @@ public class EvalRPN { } ``` - +Go: +```Go +func evalRPN(tokens []string) int { + stack := []int{} + for _, token := range tokens { + val, err := strconv.Atoi(token) + if err == nil { + stack = append(stack, val) + } else { + num1, num2 := stack[len(stack)-2], stack[(len(stack))-1] + stack = stack[:len(stack)-2] + switch token { + case "+": + stack = append(stack, num1+num2) + case "-": + stack = append(stack, num1-num2) + case "*": + stack = append(stack, num1*num2) + case "/": + stack = append(stack, num1/num2) + } + } + } + return stack[0] +} +``` diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md index d81c139d..62a47ab7 100644 --- a/problems/0151.翻转字符串里的单词.md +++ b/problems/0151.翻转字符串里的单词.md @@ -141,7 +141,8 @@ void reverse(string& s, int start, int end) { -``` +```C++ +// 版本一 class Solution { public: // 反转字符串s中左闭又闭的区间[start, end] @@ -182,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; // 进入单词区间 } @@ -201,9 +202,42 @@ public: } return s; } + + /* 主函数简单写法 + string reverseWords(string s) { + removeExtraSpaces(s); + reverse(s, 0, s.size() - 1); + for(int i = 0; i < s.size(); i++) { + int j = i; + // 查找单词间的空格,翻转单词 + while(j < s.size() && s[j] != ' ') j++; + reverse(s, i, j - 1); + i = j; + } + return s; + } + */ }; ``` +当然这里的主函数reverseWords写的有一些冗余的,可以精简一些,精简之后的主函数为: + +```C++ +// 注意这里仅仅是主函数,其他函数和版本一一致 +string reverseWords(string s) { + removeExtraSpaces(s); + reverse(s, 0, s.size() - 1); + for(int i = 0; i < s.size(); i++) { + int j = i; + // 查找单词间的空格,翻转单词 + while(j < s.size() && s[j] != ' ') j++; + reverse(s, i, j - 1); + i = j; + } + return s; +} +``` + @@ -213,6 +247,74 @@ public: Java: +```Java +class Solution { + /** + * 不使用Java内置方法实现 + *

+ * 1.去除首尾以及中间多余空格 + * 2.反转整个字符串 + * 3.反转各个单词 + */ + public String reverseWords(String s) { + // System.out.println("ReverseWords.reverseWords2() called with: s = [" + s + "]"); + // 1.去除首尾以及中间多余空格 + StringBuilder sb = removeSpace(s); + // 2.反转整个字符串 + reverseString(sb, 0, sb.length() - 1); + // 3.反转各个单词 + reverseEachWord(sb); + return sb.toString(); + } + + private StringBuilder removeSpace(String s) { + // System.out.println("ReverseWords.removeSpace() called with: s = [" + s + "]"); + int start = 0; + int end = s.length() - 1; + while (s.charAt(start) == ' ') start++; + while (s.charAt(end) == ' ') end--; + StringBuilder sb = new StringBuilder(); + while (start <= end) { + char c = s.charAt(start); + if (c != ' ' || sb.charAt(sb.length() - 1) != ' ') { + sb.append(c); + } + start++; + } + // System.out.println("ReverseWords.removeSpace returned: sb = [" + sb + "]"); + return sb; + } + + /** + * 反转字符串指定区间[start, end]的字符 + */ + public void reverseString(StringBuilder sb, int start, int end) { + // System.out.println("ReverseWords.reverseString() called with: sb = [" + sb + "], start = [" + start + "], end = [" + end + "]"); + while (start < end) { + char temp = sb.charAt(start); + sb.setCharAt(start, sb.charAt(end)); + sb.setCharAt(end, temp); + start++; + end--; + } + // System.out.println("ReverseWords.reverseString returned: sb = [" + sb + "]"); + } + + private void reverseEachWord(StringBuilder sb) { + int start = 0; + int end = 1; + int n = sb.length(); + while (start < n) { + while (end < n && sb.charAt(end) != ' ') { + end++; + } + reverseString(sb, start, end - 1); + start = end + 1; + end = start + 1; + } + } +} +``` Python: diff --git a/problems/0198.打家劫舍.md b/problems/0198.打家劫舍.md index b9ccec45..649dd055 100644 --- a/problems/0198.打家劫舍.md +++ b/problems/0198.打家劫舍.md @@ -111,12 +111,56 @@ public: Java: +```Java +// 动态规划 +class Solution { + public int rob(int[] nums) { + if (nums == null || nums.length == 0) return 0; + if (nums.length == 1) return nums[0]; + int[] dp = new int[nums.length + 1]; + dp[0] = nums[0]; + dp[1] = Math.max(dp[0], nums[1]); + for (int i = 2; i < nums.length; i++) { + dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]); + } + + return dp[nums.length - 1]; + } +} +``` Python: Go: +```Go +func rob(nums []int) int { + if len(nums)<1{ + return 0 + } + if len(nums)==1{ + return nums[0] + } + if len(nums)==2{ + return max(nums[0],nums[1]) + } + dp :=make([]int,len(nums)) + dp[0]=nums[0] + dp[1]=max(nums[0],nums[1]) + for i:=2;ib{ + return a + } + return b +} +``` diff --git a/problems/0202.快乐数.md b/problems/0202.快乐数.md index d6b1cdd2..8c0dd1e7 100644 --- a/problems/0202.快乐数.md +++ b/problems/0202.快乐数.md @@ -84,7 +84,28 @@ public: Java: +```java +class Solution { + public boolean isHappy(int n) { + Set record = new HashSet<>(); + while (n != 1 && !record.contains(n)) { + record.add(n); + n = getNextNumber(n); + } + return n == 1; + } + private int getNextNumber(int n) { + int res = 0; + while (n > 0) { + int temp = n % 10; + res += temp * temp; + n = n / 10; + } + return res; + } +} +``` Python: diff --git a/problems/0206.翻转链表.md b/problems/0206.翻转链表.md index b465cdf9..886bbfcd 100644 --- a/problems/0206.翻转链表.md +++ b/problems/0206.翻转链表.md @@ -102,7 +102,45 @@ public: Java: +```java +// 双指针 +class Solution { + public ListNode reverseList(ListNode head) { + ListNode prev = null; + ListNode cur = head; + ListNode temp = null; + while (cur != null) { + temp = cur.next;// 保存下一个节点 + cur.next = prev; + prev = cur; + cur = temp; + } + return prev; + } +} +``` +```java +// 递归 +class Solution { + public ListNode reverseList(ListNode head) { + return reverse(null, head); + } + + private ListNode reverse(ListNode prev, ListNode cur) { + if (cur == null) { + return prev; + } + ListNode temp = null; + temp = cur.next;// 先保存下一个节点 + cur.next = prev;// 反转 + // 更新prev、cur位置 + prev = cur; + cur = temp; + return reverse(prev, cur); + } +} +``` Python: @@ -116,4 +154,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -

+
\ No newline at end of file diff --git a/problems/0209.长度最小的子数组.md b/problems/0209.长度最小的子数组.md index 1b00c4e3..0aaa466e 100644 --- a/problems/0209.长度最小的子数组.md +++ b/problems/0209.长度最小的子数组.md @@ -148,7 +148,25 @@ class Solution: Java: +```java +class Solution { + // 滑动窗口 + public int minSubArrayLen(int s, int[] nums) { + int left = 0; + int sum = 0; + int result = Integer.MAX_VALUE; + for (int right = 0; right < nums.length; right++) { + sum += nums[right]; + while (sum >= s) { + result = Math.min(result, right - left + 1); + sum -= nums[left++]; + } + } + return result == Integer.MAX_VALUE ? 0 : result; + } +} +``` Python: @@ -177,4 +195,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) -
+
\ No newline at end of file diff --git a/problems/0213.打家劫舍II.md b/problems/0213.打家劫舍II.md index 55e71bc0..fc58a065 100644 --- a/problems/0213.打家劫舍II.md +++ b/problems/0213.打家劫舍II.md @@ -98,7 +98,28 @@ public: Java: +```Java +class Solution { + public int rob(int[] nums) { + if (nums == null || nums.length == 0) + return 0; + int len = nums.length; + if (len == 1) + return nums[0]; + return Math.max(robAction(nums, 0, len - 1), robAction(nums, 1, len)); + } + int robAction(int[] nums, int start, int end) { + int x = 0, y = 0, z = 0; + for (int i = start; i < end; i++) { + y = z; + z = Math.max(y, x + nums[i]); + x = y; + } + return z; + } +} +``` Python: diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index 11a8eb8f..bcb443e3 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -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> result; // 存放结果集 @@ -227,7 +227,39 @@ public: Java: +```java +class Solution { + List> res = new ArrayList<>(); + List list = new ArrayList<>(); + public List> combinationSum3(int k, int n) { + res.clear(); + list.clear(); + backtracking(k, n, 9); + return res; + } + + private void backtracking(int k, int n, int maxNum) { + if (k == 0 && n == 0) { + res.add(new ArrayList<>(list)); + return; + } + + // 因为不能重复,并且单个数字最大值是maxNum,所以sum最大值为 + // (maxNum + (maxNum - 1) + ... + (maxNum - k + 1)) == k * maxNum - k*(k - 1) / 2 + if (maxNum == 0 + || n > k * maxNum - k * (k - 1) / 2 + || n < (1 + k) * k / 2) { + return; + } + list.add(maxNum); + backtracking(k - 1, n - maxNum, maxNum - 1); + list.remove(list.size() - 1); + backtracking(k, n, maxNum - 1); + } + +} +``` Python: diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md index 367fa717..b28b8dfb 100644 --- a/problems/0222.完全二叉树的节点个数.md +++ b/problems/0222.完全二叉树的节点个数.md @@ -194,7 +194,49 @@ public: Java: +```java +class Solution { + // 通用递归解法 + public int countNodes(TreeNode root) { + if(root == null) { + return 0; + } + return countNodes(root.left) + countNodes(root.right) + 1; + } +} +``` +```java +class Solution { + /** + * 针对完全二叉树的解法 + * + * 满二叉树的结点数为:2^depth - 1 + */ + public int countNodes(TreeNode root) { + if(root == null) { + return 0; + } + int leftDepth = getDepth(root.left); + int rightDepth = getDepth(root.right); + if (leftDepth == rightDepth) {// 左子树是满二叉树 + // 2^leftDepth其实是 (2^leftDepth - 1) + 1 ,左子树 + 根结点 + return (1 << leftDepth) + countNodes(root.right); + } else {// 右子树是满二叉树 + return (1 << rightDepth) + countNodes(root.left); + } + } + + private int getDepth(TreeNode root) { + int depth = 0; + while (root != null) { + root = root.left; + depth++; + } + return depth; + } +} +``` Python: @@ -208,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) -
+
\ No newline at end of file diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md index 49b5c62b..4018364a 100644 --- a/problems/0225.用队列实现栈.md +++ b/problems/0225.用队列实现栈.md @@ -154,9 +154,58 @@ public: ## 其他语言版本 - Java: +```java +class MyStack { + + Queue queue1; // 和栈中保持一样元素的队列 + Queue queue2; // 辅助队列 + + /** Initialize your data structure here. */ + public MyStack() { + queue1 = new LinkedList<>(); + queue2 = new LinkedList<>(); + } + + /** Push element x onto stack. */ + public void push(int x) { + queue2.offer(x); // 先放在辅助队列中 + while (!queue1.isEmpty()){ + queue2.offer(queue1.poll()); + } + Queue queueTemp; + queueTemp = queue1; + queue1 = queue2; + queue2 = queueTemp; // 最后交换queue1和queue2,将元素都放到queue1中 + } + + /** Removes the element on top of the stack and returns that element. */ + public int pop() { + return queue1.poll(); // 因为queue1中的元素和栈中的保持一致,所以这个和下面两个的操作只看queue1即可 + } + + /** Get the top element. */ + public int top() { + return queue1.peek(); + } + + /** Returns whether the stack is empty. */ + public boolean empty() { + return queue1.isEmpty(); + } +} + +/** + * Your MyQueue object will be instantiated and called as such: + * MyQueue obj = new MyQueue(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.peek(); + * boolean param_4 = obj.empty(); + */ +``` + Python: @@ -227,4 +276,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0226.翻转二叉树.md b/problems/0226.翻转二叉树.md index afc1f144..3b96b4f6 100644 --- a/problems/0226.翻转二叉树.md +++ b/problems/0226.翻转二叉树.md @@ -204,12 +204,48 @@ public: Java: +```Java +class Solution { + /** + * 前后序遍历都可以 + * 中序不行,因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),再右孩子交换孩子(此时其实是对原来的左孩子做交换) + */ + public TreeNode invertTree(TreeNode root) { + if (root == null) { + return null; + } + invertTree(root.left); + invertTree(root.right); + swapChildren(root); + return root; + } + + private void swapChildren(TreeNode root) { + TreeNode tmp = root.left; + root.left = root.right; + root.right = tmp; + } +} +``` Python: - Go: +```Go +func invertTree(root *TreeNode) *TreeNode { + if root ==nil{ + return nil + } + temp:=root.Left + root.Left=root.Right + root.Right=temp + + invertTree(root.Left) + invertTree(root.Right) + return root +} +``` @@ -217,4 +253,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md index 9907b476..abdc363d 100644 --- a/problems/0232.用栈实现队列.md +++ b/problems/0232.用栈实现队列.md @@ -19,7 +19,7 @@ push(x) -- 将一个元素放入队列的尾部。 pop() -- 从队列首部移除元素。 peek() -- 返回队列首部的元素。 empty() -- 返回队列是否为空。 -  + 示例: @@ -129,9 +129,62 @@ public: ## 其他语言版本 - Java: +```java +class MyQueue { + + Stack stack1; + Stack stack2; + + /** Initialize your data structure here. */ + public MyQueue() { + stack1 = new Stack<>(); // 负责进栈 + stack2 = new Stack<>(); // 负责出栈 + } + + /** Push element x to the back of queue. */ + public void push(int x) { + stack1.push(x); + } + + /** Removes the element from in front of queue and returns that element. */ + public int pop() { + dumpStack1(); + return stack2.pop(); + } + + /** Get the front element. */ + public int peek() { + dumpStack1(); + return stack2.peek(); + } + + /** Returns whether the queue is empty. */ + public boolean empty() { + return stack1.isEmpty() && stack2.isEmpty(); + } + + // 如果stack2为空,那么将stack1中的元素全部放到stack2中 + private void dumpStack1(){ + if (stack2.isEmpty()){ + while (!stack1.isEmpty()){ + stack2.push(stack1.pop()); + } + } + } +} + +/** + * Your MyQueue object will be instantiated and called as such: + * MyQueue obj = new MyQueue(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.peek(); + * boolean param_4 = obj.empty(); + */ +``` + Python: @@ -145,4 +198,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0235.二叉搜索树的最近公共祖先.md b/problems/0235.二叉搜索树的最近公共祖先.md index cb9de8b0..93642de5 100644 --- a/problems/0235.二叉搜索树的最近公共祖先.md +++ b/problems/0235.二叉搜索树的最近公共祖先.md @@ -29,7 +29,7 @@ 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 输出: 2 解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。 -  + 说明: @@ -229,7 +229,22 @@ public: Java: - +```java +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + while (true) { + if (root.val > p.val && root.val > q.val) { + root = root.left; + } else if (root.val < p.val && root.val < q.val) { + root = root.right; + } else { + break; + } + } + return root; + } +} +``` Python: @@ -243,4 +258,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0236.二叉树的最近公共祖先.md b/problems/0236.二叉树的最近公共祖先.md index 17096d48..3233c6a1 100644 --- a/problems/0236.二叉树的最近公共祖先.md +++ b/problems/0236.二叉树的最近公共祖先.md @@ -223,13 +223,77 @@ public: Java: +```Java +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + return lowestCommonAncestor1(root, p, q); + } + public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + TreeNode left = lowestCommonAncestor1(root.left, p, q); + TreeNode right = lowestCommonAncestor1(root.right, p, q); + if (left != null && right != null) {// 左右子树分别找到了,说明此时的root就是要求的结果 + return root; + } + if (left == null) { + return right; + } + return left; + } +} +``` +```java +// 代码精简版 +class Solution { + TreeNode pre; + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root.val == p.val ||root.val == q.val) return root; + TreeNode left = lowestCommonAncestor(root.left,p,q); + TreeNode right = lowestCommonAncestor(root.right,p,q); + if (left != null && right != null) return root; + else if (left == null && right != null) return right; + else if (left != null && right == null) return left; + else return null; + } +} +``` + Python: 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 +} +``` diff --git a/problems/0239.滑动窗口最大值.md b/problems/0239.滑动窗口最大值.md index 709fa09e..781bfa6f 100644 --- a/problems/0239.滑动窗口最大值.md +++ b/problems/0239.滑动窗口最大值.md @@ -207,7 +207,60 @@ public: Java: +```Java +//自定义数组 +class MyQueue { + Deque deque = new LinkedList<>(); + //弹出元素时,比较当前要弹出的数值是否等于队列出口的数值,如果相等则弹出 + //同时判断队列当前是否为空 + void poll(int val) { + if (!deque.isEmpty() && val == deque.peek()) { + deque.poll(); + } + } + //添加元素时,如果要添加的元素大于入口处的元素,就将入口元素弹出 + //保证队列元素单调递减 + //比如此时队列元素3,1,2将要入队,比1大,所以1弹出,此时队列:3,2 + void add(int val) { + while (!deque.isEmpty() && val > deque.getLast()) { + deque.removeLast(); + } + deque.add(val); + } + //队列队顶元素始终为最大值 + int peek() { + return deque.peek(); + } +} +class Solution { + public int[] maxSlidingWindow(int[] nums, int k) { + if (nums.length == 1) { + return nums; + } + int len = nums.length - k + 1; + //存放结果元素的数组 + int[] res = new int[len]; + int num = 0; + //自定义队列 + MyQueue myQueue = new MyQueue(); + //先将前k的元素放入队列 + for (int i = 0; i < k; i++) { + myQueue.add(nums[i]); + } + res[num++] = myQueue.peek(); + for (int i = k; i < nums.length; i++) { + //滑动窗口移除最前面的元素,移除是判断该元素是否放入队列 + myQueue.poll(nums[i - k]); + //滑动窗口加入最后面的元素 + myQueue.add(nums[i]); + //记录对应的最大值 + res[num++] = myQueue.peek(); + } + return res; + } +} +``` Python: diff --git a/problems/0242.有效的字母异位词.md b/problems/0242.有效的字母异位词.md index be553c5a..1927f476 100644 --- a/problems/0242.有效的字母异位词.md +++ b/problems/0242.有效的字母异位词.md @@ -85,7 +85,26 @@ public: Java: +```java +class Solution { + public boolean isAnagram(String s, String t) { + int[] record = new int[26]; + for (char c : s.toCharArray()) { + record[c - 'a'] += 1; + } + for (char c : t.toCharArray()) { + record[c - 'a'] -= 1; + } + for (int i : record) { + if (i != 0) { + return false; + } + } + return true; + } +} +``` Python: @@ -120,4 +139,4 @@ func isAnagram(s string, t string) bool { * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index a104b27c..1180225a 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -77,7 +77,7 @@ if (cur->left == NULL && cur->right == NULL) { 这里我们先使用vector结构的path容器来记录路径,那么终止处理逻辑如下: -``` +```C++ if (cur->left == NULL && cur->right == NULL) { // 遇到叶子节点 string sPath; for (int i = 0; i < path.size() - 1; i++) { // 将path里记录的路径转为string格式 @@ -113,7 +113,7 @@ if (cur->right) { 那么回溯要怎么回溯呢,一些同学会这么写,如下: -``` +```C++ if (cur->left) { traversal(cur->left, path, result); } @@ -129,7 +129,7 @@ path.pop_back(); 那么代码应该这么写: -``` +```C++ if (cur->left) { traversal(cur->left, path, result); path.pop_back(); // 回溯 @@ -280,13 +280,75 @@ public: ## 其他语言版本 - Java: +```Java +class Solution { + /** + * 递归法 + */ + public List binaryTreePaths(TreeNode root) { + List res = new ArrayList<>(); + if (root == null) { + return res; + } + List paths = new ArrayList<>(); + traversal(root, paths, res); + return res; + } + + private void traversal(TreeNode root, List paths, List res) { + paths.add(root.val); + // 叶子结点 + if (root.left == null && root.right == null) { + // 输出 + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < paths.size() - 1; i++) { + sb.append(paths.get(i)).append("->"); + } + sb.append(paths.get(paths.size() - 1)); + res.add(sb.toString()); + return; + } + if (root.left != null) { + traversal(root.left, paths, res); + paths.remove(paths.size() - 1);// 回溯 + } + if (root.right != null) { + traversal(root.right, paths, res); + paths.remove(paths.size() - 1);// 回溯 + } + } +} + +``` Python: +```Python +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def binaryTreePaths(self, root: TreeNode) -> List[str]: + path=[] + res=[] + def backtrace(root, path): + if not root:return + path.append(root.val) + if (not root.left)and (not root.right): + res.append(path[:]) + ways=[] + if root.left:ways.append(root.left) + if root.right:ways.append(root.right) + for way in ways: + backtrace(way,path) + path.pop() + backtrace(root,path) + return ["->".join(list(map(str,i))) for i in res] - +``` Go: diff --git a/problems/0279.完全平方数.md b/problems/0279.完全平方数.md index 39260926..d72e9099 100644 --- a/problems/0279.完全平方数.md +++ b/problems/0279.完全平方数.md @@ -159,7 +159,28 @@ public: Java: - +```Java +class Solution { + public int numSquares(int n) { + int max = Integer.MAX_VALUE; + int[] dp = new int[n + 1]; + //初始化 + for (int j = 0; j <= n; j++) { + dp[j] = max; + } + //当和为0时,组合的个数为0 + dp[0] = 0; + for (int i = 1; i * i <= n; i++) { + for (int j = i * i; j <= n; j++) { + if (dp[j - i * i] != max) { + dp[j] = Math.min(dp[j], dp[j - i * i] + 1); + } + } + } + return dp[n]; + } +} +``` Python: diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md index 2bc5cf9c..f3b51588 100644 --- a/problems/0300.最长上升子序列.md +++ b/problems/0300.最长上升子序列.md @@ -98,8 +98,6 @@ public: }; ``` -杨老师的这个专栏很不错,他本身也是Oracle 首席工程师,对Java有极其深刻的理解,讲的内容很硬核,适合使用Java语言的录友们用来进阶!作为面试突击手册非常合适, 所以推荐给大家!现在下单输入口令:javahexin,可以省40元那[机智] - ## 总结 本题最关键的是要想到dp[i]由哪些状态可以推出来,并取最大值,那么很自然就能想到递推公式:dp[i] = max(dp[i], dp[j] + 1); @@ -110,14 +108,58 @@ public: Java: - +```Java +class Solution { + public int lengthOfLIS(int[] nums) { + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + for (int i = 0; i < dp.length; i++) { + for (int j = 0; j < i; j++) { + if (nums[i] > nums[j]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + } + int res = 0; + for (int i = 0; i < dp.length; i++) { + res = Math.max(res, dp[i]); + } + return res; + } +} +``` 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/0337.打家劫舍III.md b/problems/0337.打家劫舍III.md index 50b06e22..20eea817 100644 --- a/problems/0337.打家劫舍III.md +++ b/problems/0337.打家劫舍III.md @@ -218,7 +218,72 @@ public: Java: +```Java +class Solution { + // 1.递归去偷,超时 + public int rob(TreeNode root) { + if (root == null) + return 0; + int money = root.val; + if (root.left != null) { + money += rob(root.left.left) + rob(root.left.right); + } + if (root.right != null) { + money += rob(root.right.left) + rob(root.right.right); + } + return Math.max(money, rob(root.left) + rob(root.right)); + } + // 2.递归去偷,记录状态 + // 执行用时:3 ms , 在所有 Java 提交中击败了 56.24% 的用户 + public int rob1(TreeNode root) { + Map memo = new HashMap<>(); + return robAction(root, memo); + } + + int robAction(TreeNode root, Map memo) { + if (root == null) + return 0; + if (memo.containsKey(root)) + return memo.get(root); + int money = root.val; + if (root.left != null) { + money += robAction(root.left.left, memo) + robAction(root.left.right, memo); + } + if (root.right != null) { + money += robAction(root.right.left, memo) + robAction(root.right.right, memo); + } + int res = Math.max(money, robAction(root.left, memo) + robAction(root.right, memo)); + memo.put(root, res); + return res; + } + + // 3.状态标记递归 + // 执行用时:0 ms , 在所有 Java 提交中击败了 100% 的用户 + // 不偷:Max(左孩子不偷,左孩子偷) + Max(又孩子不偷,右孩子偷) + // root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) + + // Math.max(rob(root.right)[0], rob(root.right)[1]) + // 偷:左孩子不偷+ 右孩子不偷 + 当前节点偷 + // root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val; + public int rob3(TreeNode root) { + int[] res = robAction1(root); + return Math.max(res[0], res[1]); + } + + int[] robAction1(TreeNode root) { + int res[] = new int[2]; + if (root == null) + return res; + + int[] left = robAction1(root.left); + int[] right = robAction1(root.right); + + res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]); + res[1] = root.val + left[0] + right[0]; + return res; + } +} +``` Python: diff --git a/problems/0344.反转字符串.md b/problems/0344.反转字符串.md index ddb9805d..b4c843b7 100644 --- a/problems/0344.反转字符串.md +++ b/problems/0344.反转字符串.md @@ -140,12 +140,37 @@ public: Java: - +```Java +class Solution { + public void reverseString(char[] s) { + int l = 0; + int r = s.length - 1; + while (l < r) { + s[l] ^= s[r]; //构造 a ^ b 的结果,并放在 a 中 + s[r] ^= s[l]; //将 a ^ b 这一结果再 ^ b ,存入b中,此时 b = a, a = a ^ b + s[l] ^= s[r]; //a ^ b 的结果再 ^ a ,存入 a 中,此时 b = a, a = b 完成交换 + l++; + r--; + } + } +} +``` Python: Go: +```Go +func reverseString(s []byte) { + left:=0 + right:=len(s)-1 + for left map = new HashMap<>(); + for (int num : nums) { + map.put(num, map.getOrDefault(num, 0) + 1); + } + + Set> entries = map.entrySet(); + // 根据map的value值正序排,相当于一个小顶堆 + PriorityQueue> queue = new PriorityQueue<>((o1, o2) -> o1.getValue() - o2.getValue()); + for (Map.Entry entry : entries) { + queue.offer(entry); + if (queue.size() > k) { + queue.poll(); + } + } + for (int i = k - 1; i >= 0; i--) { + result[i] = queue.poll().getKey(); + } + return result; + } +} +``` Python: diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index c196b467..b5116ee1 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -76,6 +76,37 @@ public: Java: +```Java +import java.util.HashSet; +import java.util.Set; + +class Solution { + public int[] intersection(int[] nums1, int[] nums2) { + if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) { + return new int[0]; + } + Set set1 = new HashSet<>(); + Set resSet = new HashSet<>(); + //遍历数组1 + for (int i : nums1) { + set1.add(i); + } + //遍历数组2的过程中判断哈希表中是否存在该元素 + for (int i : nums2) { + if (set1.contains(i)) { + resSet.add(i); + } + } + int[] resArr = new int[resSet.size()]; + int index = 0; + //将结果几何转为数组 + for (int i : resSet) { + resArr[index++] = i; + } + return resArr; + } +} +``` Python: diff --git a/problems/0376.摆动序列.md b/problems/0376.摆动序列.md index 6ae76526..fa90142d 100644 --- a/problems/0376.摆动序列.md +++ b/problems/0376.摆动序列.md @@ -111,7 +111,31 @@ public: Java: - +```Java +class Solution { + public int wiggleMaxLength(int[] nums) { + if (nums == null || nums.length <= 1) { + return nums.length; + } + //当前差值 + int curDiff = 0; + //上一个差值 + int preDiff = 0; + int count = 1; + for (int i = 1; i < nums.length; i++) { + //得到当前差值 + curDiff = nums[i] - nums[i - 1]; + //如果当前差值和上一个差值为一正一负 + //等于0的情况表示初始时的preDiff + if ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) { + count++; + preDiff = curDiff; + } + } + return count; + } +} +``` Python: diff --git a/problems/0377.组合总和Ⅳ.md b/problems/0377.组合总和Ⅳ.md index 8f8cfd86..eca9a13b 100644 --- a/problems/0377.组合总和Ⅳ.md +++ b/problems/0377.组合总和Ⅳ.md @@ -147,6 +147,7 @@ C++测试用例有超过两个树相加超过int的数据,所以需要在if里 Java: + ```Java class Solution { public int combinationSum4(int[] nums, int target) { @@ -163,10 +164,23 @@ class Solution { } } -``` Python: +```python +class Solution: + def combinationSum4(self, nums, target): + dp = [0] * (target + 1) + dp[0] = 1 + + for i in range(1, target+1): + for j in nums: + if i >= j: + dp[i] += dp[i - j] + + return dp[-1] +``` + Go: @@ -177,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) -
+
\ No newline at end of file diff --git a/problems/0383.赎金信.md b/problems/0383.赎金信.md index 742bfdc3..2f7ae4d8 100644 --- a/problems/0383.赎金信.md +++ b/problems/0383.赎金信.md @@ -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: - - ## 其他语言版本 diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md index 8ff2b320..5f303196 100644 --- a/problems/0404.左叶子之和.md +++ b/problems/0404.左叶子之和.md @@ -159,13 +159,71 @@ public: ## 其他语言版本 - Java: +**递归** + +```java +class Solution { + public int sumOfLeftLeaves(TreeNode root) { + if (root == null) return 0; + int leftValue = sumOfLeftLeaves(root.left); // 左 + int rightValue = sumOfLeftLeaves(root.right); // 右 + + int midValue = 0; + if (root.left != null && root.left.left == null && root.left.right == null) { // 中 + midValue = root.left.val; + } + int sum = midValue + leftValue + rightValue; + return sum; + } +} +``` + +**迭代** + +```java +class Solution { + public int sumOfLeftLeaves(TreeNode root) { + if (root == null) return 0; + Stack stack = new Stack<> (); + stack.add(root); + int result = 0; + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + if (node.left != null && node.left.left == null && node.left.right == null) { + result += node.left.val; + } + if (node.right != null) stack.add(node.right); + if (node.left != null) stack.add(node.left); + } + return result; + } +} +``` + + 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: @@ -175,4 +233,6 @@ 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/0406.根据身高重建队列.md b/problems/0406.根据身高重建队列.md index b5260a8c..c404ec8d 100644 --- a/problems/0406.根据身高重建队列.md +++ b/problems/0406.根据身高重建队列.md @@ -185,10 +185,44 @@ public: Java: +```java +class Solution { + public int[][] reconstructQueue(int[][] people) { + Arrays.sort(people, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + if (o1[0] != o2[0]) { + return Integer.compare(o2[0],o1[0]); + } else { + return Integer.compare(o1[1],o2[1]); + } + } + }); + LinkedList que = new LinkedList<>(); + + for (int[] p : people) { + que.add(p[1],p); + } + + return que.toArray(new int[people.length][]); + } +} +``` 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: diff --git a/problems/0435.无重叠区间.md b/problems/0435.无重叠区间.md index 3df496f4..4341f3b8 100644 --- a/problems/0435.无重叠区间.md +++ b/problems/0435.无重叠区间.md @@ -182,7 +182,34 @@ public: Java: +```java +class Solution { + public int eraseOverlapIntervals(int[][] intervals) { + if (intervals.length < 2) return 0; + Arrays.sort(intervals, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + if (o1[0] != o2[0]) { + return Integer.compare(o1[1],o2[1]); + } else { + return Integer.compare(o2[0],o1[0]); + } + } + }); + int count = 0; + int edge = intervals[0][1]; + for (int i = 1; i < intervals.length; i++) { + if (intervals[i][0] < edge) { + count++; + } else { + edge = intervals[i][1]; + } + } + return count; + } +} +``` Python: @@ -196,4 +223,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0450.删除二叉搜索树中的节点.md b/problems/0450.删除二叉搜索树中的节点.md index ed0cb9d7..604fb376 100644 --- a/problems/0450.删除二叉搜索树中的节点.md +++ b/problems/0450.删除二叉搜索树中的节点.md @@ -251,12 +251,77 @@ public: Java: +```java +class Solution { + public TreeNode deleteNode(TreeNode root, int key) { + root = delete(root,key); + return root; + } + private TreeNode delete(TreeNode root, int key) { + if (root == null) return null; + + if (root.val > key) { + root.left = delete(root.left,key); + } else if (root.val < key) { + root.right = delete(root.right,key); + } else { + if (root.left == null) return root.right; + if (root.right == null) return root.left; + TreeNode tmp = root.right; + while (tmp.left != null) { + tmp = tmp.left; + } + root.val = tmp.val; + root.right = delete(root.right,tmp.val); + } + return root; + } +} +``` Python: Go: +```Go +func deleteNode(root *TreeNode, key int) *TreeNode { + if root==nil{ + return nil + } + if keyroot.Val{ + root.Right=deleteNode(root.Right,key) + return root + } + if root.Right==nil{ + return root.Left + } + if root.Left==nil{ + return root.Right + } + minnode:=root.Right + for minnode.Left!=nil{ + minnode=minnode.Left + } + root.Val=minnode.Val + root.Right=deleteNode1(root.Right) + return root +} + +func deleteNode1(root *TreeNode)*TreeNode{ + if root.Left==nil{ + pRight:=root.Right + root.Right=nil + return pRight + } + root.Left=deleteNode1(root.Left) + return root +} +``` @@ -265,4 +330,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0452.用最少数量的箭引爆气球.md b/problems/0452.用最少数量的箭引爆气球.md index 7372ea92..f62fb153 100644 --- a/problems/0452.用最少数量的箭引爆气球.md +++ b/problems/0452.用最少数量的箭引爆气球.md @@ -139,7 +139,32 @@ public: Java: +```java +class Solution { + public int findMinArrowShots(int[][] points) { + Arrays.sort(points, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + if (o1[0] != o2[0]) { + return Integer.compare(o1[0],o2[0]); + } else { + return Integer.compare(o1[0],o2[0]); + } + } + }); + int count = 1; + for (int i = 1; i < points.length; i++) { + if (points[i][0] > points[i - 1][1]) { + count++; + } else { + points[i][1] = Math.min(points[i][1],points[i - 1][1]); + } + } + return count; + } +} +``` Python: @@ -153,4 +178,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0455.分发饼干.md b/problems/0455.分发饼干.md index ca3eba74..f57a7fa6 100644 --- a/problems/0455.分发饼干.md +++ b/problems/0455.分发饼干.md @@ -30,7 +30,7 @@ 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 你拥有的饼干数量和尺寸都足以让所有孩子满足。 所以你应该输出2. -  + 提示: * 1 <= g.length <= 3 * 10^4 @@ -115,7 +115,23 @@ public: Java: - +```java +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int start = 0; + int count = 0; + for (int i = 0; i < s.length && start < g.length; i++) { + if (s[i] >= g[start]) { + start++; + count++; + } + } + return count; + } +} +``` Python: @@ -129,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) -
+
\ No newline at end of file diff --git a/problems/0491.递增子序列.md b/problems/0491.递增子序列.md index 5deec0ee..ebcd9541 100644 --- a/problems/0491.递增子序列.md +++ b/problems/0491.递增子序列.md @@ -200,6 +200,32 @@ public: Java: +```java +class Solution { + private List path = new ArrayList<>(); + private List> res = new ArrayList<>(); + public List> findSubsequences(int[] nums) { + backtracking(nums,0); + return res; + } + + private void backtracking (int[] nums, int start) { + if (path.size() > 1) { + res.add(new ArrayList<>(path)); + } + + int[] used = new int[201]; + for (int i = start; i < nums.length; i++) { + if (!path.isEmpty() && nums[i] < path.get(path.size() - 1) || + (used[nums[i] + 100] == 1)) continue; + used[nums[i] + 100] = 1; + path.add(nums[i]); + backtracking(nums, i + 1); + path.remove(path.size() - 1); + } + } +} +``` Python: @@ -207,6 +233,34 @@ Python: Go: +Javascript: + +```Javascript + +var findSubsequences = function(nums) { + let result = [] + let path = [] + function backtracing(startIndex) { + if(path.length > 1) { + result.push(path.slice()) + } + let uset = [] + for(let i = startIndex; i < nums.length; i++) { + if((path.length > 0 && nums[i] < path[path.length - 1]) || uset[nums[i] + 100]) { + continue + } + uset[nums[i] + 100] = true + path.push(nums[i]) + backtracing(i + 1) + path.pop() + } + } + backtracing(0) + return result +}; + +``` + @@ -214,4 +268,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md index 2fb2a5eb..1782c88c 100644 --- a/problems/0494.目标和.md +++ b/problems/0494.目标和.md @@ -241,7 +241,24 @@ dp[j] += dp[j - nums[i]]; Java: - +```java +class Solution { + public int findTargetSumWays(int[] nums, int target) { + int sum = 0; + for (int i = 0; i < nums.length; i++) sum += nums[i]; + if ((target + sum) % 2 != 0) return 0; + int size = (target + sum) / 2; + int[] dp = new int[size + 1]; + dp[0] = 1; + for (int i = 0; i < nums.length; i++) { + for (int j = size; j >= nums[i]; j--) { + dp[j] += dp[j - nums[i]]; + } + } + return dp[size]; + } +} +``` Python: @@ -255,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) -
+
\ No newline at end of file diff --git a/problems/0501.二叉搜索树中的众数.md b/problems/0501.二叉搜索树中的众数.md index 0e8c0d0e..385ce2f1 100644 --- a/problems/0501.二叉搜索树中的众数.md +++ b/problems/0501.二叉搜索树中的众数.md @@ -345,6 +345,53 @@ public: Java: +```Java +class Solution { + ArrayList resList; + int maxCount; + int count; + TreeNode pre; + + public int[] findMode(TreeNode root) { + resList = new ArrayList<>(); + maxCount = 0; + count = 0; + pre = null; + findMode1(root); + int[] res = new int[resList.size()]; + for (int i = 0; i < resList.size(); i++) { + res[i] = resList.get(i); + } + return res; + } + + public void findMode1(TreeNode root) { + if (root == null) { + return; + } + findMode1(root.left); + + int rootValue = root.val; + // 计数 + if (pre == null || rootValue != pre.val) { + count = 1; + } else { + count++; + } + // 更新结果以及maxCount + if (count > maxCount) { + resList.clear(); + resList.add(rootValue); + maxCount = count; + } else if (count == maxCount) { + resList.add(rootValue); + } + pre = root; + + findMode1(root.right); + } +} +``` Python: @@ -358,4 +405,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0509.斐波那契数.md b/problems/0509.斐波那契数.md index 8537ed8b..112c96f9 100644 --- a/problems/0509.斐波那契数.md +++ b/problems/0509.斐波那契数.md @@ -171,10 +171,40 @@ public: Java: - +```Java +class Solution { + public int fib(int n) { + if (n < 2) return n; + int a = 0, b = 1, c = 0; + for (int i = 1; i < n; i++) { + c = a + b; + a = b; + b = c; + } + return c; + } +} +``` 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: diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index 19c870c3..44096a29 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -218,10 +218,84 @@ public: Java: +```java +// 递归法 +class Solution { + private int Deep = -1; + private int value = 0; + public int findBottomLeftValue(TreeNode root) { + value = root.val; + findLeftValue(root,0); + return value; + } + + private void findLeftValue (TreeNode root,int deep) { + if (root == null) return; + if (root.left == null && root.right == null) { + if (deep > Deep) { + value = root.val; + Deep = deep; + } + } + if (root.left != null) findLeftValue(root.left,deep + 1); + if (root.right != null) findLeftValue(root.right,deep + 1); + } +} +``` + +```java +//迭代法 +class Solution { + + public int findBottomLeftValue(TreeNode root) { + Queue queue = new LinkedList<>(); + queue.offer(root); + int res = 0; + while (!queue.isEmpty()) { + int size = queue.size(); + for (int i = 0; i < size; i++) { + TreeNode poll = queue.poll(); + if (i == 0) { + res = poll.val; + } + if (poll.left != null) { + queue.offer(poll.left); + } + if (poll.right != null) { + queue.offer(poll.right); + } + } + } + return res; + } +} +``` + + 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: diff --git a/problems/0516.最长回文子序列.md b/problems/0516.最长回文子序列.md index 813e75f5..d7acef99 100644 --- a/problems/0516.最长回文子序列.md +++ b/problems/0516.最长回文子序列.md @@ -148,6 +148,25 @@ public: Java: +```java +public class Solution { + public int longestPalindromeSubseq(String s) { + int len = s.length(); + int[][] dp = new int[len + 1][len + 1]; + for (int i = len - 1; i >= 0; i--) { // 从后往前遍历 保证情况不漏 + dp[i][i] = 1; // 初始化 + for (int j = i + 1; j < len; j++) { + if (s.charAt(i) == s.charAt(j)) { + dp[i][j] = dp[i + 1][j - 1] + 2; + } else { + dp[i][j] = Math.max(dp[i + 1][j], Math.max(dp[i][j], dp[i][j - 1])); + } + } + } + return dp[0][len - 1]; + } +} +``` Python: diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md index d5abc692..903ebf78 100644 --- a/problems/0530.二叉搜索树的最小绝对差.md +++ b/problems/0530.二叉搜索树的最小绝对差.md @@ -152,6 +152,29 @@ public: Java: +```Java +class Solution { + TreeNode pre;// 记录上一个遍历的结点 + int result = Integer.MAX_VALUE; + public int getMinimumDifference(TreeNode root) { + if (root == null) { + return result; + } + // 左 + int left = getMinimumDifference(root.left); + + // 中 + if (pre != null) { + result = Math.min(left, root.val - pre.val); + } + pre = root; + // 右 + int right = getMinimumDifference(root.right); + result = Math.min(right, result); + return result; + } +} +``` Python: @@ -165,4 +188,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0538.把二叉搜索树转换为累加树.md b/problems/0538.把二叉搜索树转换为累加树.md index a5f4c43c..209c989b 100644 --- a/problems/0538.把二叉搜索树转换为累加树.md +++ b/problems/0538.把二叉搜索树转换为累加树.md @@ -173,7 +173,27 @@ public: Java: +```Java +class Solution { + int sum; + public TreeNode convertBST(TreeNode root) { + sum = 0; + convertBST1(root); + return root; + } + // 按右中左顺序遍历,累加即可 + public void convertBST1(TreeNode root) { + if (root == null) { + return; + } + convertBST1(root.right); + sum += root.val; + root.val = sum; + convertBST1(root.left); + } +} +``` Python: @@ -187,4 +207,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0541.反转字符串II.md b/problems/0541.反转字符串II.md index 6a84006e..0a92ac8b 100644 --- a/problems/0541.反转字符串II.md +++ b/problems/0541.反转字符串II.md @@ -46,7 +46,7 @@ https://leetcode-cn.com/problems/reverse-string-ii/ 使用C++库函数reverse的版本如下: -``` +```C++ class Solution { public: string reverseStr(string s, int k) { @@ -68,7 +68,8 @@ public: 那么我们也可以实现自己的reverse函数,其实和题目[344. 反转字符串](https://mp.weixin.qq.com/s/X02S61WCYiCEhaik6VUpFA)道理是一样的。 下面我实现的reverse函数区间是左闭右闭区间,代码如下: -``` + +```C++ class Solution { public: void reverse(string& s, int start, int end) { @@ -101,7 +102,36 @@ public: Java: +```Java +class Solution { + public String reverseStr(String s, int k) { + StringBuffer res = new StringBuffer(); + for (int i = 0; i < s.length(); i += (2 * k)) { + StringBuffer temp = new StringBuffer(); + // 剩余字符大于 k 个,每隔 2k 个字符的前 k 个字符进行反转 + if (i + k <= s.length()) { + // 反转前 k 个字符 + temp.append(s.substring(i, i + k)); + res.append(temp.reverse()); + + // 反转完前 k 个字符之后,如果紧接着还有 k 个字符,则直接加入这 k 个字符 + if (i + 2 * k <= s.length()) { + res.append(s.substring(i + k, i + 2 * k)); + // 不足 k 个字符,则直接加入剩下所有字符 + } else { + res.append(s.substring(i + k, s.length())); + } + continue; + } + // 剩余字符少于 k 个,则将剩余字符全部反转。 + temp.append(s.substring(i, s.length())); + res.append(temp.reverse()); + } + return res.toString(); + } +} +``` Python: diff --git a/problems/0617.合并二叉树.md b/problems/0617.合并二叉树.md index adc0703b..848454de 100644 --- a/problems/0617.合并二叉树.md +++ b/problems/0617.合并二叉树.md @@ -257,6 +257,59 @@ public: Java: +```Java +class Solution { + // 递归 + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null) return root2; + if (root2 == null) return root1; + + TreeNode newRoot = new TreeNode(root1.val + root2.val); + newRoot.left = mergeTrees(root1.left,root2.left); + newRoot.right = mergeTrees(root1.right,root2.right); + return newRoot; + } +} +``` + +```Java +class Solution { + // 迭代 + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null) { + return root2; + } + if (root2 == null) { + return root1; + } + Stack stack = new Stack<>(); + stack.push(root2); + stack.push(root1); + while (!stack.isEmpty()) { + TreeNode node1 = stack.pop(); + TreeNode node2 = stack.pop(); + node1.val += node2.val; + if (node2.right != null && node1.right != null) { + stack.push(node2.right); + stack.push(node1.right); + } else { + if (node1.right == null) { + node1.right = node2.right; + } + } + if (node2.left != null && node1.left != null) { + stack.push(node2.left); + stack.push(node1.left); + } else { + if (node1.left == null) { + node1.left = node2.left; + } + } + } + return root1; + } +} +``` Python: @@ -270,4 +323,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0647.回文子串.md b/problems/0647.回文子串.md index fbc9133e..45bb72be 100644 --- a/problems/0647.回文子串.md +++ b/problems/0647.回文子串.md @@ -227,6 +227,30 @@ Python: Go: +```Go +func countSubstrings(s string) int { + res:=0 + dp:=make([][]bool,len(s)) + for i:=0;i=0;i--{ + for j:=i;jright = traversal(nums, maxValueIndex + 1, right); Java: +```Java +class Solution { + public TreeNode constructMaximumBinaryTree(int[] nums) { + return constructMaximumBinaryTree1(nums, 0, nums.length); + } + + public TreeNode constructMaximumBinaryTree1(int[] nums, int leftIndex, int rightIndex) { + if (rightIndex - leftIndex < 1) {// 没有元素了 + return null; + } + if (rightIndex - leftIndex == 1) {// 只有一个元素 + return new TreeNode(nums[leftIndex]); + } + int maxIndex = leftIndex;// 最大值所在位置 + int maxVal = nums[maxIndex];// 最大值 + for (int i = leftIndex + 1; i < rightIndex; i++) { + if (nums[i] > maxVal){ + maxVal = nums[i]; + maxIndex = i; + } + } + TreeNode root = new TreeNode(maxVal); + // 根据maxIndex划分左右子树 + root.left = constructMaximumBinaryTree1(nums, leftIndex, maxIndex); + root.right = constructMaximumBinaryTree1(nums, maxIndex + 1, rightIndex); + return root; + } +} +``` 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: diff --git a/problems/0669.修剪二叉搜索树.md b/problems/0669.修剪二叉搜索树.md index 41f684f4..8b9e1f6d 100644 --- a/problems/0669.修剪二叉搜索树.md +++ b/problems/0669.修剪二叉搜索树.md @@ -243,6 +243,26 @@ public: Java: +```Java +class Solution { + public TreeNode trimBST(TreeNode root, int low, int high) { + if (root == null) { + return null; + } + if (root.val < low) { + return trimBST(root.right, low, high); + } + if (root.val > high) { + return trimBST(root.left, low, high); + } + // root在[low,high]范围内 + root.left = trimBST(root.left, low, high); + root.right = trimBST(root.right, low, high); + return root; + } +} + +``` Python: @@ -256,4 +276,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0700.二叉搜索树中的搜索.md b/problems/0700.二叉搜索树中的搜索.md index 5c1cdfdf..277ef681 100644 --- a/problems/0700.二叉搜索树中的搜索.md +++ b/problems/0700.二叉搜索树中的搜索.md @@ -140,12 +140,99 @@ public: ## 其他语言版本 - Java: +```Java +class Solution { + // 递归,普通二叉树 + public TreeNode searchBST(TreeNode root, int val) { + if (root == null || root.val == val) { + return root; + } + TreeNode left = searchBST(root.left, val); + if (left != null) { + return left; + } + return searchBST(root.right, val); + } +} + +class Solution { + // 递归,利用二叉搜索树特点,优化 + public TreeNode searchBST(TreeNode root, int val) { + if (root == null || root.val == val) { + return root; + } + if (val < root.val) { + return searchBST(root.left, val); + } else { + return searchBST(root.right, val); + } + } +} + +class Solution { + // 迭代,普通二叉树 + public TreeNode searchBST(TreeNode root, int val) { + if (root == null || root.val == val) { + return root; + } + Stack stack = new Stack<>(); + stack.push(root); + while (!stack.isEmpty()) { + TreeNode pop = stack.pop(); + if (pop.val == val) { + return pop; + } + if (pop.right != null) { + stack.push(pop.right); + } + if (pop.left != null) { + stack.push(pop.left); + } + } + return null; + } +} + +class Solution { + // 迭代,利用二叉搜索树特点,优化,可以不需要栈 + public TreeNode searchBST(TreeNode root, int val) { + while (root != null) + if (val < root.val) root = root.left; + else if (val > root.val) root = root.right; + else return root; + return root; + } +} +``` Python: +递归法: + +```python +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 +``` + +迭代法: + +```python +class Solution: + def searchBST(self, root: TreeNode, val: int) -> TreeNode: + while root is not None: + if val < root.val: root = root.left + elif val > root.val: root = root.right + else: return root + return root +``` + Go: @@ -156,4 +243,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0701.二叉搜索树中的插入操作.md b/problems/0701.二叉搜索树中的插入操作.md index 760509d9..122a1d2a 100644 --- a/problems/0701.二叉搜索树中的插入操作.md +++ b/problems/0701.二叉搜索树中的插入操作.md @@ -16,7 +16,7 @@ 注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。 ![701.二叉搜索树中的插入操作](https://img-blog.csdnimg.cn/20201019173259554.png) -  + 提示: * 给定的树上的节点数介于 0 和 10^4 之间 @@ -206,14 +206,85 @@ public: ## 其他语言版本 - Java: +```java +class Solution { + public TreeNode insertIntoBST(TreeNode root, int val) { + if (root == null) return new TreeNode(val); + TreeNode newRoot = root; + TreeNode pre = root; + while (root != null) { + pre = root; + if (root.val > val) { + root = root.left; + } else if (root.val < val) { + root = root.right; + } + } + if (pre.val > val) { + pre.left = new TreeNode(val); + } else { + pre.right = new TreeNode(val); + } + return newRoot; + } +} +``` + +递归法 + +```java +class Solution { + public TreeNode insertIntoBST(TreeNode root, int val) { + return buildTree(root, val); + } + + public TreeNode buildTree(TreeNode root, int val){ + if (root == null) // 如果当前节点为空,也就意味着val找到了合适的位置,此时创建节点直接返回。 + return new TreeNode(val); + if (root.val < val){ + root.right = buildTree(root.right, val); // 递归创建右子树 + }else if (root.val > val){ + root.left = buildTree(root.left, val); // 递归创建左子树 + } + return root; + } +} +``` Python: +递归法 + +```python +class Solution: + def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode: + if root is None: + return TreeNode(val) # 如果当前节点为空,也就意味着val找到了合适的位置,此时创建节点直接返回。 + if root.val < val: + root.right = self.insertIntoBST(root.right, val) # 递归创建右子树 + if root.val > val: + root.left = self.insertIntoBST(root.left, val) # 递归创建左子树 + return root +``` + 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 +} +``` diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index bb013d95..c7207364 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -23,7 +23,7 @@ 输入: nums = [-1,0,3,5,9,12], target = 2 输出: -1 解释: 2 不存在 nums 中因此返回 -1 -  + 提示: * 你可以假设 nums 中的所有元素是不重复的。 @@ -146,11 +146,50 @@ public: ## 其他语言版本 - Java: +(版本一)左闭右闭区间 + +```java +class Solution { + public int search(int[] nums, int target) { + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + ((right - left) >> 1); + if (nums[mid] == target) + return mid; + else if (nums[mid] < target) + left = mid + 1; + else if (nums[mid] > target) + right = mid - 1; + } + return -1; + } +} +``` + +(版本二)左闭右开区间 + +```java +class Solution { + public int search(int[] nums, int target) { + int left = 0, right = nums.length; + while (left < right) { + int mid = left + ((right - left) >> 1); + if (nums[mid] == target) + return mid; + else if (nums[mid] < target) + left = mid + 1; + else if (nums[mid] > target) + right = mid; + } + return -1; + } +} +``` Python: + ```python3 class Solution: def search(self, nums: List[int], target: int) -> int: @@ -178,4 +217,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0707.设计链表.md b/problems/0707.设计链表.md index 93133b55..86cf623b 100644 --- a/problems/0707.设计链表.md +++ b/problems/0707.设计链表.md @@ -231,8 +231,166 @@ 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: diff --git a/problems/0714.买卖股票的最佳时机含手续费.md b/problems/0714.买卖股票的最佳时机含手续费.md index 6d0e6a5e..99f01197 100644 --- a/problems/0714.买卖股票的最佳时机含手续费.md +++ b/problems/0714.买卖股票的最佳时机含手续费.md @@ -155,6 +155,24 @@ public: ## 其他语言版本 Java: +```java +// 贪心思路 +class Solution { + public int maxProfit(int[] prices, int fee) { + int buy = prices[0] + fee; + int sum = 0; + for (int p : prices) { + if (p + fee < buy) { + buy = p + fee; + } else if (p > buy){ + sum += p - buy; + buy = p; + } + } + return sum; + } +} +``` ```java class Solution { // 动态规划 diff --git a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md index 3926643d..a239e5d8 100644 --- a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md +++ b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md @@ -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..f0f9a883 100644 --- a/problems/0718.最长重复子数组.md +++ b/problems/0718.最长重复子数组.md @@ -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 d423d4d6..dc136028 100644 --- a/problems/0738.单调递增的数字.md +++ b/problems/0738.单调递增的数字.md @@ -125,6 +125,24 @@ public: Java: +```java +class Solution { + public int monotoneIncreasingDigits(int N) { + String[] strings = (N + "").split(""); + int start = strings.length; + for (int i = strings.length - 1; i > 0; i--) { + if (Integer.parseInt(strings[i]) < Integer.parseInt(strings[i - 1])) { + strings[i - 1] = (Integer.parseInt(strings[i - 1]) - 1) + ""; + start = i; + } + } + for (int i = start; i < strings.length; i++) { + strings[i] = "9"; + } + return Integer.parseInt(String.join("",strings)); + } +} +``` Python: @@ -139,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) -
+
\ No newline at end of file diff --git a/problems/0763.划分字母区间.md b/problems/0763.划分字母区间.md index 1b93edf7..c1474280 100644 --- a/problems/0763.划分字母区间.md +++ b/problems/0763.划分字母区间.md @@ -84,7 +84,28 @@ public: Java: - +```java +class Solution { + public List partitionLabels(String S) { + List list = new LinkedList<>(); + int[] edge = new int[123]; + char[] chars = S.toCharArray(); + for (int i = 0; i < chars.length; i++) { + edge[chars[i] - 0] = i; + } + int idx = 0; + int last = -1; + for (int i = 0; i < chars.length; i++) { + idx = Math.max(idx,edge[chars[i] - 0]); + if (i == idx) { + list.add(i - last); + last = i; + } + } + return list; + } +} +``` Python: diff --git a/problems/0860.柠檬水找零.md b/problems/0860.柠檬水找零.md index c718b0cd..052bcdb1 100644 --- a/problems/0860.柠檬水找零.md +++ b/problems/0860.柠檬水找零.md @@ -127,10 +127,59 @@ public: Java: +```java +class Solution { + public boolean lemonadeChange(int[] bills) { + int cash_5 = 0; + int cash_10 = 0; + for (int i = 0; i < bills.length; i++) { + if (bills[i] == 5) { + cash_5++; + } else if (bills[i] == 10) { + cash_5--; + cash_10++; + } else if (bills[i] == 20) { + if (cash_10 > 0) { + cash_10--; + cash_5--; + } else { + cash_5 -= 3; + } + } + if (cash_5 < 0 || cash_10 < 0) return false; + } + + return true; + } +} +``` 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: diff --git a/problems/0968.监控二叉树.md b/problems/0968.监控二叉树.md index ab2bd2e5..e541ba13 100644 --- a/problems/0968.监控二叉树.md +++ b/problems/0968.监控二叉树.md @@ -316,6 +316,33 @@ public: Java: +```java +class Solution { + private int count = 0; + public int minCameraCover(TreeNode root) { + if (trval(root) == 0) count++; + return count; + } + + private int trval(TreeNode root) { + if (root == null) return -1; + + int left = trval(root.left); + int right = trval(root.right); + + if (left == 0 || right == 0) { + count++; + return 2; + } + + if (left == 2 || right == 2) { + return 1; + } + + return 0; + } +} +``` Python: @@ -330,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) -
+
\ No newline at end of file diff --git a/problems/1005.K次取反后最大化的数组和.md b/problems/1005.K次取反后最大化的数组和.md index b2073e14..89ed9176 100644 --- a/problems/1005.K次取反后最大化的数组和.md +++ b/problems/1005.K次取反后最大化的数组和.md @@ -29,7 +29,7 @@ 输入:A = [2,-3,-1,5,-4], K = 2 输出:13 解释:选择索引 (1, 4) ,然后 A 变为 [2,3,-1,5,4]。 -  + 提示: * 1 <= A.length <= 10000 @@ -99,10 +99,43 @@ public: Java: +```java +class Solution { + public int largestSumAfterKNegations(int[] A, int K) { + if (A.length == 1) return A[0]; + Arrays.sort(A); + int sum = 0; + int idx = 0; + for (int i = 0; i < K; i++) { + if (i < A.length - 1 && A[idx] < 0) { + A[idx] = -A[idx]; + if (A[idx] >= Math.abs(A[idx + 1])) idx++; + continue; + } + A[idx] = -A[idx]; + } + for (int i = 0; i < A.length; i++) { + sum += A[i]; + } + return sum; + } +} +``` Python: - +```python +class Solution: + def largestSumAfterKNegations(self, A: List[int], K: int) -> int: + A = sorted(A, key=abs, reverse=True) # 将A按绝对值从大到小排列 + for i in range(len(A)): + if K > 0 and A[i] < 0: + A[i] *= -1 + K -= 1 + if K > 0: + A[len(A) - 1] *= ((-1)**K) + return sum(A) +``` Go: diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md index 7a06f02d..607a4ccf 100644 --- a/problems/1047.删除字符串中的所有相邻重复项.md +++ b/problems/1047.删除字符串中的所有相邻重复项.md @@ -122,10 +122,41 @@ public: Java: - +```Java +class Solution { + public String removeDuplicates(String S) { + Deque deque = new LinkedList<>(); + char ch; + for (int i = 0; i < S.length(); i++) { + ch = S.charAt(i); + if (deque.isEmpty() || deque.peek() != ch) { + deque.push(ch); + } else { + deque.pop(); + } + } + String str = ""; + //剩余的元素即为不重复的元素 + while (!deque.isEmpty()) { + str = deque.pop() + str; + } + return str; + } +} +``` 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/1143.最长公共子序列.md b/problems/1143.最长公共子序列.md index 0664b0d9..961924c8 100644 --- a/problems/1143.最长公共子序列.md +++ b/problems/1143.最长公共子序列.md @@ -31,7 +31,7 @@ 输入:text1 = "abc", text2 = "def" 输出:0 解释:两个字符串没有公共子序列,返回 0。 -  + 提示: * 1 <= text1.length <= 1000 * 1 <= text2.length <= 1000 @@ -126,14 +126,74 @@ public: ## 其他语言版本 - Java: +```java +class Solution { + public int longestCommonSubsequence(String text1, String text2) { + int[][] dp = new int[text1.length() + 1][text2.length() + 1]; // 先对dp数组做初始化操作 + for (int i = 1 ; i <= text1.length() ; i++) { + char char1 = text1.charAt(i - 1); + for (int j = 1; j <= text2.length(); j++) { + char char2 = text2.charAt(j - 1); + if (char1 == char2) { // 开始列出状态转移方程 + 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[text1.length()][text2.length()]; + } +} +``` Python: +```python +class Solution: + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + len1, len2 = len(text1)+1, len(text2)+1 + dp = [[0 for _ in range(len1)] for _ in range(len2)] # 先对dp数组做初始化操作 + for i in range(1, len2): + for j in range(1, len1): # 开始列出状态转移方程 + if text1[j-1] == text2[i-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[-1][-1] +``` + 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 +} +``` diff --git a/problems/二叉树的递归遍历.md b/problems/二叉树的递归遍历.md index 02d4b060..937ef603 100644 --- a/problems/二叉树的递归遍历.md +++ b/problems/二叉树的递归遍历.md @@ -115,10 +115,108 @@ void traversal(TreeNode* cur, vector& vec) { Java: +```Java +// 前序遍历·递归·LC144_二叉树的前序遍历 +class Solution { + ArrayList preOrderReverse(TreeNode root) { + ArrayList result = new ArrayList(); + preOrder(root, result); + return result; + } + void preOrder(TreeNode root, ArrayList result) { + if (root == null) { + return; + } + result.add(root.val); // 注意这一句 + preOrder(root.left, result); + preOrder(root.right, result); + } +} +// 中序遍历·递归·LC94_二叉树的中序遍历 +class Solution { + public List inorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + inorder(root, res); + return res; + } + + void inorder(TreeNode root, List list) { + if (root == null) { + return; + } + inorder(root.left, list); + list.add(root.val); // 注意这一句 + inorder(root.right, list); + } +} +// 后序遍历·递归·LC145_二叉树的后序遍历 +class Solution { + public List postorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + postorder(root, res); + return res; + } + + void postorder(TreeNode root, List list) { + if (root == null) { + return; + } + postorder(root.left, list); + postorder(root.right, list); + list.add(root.val); // 注意这一句 + } +} +``` 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: 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 @@ ![编程风格](https://img-blog.csdnimg.cn/20201119173039835.png) -## 水平留白(代码空格) +### 水平留白(代码空格) 经常看到有的同学的代码都堆在一起,看起来都费劲,或者是有的间隔有空格,有的没有空格,很不统一,有的同学甚至为了让代码精简,把所有空格都省略掉了。 @@ -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 7881adf3..5f89241b 100644 --- a/problems/剑指Offer05.替换空格.md +++ b/problems/剑指Offer05.替换空格.md @@ -129,7 +129,26 @@ for (int i = 0; i < a.size(); i++) { Java: - +```Java +//使用一个新的对象,复制 str,复制的过程对其判断,是空格则替换,否则直接复制,类似于数组复制 +public static String replaceSpace(StringBuffer str) { + if (str == null) { + return null; + } + //选用 StringBuilder 单线程使用,比较快,选不选都行 + StringBuilder sb = new StringBuilder(); + //使用 sb 逐个复制 str ,碰到空格则替换,否则直接复制 + for (int i = 0; i < str.length(); i++) { + //str.charAt(i) 为 char 类型,为了比较需要将其转为和 " " 相同的字符串类型 + if (" ".equals(String.valueOf(str.charAt(i)))){ + sb.append("%20"); + } else { + sb.append(str.charAt(i)); + } + } + return sb.toString(); + } +``` Python: diff --git a/problems/回溯算法理论基础.md b/problems/回溯算法理论基础.md index 3aba34db..8bfd101c 100644 --- a/problems/回溯算法理论基础.md +++ b/problems/回溯算法理论基础.md @@ -163,10 +163,6 @@ void backtracking(参数) { -![](https://img-blog.csdnimg.cn/20210416110157800.png) - - - ## 其他语言版本 diff --git a/problems/数组总结篇.md b/problems/数组总结篇.md index 7c4c0fed..d8daa866 100644 --- a/problems/数组总结篇.md +++ b/problems/数组总结篇.md @@ -131,9 +131,6 @@ 最后,大家周末愉快! - - - ## 其他语言版本 diff --git a/problems/数组理论基础.md b/problems/数组理论基础.md index 457cd33e..a2c86ac4 100644 --- a/problems/数组理论基础.md +++ b/problems/数组理论基础.md @@ -7,6 +7,7 @@

欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+ ## 数组理论基础 数组是非常基础的数据结构,在面试中,考察数组的题目一般在思维上都不难,主要是考察对代码的掌控能力 @@ -23,6 +24,8 @@ ![算法通关数组](https://code-thinking.cdn.bcebos.com/pics/%E7%AE%97%E6%B3%95%E9%80%9A%E5%85%B3%E6%95%B0%E7%BB%84.png) + + 需要两点注意的是 * **数组下标都是从0开始的。** @@ -34,6 +37,7 @@ ![算法通关数组1](https://code-thinking.cdn.bcebos.com/pics/%E7%AE%97%E6%B3%95%E9%80%9A%E5%85%B3%E6%95%B0%E7%BB%841.png) + 而且大家如果使用C++的话,要注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组。 **数组的元素是不能删的,只能覆盖。** @@ -42,122 +46,77 @@ ![算法通关数组2](https://code-thinking.cdn.bcebos.com/pics/%E7%AE%97%E6%B3%95%E9%80%9A%E5%85%B3%E6%95%B0%E7%BB%842.png) + **那么二维数组在内存的空间地址是连续的么?** -不同编程语言的内存管理是不一样的,以C++为例,在C++中二维数组是连续分布的,如图: +不同编程语言的内存管理是不一样的,以C++为例,在C++中二维数组是连续分布的。 + +我们来做一个实验,C++测试代码如下: + +```C++ +void test_arr() { + int array[2][3] = { + {0, 1, 2}, + {3, 4, 5} + }; + cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << endl; + cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2] << endl; +} + +int main() { + test_arr(); +} + +``` + +测试地址为 + +``` +0x7ffee4065820 0x7ffee4065824 0x7ffee4065828 +0x7ffee406582c 0x7ffee4065830 0x7ffee4065834 +``` + +注意地址为16进制,可以看出二维数组地址是连续一条线的。 + +一些录友可能看不懂内存地址,我就简单介绍一下, 0x7ffee4065820 与 0x7ffee4065824 差了一个4,就是4个字节,因为这是一个int型的数组,所以两个相信数组元素地址差4个字节。 + +0x7ffee4065828 与 0x7ffee406582c 也是差了4个字节,在16进制里8 + 4 = c,c就是12。 + +如图: ![数组内存](https://img-blog.csdnimg.cn/20210310150641186.png) -Java的二维数组可能是如下排列的方式: +**所以可以看出在C++中二维数组在地址空间上是连续的**。 + +像Java是没有指针的,同时也不对程序员暴漏其元素的地址,寻址操作完全交给虚拟机。 + +所以看不到每个元素的地址情况,这里我以Java为例,也做一个实验。 + +```Java +public static void test_arr() { + int[][] arr = {{1, 2, 3}, {3, 4, 5}, {6, 7, 8}, {9,9,9}}; + System.out.println(arr[0]); + System.out.println(arr[1]); + System.out.println(arr[2]); + System.out.println(arr[3]); +} +``` +输出的地址为: + +``` +[I@7852e922 +[I@4e25154f +[I@70dea4e +[I@5c647e05 +``` + +这里的数值也是16进制,这不是真正的地址,而是经过处理过后的数值了,我们也可以看出,二维数组的每一行头结点的地址是没有规则的,更谈不上连续。 + +所以Java的二维数组可能是如下排列的方式: ![算法通关数组3](https://img-blog.csdnimg.cn/20201214111631844.png) -我们在[数组过于简单,但你该了解这些!](https://mp.weixin.qq.com/s/c2KABb-Qgg66HrGf8z-8Og)分别作了实验 - -## 数组的经典题目 - -在面试中,数组是必考的基础数据结构。 - -其实数据的题目在思想上一般比较简单的,但是如果想高效,并不容易。 - -我们之前一共讲解了四道经典数组题目,每一道题目都代表一个类型,一种思想。 - -### 二分法 - -[704.二分查找](https://mp.weixin.qq.com/s/4X-8VRgnYRGd5LYGZ33m4w) - -在这道题目中我们讲到了**循环不变量原则**,只有在循环中坚持对区间的定义,才能清楚的把握循环中的各种细节。 - -**二分法是算法面试中的常考题,建议通过这道题目,锻炼自己手撕二分的能力**。 - -相关题目: - -* 35.搜索插入位置 -* 34.在排序数组中查找元素的第一个和最后一个位置 -* 69.x 的平方根 -* 367.有效的完全平方数 - -### 双指针法 - -[27. 移除元素](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww) - -双指针法(快慢指针法):**通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。** - -暴力解法时间复杂度:O(n^2) -双指针时间复杂度:O(n) - -这道题目迷惑了不少同学,纠结于数组中的元素为什么不能删除,主要是因为一下两点: - -* 数组在内存中是连续的地址空间,不能释放单一元素,如果要释放,就是全释放(程序运行结束,回收内存栈空间)。 -* C++中vector和array的区别一定要弄清楚,vector的底层实现是array,所以vector展现出友好的一些都是因为经过包装了。 - -双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组和链表操作的面试题,都使用双指针法。 - -相关题目: - -* 26.删除排序数组中的重复项 -* 283.移动零 -* 844.比较含退格的字符串 -* 977.有序数组的平方 - -### 滑动窗口 - -[209.长度最小的子数组](https://mp.weixin.qq.com/s/ewCRwVw0h0v4uJacYO7htQ) - -本题介绍了数组操作中的另一个重要思想:滑动窗口。 - -暴力解法时间复杂度:O(n^2) -滑动窗口时间复杂度:O(n) - -本题中,主要要理解滑动窗口如何移动 窗口起始位置,达到动态更新窗口大小的,从而得出长度最小的符合条件的长度。 - -**滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)的暴力解法降为O(n)。** - -如果没有接触过这一类的方法,很难想到类似的解题思路,滑动窗口方法还是很巧妙的。 - -相关题目: - -* 904.水果成篮 -* 76.最小覆盖子串 - -### 模拟行为 - -[59.螺旋矩阵II](https://mp.weixin.qq.com/s/Hn6-mlCPvKAdWbiFfQyaaw) - -模拟类的题目在数组中很常见,不涉及到什么算法,就是单纯的模拟,十分考察大家对代码的掌控能力。 - -在这道题目中,我们再一次介绍到了**循环不变量原则**,其实这也是写程序中的重要原则。 - -相信大家又遇到过这种情况: 感觉题目的边界调节超多,一波接着一波的判断,找边界,踩了东墙补西墙,好不容易运行通过了,代码写的十分冗余,毫无章法,其实**真正解决题目的代码都是简洁的,或者有原则性的**,大家可以在这道题目中体会到这一点。 - -相关题目: - -* 54.螺旋矩阵 -* 剑指Offer 29.顺时针打印矩阵 - -## 总结 - -从二分法到双指针,从滑动窗口到螺旋矩阵,相信如果大家真的认真做了「代码随想录」每日推荐的题目,定会有所收获。 - -**每道题目后面都有相关练习题,也别忘了去做做!** - -数组专题中讲解和相关题目已经有16道了,就不介绍太过题目了,因为数组是非常基础的数据结构后面很多专题还会用到数组,所以后面的题目依然会会间接练习数组的。 - - - -![](https://img-blog.csdnimg.cn/20210416110157800.png) - -## 其他语言版本 - - -Java: - - -Python: - - -Go: - +这里面试中数组相关的理论知识就介绍完了。 diff --git a/problems/面试题02.07.链表相交.md b/problems/面试题02.07.链表相交.md new file mode 100644 index 00000000..493438d7 --- /dev/null +++ b/problems/面试题02.07.链表相交.md @@ -0,0 +1,165 @@ + +

+ + + + +

+

欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+ +## 面试题 02.07. 链表相交 + +题目链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists-lcci/ + +给定两个(单向)链表,判定它们是否相交并返回交点。请注意相交的定义基于节点的引用,而不是基于节点的值。换句话说,如果一个链表的第k个节点与另一个链表的第j个节点是同一节点(引用完全相同),则这两个链表相交。 + +示例 1: + +输入:listA = [4,1,8,4,5], listB = [5,0,1,8,4,5] + +输出:Reference of the node with value = 8 + +输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。 + + +## 思路 + +本来很简洁明了的一道题,让题目描述搞的云里雾里的。 + +简单来说,就是求两个链表交点节点的**指针**。 这里同学们要注意,交点不是数值相等,而是指针相等。 + +为了方便举例,假设节点元素数值相等,则节点指针相等。 + +看如下两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点: + +![面试题02.07.链表相交_1](https://code-thinking.cdn.bcebos.com/pics/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4_1.png)v + +我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,如图: + +![面试题02.07.链表相交_2](https://code-thinking.cdn.bcebos.com/pics/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4_2.png) + +此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到焦点。 + +否则循环退出返回空指针。 + +C++代码如下: + +```C++ +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) { + swap (lenA, lenB); + swap (curA, curB); + } + // 求长度差 + int gap = lenA - lenB; + // 让curA和curB在同一起点上(末尾位置对齐) + while (gap--) { + curA = curA->next; + } + // 遍历curA 和 curB,遇到相同则直接返回 + while (curA != NULL) { + if (curA == curB) { + return curA; + } + curA = curA->next; + curB = curB->next; + } + return NULL; + } +}; +``` + +* 时间复杂度:$O(n + m)$ +* 空间复杂度:$O(1)$ + +## 其他语言版本 + + +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: + + + + +----------------------- +* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) +* B站视频:[代码随想录](https://space.bilibili.com/525438321) +* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) +