diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 7794435b..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/problems/0001.两数之和.md b/problems/0001.两数之和.md index 22b2e7eb..9571a773 100644 --- a/problems/0001.两数之和.md +++ b/problems/0001.两数之和.md @@ -118,6 +118,18 @@ class Solution: return [records[target - val], idx] # 如果存在就返回字典记录索引和当前索引 ``` +Python (v2): + +```python +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + rec = {} + for i in range(len(nums)): + rest = target - nums[i] + # Use get to get the index of the data, making use of one of the dictionary properties. + if rec.get(rest, None) is not None: return [rec[rest], i] + rec[nums[i]] = i +``` Go: diff --git a/problems/0005.最长回文子串.md b/problems/0005.最长回文子串.md index 99458825..8b3af3bb 100644 --- a/problems/0005.最长回文子串.md +++ b/problems/0005.最长回文子串.md @@ -260,7 +260,26 @@ public: # 其他语言版本 -## Java +Java: + +```java +public int[] twoSum(int[] nums, int target) { + int[] res = new int[2]; + if(nums == null || nums.length == 0){ + return res; + } + Map map = new HashMap<>(); + for(int i = 0; i < nums.length; i++){ + int temp = target - nums[i]; + if(map.containsKey(temp)){ + res[1] = i; + res[0] = map.get(temp); + } + map.put(nums[i], i); + } + return res; +} +``` ```java // 双指针 中心扩散法 @@ -291,7 +310,7 @@ class Solution { } ``` -## Python +Python: ```python class Solution: @@ -312,7 +331,8 @@ class Solution: return s[left:right + 1] ``` -> 双指针法: +双指针: + ```python class Solution: def longestPalindrome(self, s: str) -> str: @@ -340,13 +360,13 @@ class Solution: return s[start:end] ``` -## Go +Go: ```go ``` -## JavaScript +JavaScript: ```js //动态规划解法 @@ -462,8 +482,9 @@ var longestPalindrome = function(s) { }; ``` -## C -动态规划: +C: + +动态规划: ```c //初始化dp数组,全部初始为false bool **initDP(int strLen) { @@ -513,7 +534,7 @@ char * longestPalindrome(char * s){ } ``` -双指针: +双指针: ```c int left, maxLength; void extend(char *str, int i, int j, int size) { diff --git a/problems/0015.三数之和.md b/problems/0015.三数之和.md index 9b59e66d..bfde6b35 100644 --- a/problems/0015.三数之和.md +++ b/problems/0015.三数之和.md @@ -247,7 +247,34 @@ class Solution: right -= 1 return ans ``` +Python (v2): + +```python +class Solution: + def threeSum(self, nums: List[int]) -> List[List[int]]: + if len(nums) < 3: return [] + nums, res = sorted(nums), [] + for i in range(len(nums) - 2): + cur, l, r = nums[i], i + 1, len(nums) - 1 + if res != [] and res[-1][0] == cur: continue # Drop duplicates for the first time. + + while l < r: + if cur + nums[l] + nums[r] == 0: + res.append([cur, nums[l], nums[r]]) + # Drop duplicates for the second time in interation of l & r. Only used when target situation occurs, because that is the reason for dropping duplicates. + while l < r - 1 and nums[l] == nums[l + 1]: + l += 1 + while r > l + 1 and nums[r] == nums[r - 1]: + r -= 1 + if cur + nums[l] + nums[r] > 0: + r -= 1 + else: + l += 1 + return res +``` + Go: + ```Go func threeSum(nums []int)[][]int{ sort.Ints(nums) diff --git a/problems/0018.四数之和.md b/problems/0018.四数之和.md index c6c55d50..7304254e 100644 --- a/problems/0018.四数之和.md +++ b/problems/0018.四数之和.md @@ -216,6 +216,7 @@ class Solution(object): # good thing about using python is you can use set to drop duplicates. ans = set() + # ans = [] # save results by list() for i in range(len(nums)): for j in range(i + 1, len(nums)): for k in range(j + 1, len(nums)): @@ -224,10 +225,16 @@ class Solution(object): # make sure no duplicates. count = (nums[i] == val) + (nums[j] == val) + (nums[k] == val) if hashmap[val] > count: - ans.add(tuple(sorted([nums[i], nums[j], nums[k], val]))) - else: - continue - return ans + ans_tmp = tuple(sorted([nums[i], nums[j], nums[k], val])) + ans.add(ans_tmp) + # Avoiding duplication in list manner but it cause time complexity increases + # if ans_tmp not in ans: + # ans.append(ans_tmp) + else: + continue + return list(ans) + # if used list() to save results, just + # return ans ``` diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md index bf1fd5e1..ce75e0d7 100644 --- a/problems/0024.两两交换链表中的节点.md +++ b/problems/0024.两两交换链表中的节点.md @@ -254,32 +254,20 @@ TypeScript: ```typescript function swapPairs(head: ListNode | null): ListNode | null { - /** - * 初始状态: - * curNode -> node1 -> node2 -> tmepNode - * 转换过程: - * curNode -> node2 - * curNode -> node2 -> node1 - * curNode -> node2 -> node1 -> tempNode - * curNode = node1 - */ - let retNode: ListNode | null = new ListNode(0, head), - curNode: ListNode | null = retNode, - node1: ListNode | null = null, - node2: ListNode | null = null, - tempNode: ListNode | null = null; - - while (curNode && curNode.next && curNode.next.next) { - node1 = curNode.next; - node2 = curNode.next.next; - tempNode = node2.next; - curNode.next = node2; - node2.next = node1; - node1.next = tempNode; - curNode = node1; - } - return retNode.next; -}; + const dummyHead: ListNode = new ListNode(0, head); + let cur: ListNode = dummyHead; + while(cur.next !== null && cur.next.next !== null) { + const tem: ListNode = cur.next; + const tem1: ListNode = cur.next.next.next; + + cur.next = cur.next.next; // step 1 + cur.next.next = tem; // step 2 + cur.next.next.next = tem1; // step 3 + + cur = cur.next.next; + } + return dummyHead.next; +} ``` Kotlin: diff --git a/problems/0042.接雨水.md b/problems/0042.接雨水.md index 55f80a54..75152eb7 100644 --- a/problems/0042.接雨水.md +++ b/problems/0042.接雨水.md @@ -365,7 +365,7 @@ public: ## 其他语言版本 -Java: +### Java: 双指针法 ```java @@ -468,7 +468,7 @@ class Solution { } ``` -Python: +### Python: 双指针法 ```python3 @@ -575,7 +575,7 @@ class Solution: ``` -Go: +### Go ```go func trap(height []int) int { @@ -642,7 +642,7 @@ func min(a,b int)int{ -JavaScript: +### JavaScript: ```javascript //双指针 @@ -744,7 +744,7 @@ var trap = function(height) { }; ``` -C: +### C: 一种更简便的双指针方法: diff --git a/problems/0053.最大子序和(动态规划).md b/problems/0053.最大子序和(动态规划).md index 37de9bbe..703e1dd6 100644 --- a/problems/0053.最大子序和(动态规划).md +++ b/problems/0053.最大子序和(动态规划).md @@ -174,6 +174,7 @@ const maxSubArray = nums => { // 数组长度,dp初始化 const len = nums.length; let dp = new Array(len).fill(0); + dp[0] = nums[0]; // 最大值初始化为dp[0] let max = dp[0]; for (let i = 1; i < len; i++) { diff --git a/problems/0059.螺旋矩阵II.md b/problems/0059.螺旋矩阵II.md index a6e79032..5c679982 100644 --- a/problems/0059.螺旋矩阵II.md +++ b/problems/0059.螺旋矩阵II.md @@ -192,47 +192,31 @@ python3: ```python class Solution: - def generateMatrix(self, n: int) -> List[List[int]]: - # 初始化要填充的正方形 - matrix = [[0] * n for _ in range(n)] + nums = [[0] * n for _ in range(n)] + startx, starty = 0, 0 # 起始点 + loop, mid = n // 2, n // 2 # 迭代次数、n为奇数时,矩阵的中心点 + count = 1 # 计数 - left, right, up, down = 0, n - 1, 0, n - 1 - number = 1 # 要填充的数字 + for offset in range(1, loop + 1) : # 每循环一层偏移量加1,偏移量从1开始 + for i in range(starty, n - offset) : # 从左至右,左闭右开 + nums[startx][i] = count + count += 1 + for i in range(startx, n - offset) : # 从上至下 + nums[i][n - offset] = count + count += 1 + for i in range(n - offset, starty, -1) : # 从右至左 + nums[n - offset][i] = count + count += 1 + for i in range(n - offset, startx, -1) : # 从下至上 + nums[i][starty] = count + count += 1 + startx += 1 # 更新起始点 + starty += 1 - while left < right and up < down: - - # 从左到右填充上边 - for x in range(left, right): - matrix[up][x] = number - number += 1 - - # 从上到下填充右边 - for y in range(up, down): - matrix[y][right] = number - number += 1 - - # 从右到左填充下边 - for x in range(right, left, -1): - matrix[down][x] = number - number += 1 - - # 从下到上填充左边 - for y in range(down, up, -1): - matrix[y][left] = number - number += 1 - - # 缩小要填充的范围 - left += 1 - right -= 1 - up += 1 - down -= 1 - - # 如果阶数为奇数,额外填充一次中心 - if n % 2: - matrix[n // 2][n // 2] = number - - return matrix + if n % 2 != 0 : # n为奇数时,填充中心点 + nums[mid][mid] = count + return nums ``` javaScript diff --git a/problems/0063.不同路径II.md b/problems/0063.不同路径II.md index 8e82007e..86c42150 100644 --- a/problems/0063.不同路径II.md +++ b/problems/0063.不同路径II.md @@ -155,6 +155,39 @@ public: * 时间复杂度:$O(n × m)$,n、m 分别为obstacleGrid 长度和宽度 * 空间复杂度:$O(n × m)$ + +同样我们给出空间优化版本: +```CPP +class Solution { +public: + int uniquePathsWithObstacles(vector>& obstacleGrid) { + if (obstacleGrid[0][0] == 1) + return 0; + vector dp(obstacleGrid[0].size()); + for (int j = 0; j < dp.size(); ++j) + if (obstacleGrid[0][j] == 1) + dp[j] = 0; + else if (j == 0) + dp[j] = 1; + else + dp[j] = dp[j-1]; + + for (int i = 1; i < obstacleGrid.size(); ++i) + for (int j = 0; j < dp.size(); ++j){ + if (obstacleGrid[i][j] == 1) + dp[j] = 0; + else if (j != 0) + dp[j] = dp[j] + dp[j-1]; + } + return dp.back(); + } +}; +``` + +* 时间复杂度:$O(n × m)$,n、m 分别为obstacleGrid 长度和宽度 +* 空间复杂度:$O(m)$ + + ## 总结 本题是[62.不同路径](https://programmercarl.com/0062.不同路径.html)的障碍版,整体思路大体一致。 diff --git a/problems/0070.爬楼梯.md b/problems/0070.爬楼梯.md index 7f47a991..da19ea0e 100644 --- a/problems/0070.爬楼梯.md +++ b/problems/0070.爬楼梯.md @@ -256,16 +256,28 @@ public int climbStairs(int n) { ### Python ```python +# 空间复杂度为O(n)版本 class Solution: def climbStairs(self, n: int) -> int: - # dp[i]表示爬到第i级楼梯的种数, (1, 2) (2, 1)是两种不同的类型 - dp = [0] * (n + 1) - dp[0] = 1 - for i in range(n+1): - for j in range(1, 3): - if i>=j: - dp[i] += dp[i-j] - return dp[-1] + # dp[i] 为第 i 阶楼梯有多少种方法爬到楼顶 + dp=[0]*(n+1) + dp[0]=1 + dp[1]=1 + for i in range(2,n+1): + dp[i]=dp[i-1]+dp[i-2] + return dp[n] + +# 空间复杂度为O(1)版本 +class Solution: + def climbStairs(self, n: int) -> int: + dp=[0]*(n+1) + dp[0]=1 + dp[1]=1 + for i in range(2,n+1): + tmp=dp[0]+dp[1] + dp[0]=dp[1] + dp[1]=tmp + return dp[1] ``` ### Go diff --git a/problems/0077.组合.md b/problems/0077.组合.md index 2bd7a287..e582daf6 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -423,8 +423,8 @@ class Solution: if len(path) == k: res.append(path[:]) return - for i in range(startIndex,n - (k - len(path)) + 2): #优化的地方 - path.append(i) #处理节点 + for i in range(startIndex,n-(k-len(path))+2): #优化的地方 + path.append(i) #处理节点 backtrack(n,k,i+1) #递归 path.pop() #回溯,撤销处理的节点 backtrack(n,k,1) diff --git a/problems/0098.验证二叉搜索树.md b/problems/0098.验证二叉搜索树.md index 4ed29619..c0f3e039 100644 --- a/problems/0098.验证二叉搜索树.md +++ b/problems/0098.验证二叉搜索树.md @@ -526,6 +526,48 @@ var isValidBST = function (root) { }; ``` +## TypeScript + +> 辅助数组解决: + +```typescript +function isValidBST(root: TreeNode | null): boolean { + const traversalArr: number[] = []; + function inorderTraverse(root: TreeNode | null): void { + if (root === null) return; + inorderTraverse(root.left); + traversalArr.push(root.val); + inorderTraverse(root.right); + } + inorderTraverse(root); + for (let i = 0, length = traversalArr.length; i < length - 1; i++) { + if (traversalArr[i] >= traversalArr[i + 1]) return false; + } + return true; +}; +``` + +> 递归中解决: + +```typescript +function isValidBST(root: TreeNode | null): boolean { + let maxVal = -Infinity; + function inorderTraverse(root: TreeNode | null): boolean { + if (root === null) return true; + let leftValid: boolean = inorderTraverse(root.left); + if (!leftValid) return false; + if (maxVal < root.val) { + maxVal = root.val + } else { + return false; + } + let rightValid: boolean = inorderTraverse(root.right); + return leftValid && rightValid; + } + return inorderTraverse(root); +}; +``` + ----------------------- diff --git a/problems/0101.对称二叉树.md b/problems/0101.对称二叉树.md index e4e232c8..0007b4d4 100644 --- a/problems/0101.对称二叉树.md +++ b/problems/0101.对称二叉树.md @@ -437,6 +437,41 @@ class Solution: return True ``` +层序遍历 + +```python +class Solution: + def isSymmetric(self, root: TreeNode) -> bool: + if not root: return True + que, cnt = [[root.left, root.right]], 1 + while que: + nodes, tmp, sign = que.pop(), [], False + for node in nodes: + if not node: + tmp.append(None) + tmp.append(None) + else: + if node.left: + tmp.append(node.left) + sign = True + else: + tmp.append(None) + if node.right: + tmp.append(node.right) + sign = True + else: + tmp.append(None) + p1, p2 = 0, len(nodes) - 1 + while p1 < p2: + if (not nodes[p1] and nodes[p2]) or (nodes[p1] and not nodes[p2]): return False + elif nodes[p1] and nodes[p2] and nodes[p1].val != nodes[p2].val: return False + p1 += 1 + p2 -= 1 + if sign: que.append(tmp) + cnt += 1 + return True +``` + ## Go ```go diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index 74485848..4951631c 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -273,32 +273,29 @@ function levelOrder(root: TreeNode | null): number[][] { }; ``` -Swift: +Swift: ```swift func levelOrder(_ root: TreeNode?) -> [[Int]] { - var res = [[Int]]() - guard let root = root else { - return res - } - var queue = [TreeNode]() - queue.append(root) + var result = [[Int]]() + guard let root = root else { return result } + // 表示一层 + var queue = [root] while !queue.isEmpty { - let size = queue.count - var sub = [Int]() - for _ in 0 ..< size { + let count = queue.count + var subarray = [Int]() + for _ in 0 ..< count { + // 当前层 let node = queue.removeFirst() - sub.append(node.val) - if let left = node.left { - queue.append(left) - } - if let right = node.right { - queue.append(right) - } + subarray.append(node.val) + // 下一层 + if let node = node.left { queue.append(node) } + if let node = node.right { queue.append(node) } } - res.append(sub) + result.append(subarray) } - return res + + return result } ``` @@ -505,30 +502,29 @@ function levelOrderBottom(root: TreeNode | null): number[][] { }; ``` -Swift: +Swift: ```swift func levelOrderBottom(_ root: TreeNode?) -> [[Int]] { - var res = [[Int]]() - guard let root = root else { - return res - } - var queue: [TreeNode] = [root] + // 表示一层 + var queue = [TreeNode]() + if let node = root { queue.append(node) } + var result = [[Int]]() while !queue.isEmpty { - var sub = [Int]() - for _ in 0 ..< queue.count { + let count = queue.count + var subarray = [Int]() + for _ in 0 ..< count { + // 当前层 let node = queue.removeFirst() - sub.append(node.val) - if let left = node.left { - queue.append(left) - } - if let right = node.right { - queue.append(right) - } + subarray.append(node.val) + // 下一层 + if let node = node.left { queue.append(node) } + if let node = node.right { queue.append(node)} } - res.insert(sub, at: 0) + result.append(subarray) } - return res + + return result.reversed() } ``` @@ -729,37 +725,31 @@ function rightSideView(root: TreeNode | null): number[] { }; ``` -Swift: +Swift: ```swift func rightSideView(_ root: TreeNode?) -> [Int] { - var res = [Int]() - guard let root = root else { - return res - } + // 表示一层 var queue = [TreeNode]() - queue.append(root) + if let node = root { queue.append(node) } + var result = [Int]() while !queue.isEmpty { - let size = queue.count - for i in 0 ..< size { + let count = queue.count + for i in 0 ..< count { + // 当前层 let node = queue.removeFirst() - if i == size - 1 { - // 保存 每层最后一个元素 - res.append(node.val) - } - if let left = node.left { - queue.append(left) - } - if let right = node.right { - queue.append(right) - } + if i == count - 1 { result.append(node.val) } + + // 下一层 + if let node = node.left { queue.append(node) } + if let node = node.right { queue.append(node) } } } - return res + + return result } ``` - # 637.二叉树的层平均值 [力扣题目链接](https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/) @@ -965,32 +955,30 @@ function averageOfLevels(root: TreeNode | null): number[] { }; ``` -Swift: +Swift: ```swift func averageOfLevels(_ root: TreeNode?) -> [Double] { - var res = [Double]() - guard let root = root else { - return res - } + // 表示一层 var queue = [TreeNode]() - queue.append(root) + if let node = root { queue.append(node) } + var result = [Double]() while !queue.isEmpty { - let size = queue.count + let count = queue.count var sum = 0 - for _ in 0 ..< size { + for _ in 0 ..< count { + // 当前层 let node = queue.removeFirst() sum += node.val - if let left = node.left { - queue.append(left) - } - if let right = node.right { - queue.append(right) - } + + // 下一层 + if let node = node.left { queue.append(node) } + if let node = node.right { queue.append(node) } } - res.append(Double(sum) / Double(size)) + result.append(Double(sum) / Double(count)) } - return res + + return result } ``` @@ -1212,29 +1200,28 @@ function levelOrder(root: Node | null): number[][] { }; ``` -Swift: +Swift: ```swift func levelOrder(_ root: Node?) -> [[Int]] { - var res = [[Int]]() - guard let root = root else { - return res - } + // 表示一层 var queue = [Node]() - queue.append(root) + if let node = root { queue.append(node) } + var result = [[Int]]() while !queue.isEmpty { - let size = queue.count - var sub = [Int]() - for _ in 0 ..< size { + let count = queue.count + var subarray = [Int]() + for _ in 0 ..< count { + // 当前层 let node = queue.removeFirst() - sub.append(node.val) - for childNode in node.children { - queue.append(childNode) - } + subarray.append(node.val) + // 下一层 + for node in node.children { queue.append(node) } } - res.append(sub) + result.append(subarray) } - return res + + return result } ``` @@ -1419,34 +1406,30 @@ function largestValues(root: TreeNode | null): number[] { }; ``` -Swift: +Swift: ```swift func largestValues(_ root: TreeNode?) -> [Int] { - var res = [Int]() - guard let root = root else { - return res - } + // 表示一层 var queue = [TreeNode]() - queue.append(root) + if let node = root { queue.append(node) } + var result = [Int]() while !queue.isEmpty { - let size = queue.count - var max: Int = Int.min - for _ in 0 ..< size { + let count = queue.count + var max = queue[0].val + for _ in 0 ..< count { + // 当前层 let node = queue.removeFirst() - if node.val > max { - max = node.val - } - if let left = node.left { - queue.append(left) - } - if let right = node.right { - queue.append(right) - } + if node.val > max { max = node.val } + + // 下一层 + if let node = node.left { queue.append(node) } + if let node = node.right { queue.append(node) } } - res.append(max) + result.append(max) } - return res + + return result } ``` @@ -1456,7 +1439,7 @@ func largestValues(_ root: TreeNode?) -> [Int] { 给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下: -``` +```cpp struct Node { int val; Node *left; @@ -1677,33 +1660,34 @@ func connect(root *Node) *Node { } ``` -Swift: +Swift: + ```swift func connect(_ root: Node?) -> Node? { - guard let root = root else { - return nil - } + // 表示一层 var queue = [Node]() - queue.append(root) + if let node = root { queue.append(node) } while !queue.isEmpty { - let size = queue.count - var preNode: Node? - for i in 0 ..< size { - let node = queue.removeFirst() + let count = queue.count + var current, previous: Node! + for i in 0 ..< count { + // 当前层 if i == 0 { - preNode = node + previous = queue.removeFirst() + current = previous } else { - preNode?.next = node - preNode = node - } - if let left = node.left { - queue.append(left) - } - if let right = node.right { - queue.append(right) + current = queue.removeFirst() + previous.next = current + previous = current } + + // 下一层 + if let node = current.left { queue.append(node) } + if let node = current.right { queue.append(node) } } + previous.next = nil } + return root } ``` @@ -1927,34 +1911,34 @@ func connect(root *Node) *Node { return root } ``` - Swift: + ```swift func connect(_ root: Node?) -> Node? { - guard let root = root else { - return nil - } + // 表示一层 var queue = [Node]() - queue.append(root) + if let node = root { queue.append(node) } while !queue.isEmpty { - let size = queue.count - var preNode: Node? - for i in 0 ..< size { - let node = queue.removeFirst() + let count = queue.count + var current, previous: Node! + for i in 0 ..< count { + // 当前层 if i == 0 { - preNode = node + previous = queue.removeFirst() + current = previous } else { - preNode?.next = node - preNode = node - } - if let left = node.left { - queue.append(left) - } - if let right = node.right { - queue.append(right) + current = queue.removeFirst() + previous.next = current + previous = current } + + // 下一层 + if let node = current.left { queue.append(node) } + if let node = current.right { queue.append(node) } } + previous.next = nil } + return root } ``` @@ -2151,29 +2135,28 @@ function maxDepth(root: TreeNode | null): number { }; ``` -Swift: +Swift: ```swift func maxDepth(_ root: TreeNode?) -> Int { - guard let root = root else { - return 0 - } + guard root != nil else { return 0 } + var depth = 0 var queue = [TreeNode]() - queue.append(root) - var res: Int = 0 + queue.append(root!) while !queue.isEmpty { - for _ in 0 ..< queue.count { + let count = queue.count + depth += 1 + for _ in 0 ..< count { + // 当前层 let node = queue.removeFirst() - if let left = node.left { - queue.append(left) - } - if let right = node.right { - queue.append(right) - } + + // 下一层 + if let node = node.left { queue.append(node) } + if let node = node.right { queue.append(node) } } - res += 1 } - return res + + return depth } ``` @@ -2374,28 +2357,25 @@ Swift: ```swift func minDepth(_ root: TreeNode?) -> Int { - guard let root = root else { - return 0 - } - var res = 0 - var queue = [TreeNode]() - queue.append(root) + guard root != nil else { return 0 } + var depth = 0 + var queue = [root!] while !queue.isEmpty { - res += 1 - for _ in 0 ..< queue.count { + let count = queue.count + depth += 1 + for _ in 0 ..< count { + // 当前层 let node = queue.removeFirst() - if node.left == nil && node.right == nil { - return res - } - if let left = node.left { - queue.append(left) - } - if let right = node.right { - queue.append(right) + if node.left == nil, node.right == nil { // 遇到叶子结点则返回 + return depth } + + // 下一层 + if let node = node.left { queue.append(node) } + if let node = node.right { queue.append(node) } } } - return res + return depth } ``` diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index 40d75983..496de431 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -89,9 +89,9 @@ TreeNode* traversal (vector& inorder, vector& postorder) { **难点大家应该发现了,就是如何切割,以及边界值找不好很容易乱套。** -此时应该注意确定切割的标准,是左闭右开,还有左开又闭,还是左闭又闭,这个就是不变量,要在递归中保持这个不变量。 +此时应该注意确定切割的标准,是左闭右开,还有左开右闭,还是左闭右闭,这个就是不变量,要在递归中保持这个不变量。 -**在切割的过程中会产生四个区间,把握不好不变量的话,一会左闭右开,一会左闭又闭,必然乱套!** +**在切割的过程中会产生四个区间,把握不好不变量的话,一会左闭右开,一会左闭右闭,必然乱套!** 我在[数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0035.搜索插入位置.html)和[数组:这个循环可以转懵很多人!](https://programmercarl.com/0059.螺旋矩阵II.html)中都强调过循环不变量的重要性,在二分查找以及螺旋矩阵的求解中,坚持循环不变量非常重要,本题也是。 @@ -814,7 +814,114 @@ var buildTree = function(preorder, inorder) { }; ``` +## TypeScript + +> 106.从中序与后序遍历序列构造二叉树 + +**创建新数组:** + +```typescript +function buildTree(inorder: number[], postorder: number[]): TreeNode | null { + if (postorder.length === 0) return null; + const rootVal: number = postorder.pop()!; + const rootValIndex: number = inorder.indexOf(rootVal); + const rootNode: TreeNode = new TreeNode(rootVal); + rootNode.left = buildTree(inorder.slice(0, rootValIndex), postorder.slice(0, rootValIndex)); + rootNode.right = buildTree(inorder.slice(rootValIndex + 1), postorder.slice(rootValIndex)); + return rootNode; +}; +``` + +**使用数组索引:** + +```typescript +function buildTree(inorder: number[], postorder: number[]): TreeNode | null { + function recur( + inorder: number[], postorder: number[], + inBegin: number, inEnd: number, + postBegin: number, postEnd: number + ): TreeNode | null { + if (postBegin === postEnd) return null; + const rootVal: number = postorder[postEnd - 1]!; + const rootValIndex: number = inorder.indexOf(rootVal, inBegin); + const rootNode: TreeNode = new TreeNode(rootVal); + + const leftInorderBegin: number = inBegin; + const leftInorderEnd: number = rootValIndex; + const rightInorderBegin: number = rootValIndex + 1; + const rightInorderEnd: number = inEnd; + + const leftPostorderBegin: number = postBegin; + const leftPostorderEnd: number = postBegin + rootValIndex - inBegin; + const rightPostorderBegin: number = leftPostorderEnd; + const rightPostorderEnd: number = postEnd - 1; + + rootNode.left = recur( + inorder, postorder, + leftInorderBegin, leftInorderEnd, + leftPostorderBegin, leftPostorderEnd + ); + rootNode.right = recur( + inorder, postorder, + rightInorderBegin, rightInorderEnd, + rightPostorderBegin, rightPostorderEnd + ); + return rootNode; + } + return recur(inorder, postorder, 0, inorder.length, 0, inorder.length); +}; +``` + +> 105.从前序与中序遍历序列构造二叉树 + +**新建数组:** + +```typescript +function buildTree(preorder: number[], inorder: number[]): TreeNode | null { + if (preorder.length === 0) return null; + const rootVal: number = preorder[0]; + const rootNode: TreeNode = new TreeNode(rootVal); + const rootValIndex: number = inorder.indexOf(rootVal); + rootNode.left = buildTree(preorder.slice(1, rootValIndex + 1), inorder.slice(0, rootValIndex)); + rootNode.right = buildTree(preorder.slice(rootValIndex + 1), inorder.slice(rootValIndex + 1)); + return rootNode; +}; +``` + +**使用数组索引:** + +```typescript +function buildTree(preorder: number[], inorder: number[]): TreeNode | null { + function recur( + preorder: number[], inorder: number[], + preBegin: number, preEnd: number, + inBegin: number, inEnd: number + ): TreeNode | null { + if (preBegin === preEnd) return null; + const rootVal: number = preorder[preBegin]; + const rootNode: TreeNode = new TreeNode(rootVal); + const rootValIndex: number = inorder.indexOf(rootVal, inBegin); + + const leftPreBegin: number = preBegin + 1; + const leftPreEnd: number = preBegin + rootValIndex - inBegin + 1; + const leftInBegin: number = inBegin; + const leftInEnd: number = rootValIndex; + + const rightPreBegin: number = leftPreEnd; + const rightPreEnd: number = preEnd; + const rightInBegin: number = rootValIndex + 1; + const rightInEnd: number = inEnd; + + rootNode.left = recur(preorder, inorder, leftPreBegin, leftPreEnd, leftInBegin, leftInEnd); + rootNode.right = recur(preorder, inorder, rightPreBegin, rightPreEnd, rightInBegin, rightInEnd); + return rootNode; + }; + return recur(preorder, inorder, 0, preorder.length, 0, inorder.length); +}; +``` + ## C + 106 从中序与后序遍历序列构造二叉树 ```c diff --git a/problems/0116.填充每个节点的下一个右侧节点指针.md b/problems/0116.填充每个节点的下一个右侧节点指针.md index bc3a8c6b..2c443de5 100644 --- a/problems/0116.填充每个节点的下一个右侧节点指针.md +++ b/problems/0116.填充每个节点的下一个右侧节点指针.md @@ -211,9 +211,52 @@ class Solution: return root ``` ## Go - ```go - +// 迭代法 +func connect(root *Node) *Node { + if root == nil { + return root + } + stack := make([]*Node, 0) + stack = append(stack, root) + for len(stack) > 0 { + n := len(stack) // 记录当前层节点个数 + for i := 0; i < n; i++ { + node := stack[0] // 依次弹出节点 + stack = stack[1:] + if i == n - 1 { // 如果是这层最右的节点,next指向nil + node.Next = nil + } else { + node.Next = stack[0] // 如果不是最右的节点,next指向右边的节点 + } + if node.Left != nil { // 如果存在左子节点,放入栈中 + stack = append(stack, node.Left) + } + if node.Right != nil { // 如果存在右子节点,放入栈中 + stack = append(stack, node.Right) + } + } + } + return root +} +``` +```go +// 常量级额外空间,使用next +func connect(root *Node) *Node { + if root == nil { + return root + } + for cur := root; cur.Left != nil; cur = cur.Left { // 遍历每层最左边的节点 + for node := cur; node != nil; node = node.Next { // 当前层从左到右遍历 + node.Left.Next = node.Right // 左子节点next指向右子节点 + if node.Next != nil { //如果node next有值,右子节点指向next节点的左子节点 + node.Right.Next = node.Next.Left + } + + } + } + return root +} ``` ## JavaScript diff --git a/problems/0127.单词接龙.md b/problems/0127.单词接龙.md index fb403a5b..407596c0 100644 --- a/problems/0127.单词接龙.md +++ b/problems/0127.单词接龙.md @@ -9,7 +9,6 @@ [力扣题目链接](https://leetcode-cn.com/problems/word-ladder/) - 字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列: * 序列中第一个单词是 beginWord 。 * 序列中最后一个单词是 endWord 。 diff --git a/problems/0139.单词拆分.md b/problems/0139.单词拆分.md index 1653a81a..3aa5ca0f 100644 --- a/problems/0139.单词拆分.md +++ b/problems/0139.单词拆分.md @@ -89,27 +89,26 @@ class Solution { private: bool backtracking (const string& s, const unordered_set& wordSet, - vector& memory, + vector& memory, int startIndex) { if (startIndex >= s.size()) { return true; } // 如果memory[startIndex]不是初始值了,直接使用memory[startIndex]的结果 - if (memory[startIndex] != -1) return memory[startIndex]; + if (!memory[startIndex]) return memory[startIndex]; for (int i = startIndex; i < s.size(); i++) { string word = s.substr(startIndex, i - startIndex + 1); if (wordSet.find(word) != wordSet.end() && backtracking(s, wordSet, memory, i + 1)) { - memory[startIndex] = 1; // 记录以startIndex开始的子串是可以被拆分的 return true; } } - memory[startIndex] = 0; // 记录以startIndex开始的子串是不可以被拆分的 + memory[startIndex] = false; // 记录以startIndex开始的子串是不可以被拆分的 return false; } public: bool wordBreak(string s, vector& wordDict) { unordered_set wordSet(wordDict.begin(), wordDict.end()); - vector memory(s.size(), -1); // -1 表示初始化状态 + vector memory(s.size(), 1); // -1 表示初始化状态 return backtracking(s, wordSet, memory, 0); } }; @@ -251,30 +250,34 @@ class Solution { // 回溯法+记忆化 class Solution { + private Set set; + private int[] memo; public boolean wordBreak(String s, List wordDict) { - Set wordDictSet = new HashSet(wordDict); - int[] memory = new int[s.length()]; - return backTrack(s, wordDictSet, 0, memory); + memo = new int[s.length()]; + set = new HashSet<>(wordDict); + return backtracking(s, 0); } - - public boolean backTrack(String s, Set wordDictSet, int startIndex, int[] memory) { - // 结束条件 - if (startIndex >= s.length()) { + + public boolean backtracking(String s, int startIndex) { + // System.out.println(startIndex); + if (startIndex == s.length()) { return true; } - if (memory[startIndex] != 0) { - // 此处认为:memory[i] = 1 表示可以拼出i 及以后的字符子串, memory[i] = -1 表示不能 - return memory[startIndex] == 1 ? true : false; + if (memo[startIndex] == -1) { + return false; } - for (int i = startIndex; i < s.length(); ++i) { - // 处理 递归 回溯 循环不变量:[startIndex, i + 1) - String word = s.substring(startIndex, i + 1); - if (wordDictSet.contains(word) && backTrack(s, wordDictSet, i + 1, memory)) { - memory[startIndex] = 1; - return true; + + for (int i = startIndex; i < s.length(); i++) { + String sub = s.substring(startIndex, i + 1); + // 拆分出来的单词无法匹配 + if (!set.contains(sub)) { + continue; } + boolean res = backtracking(s, i + 1); + if (res) return true; } - memory[startIndex] = -1; + // 这里是关键,找遍了startIndex~s.length()也没能完全匹配,标记从startIndex开始不能找到 + memo[startIndex] = -1; return false; } } diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md index ead5fa12..7588cbd6 100644 --- a/problems/0151.翻转字符串里的单词.md +++ b/problems/0151.翻转字符串里的单词.md @@ -438,6 +438,38 @@ class Solution: ``` +```python +class Solution: + def reverseWords(self, s: str) -> str: + # method 1 - Rude but work & efficient method. + s_list = [i for i in s.split(" ") if len(i) > 0] + return " ".join(s_list[::-1]) + + # method 2 - Carlo's idea + def trim_head_tail_space(ss: str): + p = 0 + while p < len(ss) and ss[p] == " ": + p += 1 + return ss[p:] + + # Trim the head and tail space + s = trim_head_tail_space(s) + s = trim_head_tail_space(s[::-1])[::-1] + + pf, ps, s = 0, 0, s[::-1] # Reverse the string. + while pf < len(s): + if s[pf] == " ": + # Will not excede. Because we have clean the tail space. + if s[pf] == s[pf + 1]: + s = s[:pf] + s[pf + 1:] + continue + else: + s = s[:ps] + s[ps: pf][::-1] + s[pf:] + ps, pf = pf + 1, pf + 2 + else: + pf += 1 + return s[:ps] + s[ps:][::-1] # Must do the last step, because the last word is omit though the pointers are on the correct positions, +``` Go: diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md index 4e7bdd34..c34831b7 100644 --- a/problems/0203.移除链表元素.md +++ b/problems/0203.移除链表元素.md @@ -324,7 +324,7 @@ function removeElements(head: ListNode | null, val: number): ListNode | null { head = head.next; } if (head === null) return head; - let pre: ListNode = head, cur: ListNode = head.next; + let pre: ListNode = head, cur: ListNode | null = head.next; // 删除非头部节点 while (cur) { if (cur.val === val) { @@ -342,14 +342,14 @@ function removeElements(head: ListNode | null, val: number): ListNode | null { ```typescript function removeElements(head: ListNode | null, val: number): ListNode | null { - head = new ListNode(0, head); - let pre: ListNode = head, cur: ListNode = head.next; + let dummyHead = new ListNode(0, head); + let pre: ListNode = dummyHead, cur: ListNode | null = dummyHead.next; // 删除非头部节点 while (cur) { if (cur.val === val) { pre.next = cur.next; } else { - pre = pre.next; + pre = cur; } cur = cur.next; } diff --git a/problems/0213.打家劫舍II.md b/problems/0213.打家劫舍II.md index b6c2d080..8e569e46 100644 --- a/problems/0213.打家劫舍II.md +++ b/problems/0213.打家劫舍II.md @@ -123,22 +123,24 @@ Python: ```Python class Solution: def rob(self, nums: List[int]) -> int: - if (n := len(nums)) == 0: - return 0 - if n == 1: - return nums[0] - result1 = self.robRange(nums, 0, n - 2) - result2 = self.robRange(nums, 1, n - 1) - return max(result1 , result2) + #在198入门级的打家劫舍问题上分两种情况考虑 + #一是不偷第一间房,二是不偷最后一间房 + if len(nums)==1:#题目中提示nums.length>=1,所以不需要考虑len(nums)==0的情况 + return nums[0] + val1=self.roblist(nums[1:])#不偷第一间房 + val2=self.roblist(nums[:-1])#不偷最后一间房 + return max(val1,val2) - def robRange(self, nums: List[int], start: int, end: int) -> int: - if end == start: return nums[start] - dp = [0] * len(nums) - dp[start] = nums[start] - dp[start + 1] = max(nums[start], nums[start + 1]) - for i in range(start + 2, end + 1): - dp[i] = max(dp[i -2] + nums[i], dp[i - 1]) - return dp[end] + def robRange(self,nums): + l=len(nums) + dp=[0]*l + dp[0]=nums[0] + for i in range(1,l): + if i==1: + dp[i]=max(dp[i-1],nums[i]) + else: + dp[i]=max(dp[i-1],dp[i-2]+nums[i]) + return dp[-1] ``` javascipt: diff --git a/problems/0226.翻转二叉树.md b/problems/0226.翻转二叉树.md index 8108e7ad..a3ebe24d 100644 --- a/problems/0226.翻转二叉树.md +++ b/problems/0226.翻转二叉树.md @@ -47,8 +47,6 @@ ## 递归法 - - 对于二叉树的递归法的前中后序遍历,已经在[二叉树:前中后序递归遍历](https://programmercarl.com/二叉树的递归遍历.html)详细讲解了。 我们下文以前序遍历为例,通过动画来看一下翻转的过程: @@ -63,7 +61,7 @@ 返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为`TreeNode*`。 -``` +```cpp TreeNode* invertTree(TreeNode* root) ``` @@ -71,7 +69,7 @@ TreeNode* invertTree(TreeNode* root) 当前节点为空的时候,就返回 -``` +```cpp if (root == NULL) return root; ``` @@ -79,7 +77,7 @@ if (root == NULL) return root; 因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。 -``` +```cpp swap(root->left, root->right); invertTree(root->left); invertTree(root->right); @@ -257,7 +255,7 @@ public: ## 其他语言版本 -### Java: +### Java ```Java //DFS递归 @@ -469,8 +467,6 @@ func invertTree(root *TreeNode) *TreeNode { } ``` - - ### JavaScript 使用递归版本的前序遍历 @@ -690,7 +686,7 @@ function invertTree(root: TreeNode | null): TreeNode | null { }; ``` -### C: +### C 递归法 ```c @@ -775,5 +771,54 @@ func invertTree1(_ root: TreeNode?) -> TreeNode? { } ``` +### Swift + +深度优先递归。 + +```swift +func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let node = root else { return root } + swap(&node.left, &node.right) + _ = invertTree(node.left) + _ = invertTree(node.right) + return root +} +``` + +深度优先迭代,子结点顺序不重要,从根结点出发深度遍历即可。 + +```swift +func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let node = root else { return root } + var stack = [node] + while !stack.isEmpty { + guard let node = stack.popLast() else { break } + swap(&node.left, &node.right) + if let node = node.left { stack.append(node) } + if let node = node.right { stack.append(node) } + } + return root +} +``` + +广度优先迭代。 + +```swift +func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let node = root else { return root } + var queue = [node] + while !queue.isEmpty { + let count = queue.count + for _ in 0 ..< count { + let node = queue.removeFirst() + swap(&node.left, &node.right) + if let node = node.left { queue.append(node) } + if let node = node.right { queue.append(node) } + } + } + return root +} +``` + -----------------------
diff --git a/problems/0235.二叉搜索树的最近公共祖先.md b/problems/0235.二叉搜索树的最近公共祖先.md index b9d0a0bf..f7f1427a 100644 --- a/problems/0235.二叉搜索树的最近公共祖先.md +++ b/problems/0235.二叉搜索树的最近公共祖先.md @@ -350,6 +350,39 @@ var lowestCommonAncestor = function(root, p, q) { }; ``` +## TypeScript + +> 递归法: + +```typescript +function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null { + if (root.val > p.val && root.val > q.val) + return lowestCommonAncestor(root.left, p, q); + if (root.val < p.val && root.val < q.val) + return lowestCommonAncestor(root.right, p, q); + return root; +}; +``` + +> 迭代法: + +```typescript +function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null { + while (root !== null) { + 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 { + return root; + }; + }; + return null; +}; +``` + + + -----------------------
diff --git a/problems/0236.二叉树的最近公共祖先.md b/problems/0236.二叉树的最近公共祖先.md index 6213aeaa..69a6d0d6 100644 --- a/problems/0236.二叉树的最近公共祖先.md +++ b/problems/0236.二叉树的最近公共祖先.md @@ -45,9 +45,13 @@ 接下来就看如何判断一个节点是节点q和节点p的公共公共祖先呢。 -**如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。** +**首先最容易想到的一个情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。** -使用后序遍历,回溯的过程,就是从低向上遍历节点,一旦发现如何这个条件的节点,就是最近公共节点了。 +**但是很多人容易忽略一个情况,就是节点本身p(q),它拥有一个子孙节点q(p)。** + +使用后序遍历,回溯的过程,就是从低向上遍历节点,一旦发现满足第一种情况的节点,就是最近公共节点了。 + +**但是如果p或者q本身就是最近公共祖先呢?其实只需要找到一个节点是p或者q的时候,直接返回当前节点,无需继续递归子树。如果接下来的遍历中找到了后继节点满足第一种情况则修改返回值为后继节点,否则,继续返回已找到的节点即可。为什么满足第一种情况的节点一定是p或q的后继节点呢?大家可以仔细思考一下。** 递归三部曲: @@ -325,6 +329,20 @@ var lowestCommonAncestor = function(root, p, q) { }; ``` +## TypeScript + +```typescript +function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null { + if (root === null || root === p || root === q) return root; + const left = lowestCommonAncestor(root.left, p, q); + const right = lowestCommonAncestor(root.right, p, q); + if (left !== null && right !== null) return root; + if (left !== null) return left; + if (right !== null) return right; + return null; +}; +``` + ----------------------- diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md index ed61a30e..dfdd5125 100644 --- a/problems/0300.最长上升子序列.md +++ b/problems/0300.最长上升子序列.md @@ -37,7 +37,7 @@ 1. dp[i]的定义 -**dp[i]表示i之前包括i的最长上升子序列的长度**。 +**dp[i]表示i之前包括i的以nums[i]结尾最长上升子序列的长度** 2. 状态转移方程 diff --git a/problems/0309.最佳买卖股票时机含冷冻期.md b/problems/0309.最佳买卖股票时机含冷冻期.md index 2dc1e874..bb8909cd 100644 --- a/problems/0309.最佳买卖股票时机含冷冻期.md +++ b/problems/0309.最佳买卖股票时机含冷冻期.md @@ -284,6 +284,24 @@ const maxProfit = (prices) => { }; ``` +```javascript +// 一维数组空间优化 +const maxProfit = (prices) => { + const n = prices.length + const dp = new Array(4).fill(0) + dp[0] = -prices[0] + for (let i = 1; i < n; i ++) { + const temp = dp[0] // 缓存上一次的状态 + const temp1 = dp[2] + dp[0] = Math.max(dp[0], Math.max(dp[3] - prices[i], dp[1] - prices[i])) // 持有状态 + dp[1] = Math.max(dp[1], dp[3]) // 今天不操作且不持有股票 + dp[2] = temp + prices[i] // 今天卖出股票 + dp[3] = temp1 // 冷冻期 + } + return Math.max(...dp) +}; +``` + -----------------------
diff --git a/problems/0337.打家劫舍III.md b/problems/0337.打家劫舍III.md index ecd31d1b..a4d8f6b2 100644 --- a/problems/0337.打家劫舍III.md +++ b/problems/0337.打家劫舍III.md @@ -216,7 +216,7 @@ public: ## 其他语言版本 -Java: +### Java ```Java class Solution { // 1.递归去偷,超时 @@ -284,7 +284,7 @@ class Solution { } ``` -Python: +### Python > 暴力递归 @@ -367,7 +367,7 @@ class Solution: return (val1, val2) ``` -Go: +### Go 动态规划 @@ -402,7 +402,7 @@ func robTree(cur *TreeNode) []int { } ``` -JavaScript: +### JavaScript > 动态规划 @@ -429,7 +429,7 @@ const rob = root => { }; ``` -Go: +### Go ```go // 打家劫舍Ⅲ 动态规划 // 时间复杂度O(n) 空间复杂度O(logn) diff --git a/problems/0416.分割等和子集.md b/problems/0416.分割等和子集.md index 9da1f8d5..4b26d188 100644 --- a/problems/0416.分割等和子集.md +++ b/problems/0416.分割等和子集.md @@ -127,9 +127,9 @@ for(int i = 0; i < nums.size(); i++) { 5. 举例推导dp数组 -dp[i]的数值一定是小于等于i的。 +dp[j]的数值一定是小于等于j的。 -**如果dp[i] == i 说明,集合中的子集总和正好可以凑成总和i,理解这一点很重要。** +**如果dp[j] == j 说明,集合中的子集总和正好可以凑成总和j,理解这一点很重要。** 用例1,输入[1,5,11,5] 为例,如图: @@ -168,8 +168,8 @@ public: }; ``` -* 时间复杂度:$O(n^2)$ -* 空间复杂度:$O(n)$,虽然dp数组大小为一个常数,但是大常数 +* 时间复杂度:O(n^2) +* 空间复杂度:O(n),虽然dp数组大小为一个常数,但是大常数 ## 总结 @@ -180,8 +180,6 @@ public: 看代码的话,就可以发现,基本就是按照01背包的写法来的。 - - ## 其他语言版本 diff --git a/problems/0454.四数相加II.md b/problems/0454.四数相加II.md index a7c903eb..a6cd413b 100644 --- a/problems/0454.四数相加II.md +++ b/problems/0454.四数相加II.md @@ -141,7 +141,24 @@ class Solution(object): ``` +```python +class Solution: + def fourSumCount(self, nums1: list, nums2: list, nums3: list, nums4: list) -> int: + from collections import defaultdict # You may use normal dict instead. + rec, cnt = defaultdict(lambda : 0), 0 + # To store the summary of all the possible combinations of nums1 & nums2, together with their frequencies. + for i in nums1: + for j in nums2: + rec[i+j] += 1 + # To add up the frequencies if the corresponding value occurs in the dictionary + for i in nums3: + for j in nums4: + cnt += rec.get(-(i+j), 0) # No matched key, return 0. + return cnt +``` + Go: + ```go func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int { m := make(map[int]int) diff --git a/problems/0491.递增子序列.md b/problems/0491.递增子序列.md index 70b08d50..6103c3d0 100644 --- a/problems/0491.递增子序列.md +++ b/problems/0491.递增子序列.md @@ -227,7 +227,39 @@ class Solution { } } ``` - +```java +//法二:使用map +class Solution { + //结果集合 + List> res = new ArrayList<>(); + //路径集合 + LinkedList path = new LinkedList<>(); + public List> findSubsequences(int[] nums) { + getSubsequences(nums,0); + return res; + } + private void getSubsequences( int[] nums, int start ) { + if(path.size()>1 ){ + res.add( new ArrayList<>(path) ); + // 注意这里不要加return,要取树上的节点 + } + HashMap map = new HashMap<>(); + for(int i=start ;i < nums.length ;i++){ + if(!path.isEmpty() && nums[i]< path.getLast()){ + continue; + } + // 使用过了当前数字 + if ( map.getOrDefault( nums[i],0 ) >=1 ){ + continue; + } + map.put(nums[i],map.getOrDefault( nums[i],0 )+1); + path.add( nums[i] ); + getSubsequences( nums,i+1 ); + path.removeLast(); + } + } +} +``` ### Python diff --git a/problems/0501.二叉搜索树中的众数.md b/problems/0501.二叉搜索树中的众数.md index a2984ecc..9cb5d071 100644 --- a/problems/0501.二叉搜索树中的众数.md +++ b/problems/0501.二叉搜索树中的众数.md @@ -512,7 +512,7 @@ class Solution: self.search_BST(cur.right) ``` - + > 迭代法-中序遍历-不使用额外空间,利用二叉搜索树特性 ```python @@ -661,7 +661,7 @@ var findMode = function(root) { } return res; }; -``` +``` 不使用额外空间,利用二叉树性质,中序遍历(有序): @@ -699,6 +699,107 @@ var findMode = function(root) { }; ``` +## TypeScript + +> 辅助Map法 + +```typescript +function findMode(root: TreeNode | null): number[] { + if (root === null) return []; + const countMap: Map = new Map(); + function traverse(root: TreeNode | null): void { + if (root === null) return; + countMap.set(root.val, (countMap.get(root.val) || 0) + 1); + traverse(root.left); + traverse(root.right); + } + traverse(root); + const countArr: number[][] = Array.from(countMap); + countArr.sort((a, b) => { + return b[1] - a[1]; + }) + const resArr: number[] = []; + const maxCount: number = countArr[0][1]; + for (let i of countArr) { + if (i[1] === maxCount) resArr.push(i[0]); + } + return resArr; +}; +``` + +> 递归中直接解决 + +```typescript +function findMode(root: TreeNode | null): number[] { + let preNode: TreeNode | null = null; + let maxCount: number = 0; + let count: number = 0; + let resArr: number[] = []; + function traverse(root: TreeNode | null): void { + if (root === null) return; + traverse(root.left); + if (preNode === null) { // 第一个节点 + count = 1; + } else if (preNode.val === root.val) { + count++; + } else { + count = 1; + } + if (count === maxCount) { + resArr.push(root.val); + } else if (count > maxCount) { + maxCount = count; + resArr.length = 0; + resArr.push(root.val); + } + preNode = root; + traverse(root.right); + } + traverse(root); + return resArr; +}; +``` + +> 迭代法 + +```typescript +function findMode(root: TreeNode | null): number[] { + const helperStack: TreeNode[] = []; + const resArr: number[] = []; + let maxCount: number = 0; + let count: number = 0; + let preNode: TreeNode | null = null; + let curNode: TreeNode | null = root; + while (curNode !== null || helperStack.length > 0) { + if (curNode !== null) { + helperStack.push(curNode); + curNode = curNode.left; + } else { + curNode = helperStack.pop()!; + if (preNode === null) { // 第一个节点 + count = 1; + } else if (preNode.val === curNode.val) { + count++; + } else { + count = 1; + } + if (count === maxCount) { + resArr.push(curNode.val); + } else if (count > maxCount) { + maxCount = count; + resArr.length = 0; + resArr.push(curNode.val); + } + preNode = curNode; + curNode = curNode.right; + } + } + return resArr; +}; +``` + + + -----------------------
diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md index 3ebb4c8c..77699c9f 100644 --- a/problems/0530.二叉搜索树的最小绝对差.md +++ b/problems/0530.二叉搜索树的最小绝对差.md @@ -238,7 +238,7 @@ class Solution: cur = cur.right return result -``` +``` ## Go: @@ -364,5 +364,74 @@ var getMinimumDifference = function(root) { } ``` +## TypeScript + +> 辅助数组解决 + +```typescript +function getMinimumDifference(root: TreeNode | null): number { + let helperArr: number[] = []; + function recur(root: TreeNode | null): void { + if (root === null) return; + recur(root.left); + helperArr.push(root.val); + recur(root.right); + } + recur(root); + let resMin: number = Infinity; + for (let i = 0, length = helperArr.length; i < length - 1; i++) { + resMin = Math.min(resMin, helperArr[i + 1] - helperArr[i]); + } + return resMin; +}; +``` + +> 递归中解决 + +```typescript +function getMinimumDifference(root: TreeNode | null): number { + let preNode: TreeNode | null= null; + let resMin: number = Infinity; + function recur(root: TreeNode | null): void { + if (root === null) return; + recur(root.left); + if (preNode !== null) { + resMin = Math.min(resMin, root.val - preNode.val); + } + preNode = root; + recur(root.right); + } + recur(root); + return resMin; +}; +``` + +> 迭代法-中序遍历 + +```typescript +function getMinimumDifference(root: TreeNode | null): number { + const helperStack: TreeNode[] = []; + let curNode: TreeNode | null = root; + let resMin: number = Infinity; + let preNode: TreeNode | null = null; + while (curNode !== null || helperStack.length > 0) { + if (curNode !== null) { + helperStack.push(curNode); + curNode = curNode.left; + } else { + curNode = helperStack.pop()!; + if (preNode !== null) { + resMin = Math.min(resMin, curNode.val - preNode.val); + } + preNode = curNode; + curNode = curNode.right; + } + } + return resMin; +}; +``` + + + -----------------------
diff --git a/problems/0541.反转字符串II.md b/problems/0541.反转字符串II.md index 14b8601a..8c13a390 100644 --- a/problems/0541.反转字符串II.md +++ b/problems/0541.反转字符串II.md @@ -98,8 +98,31 @@ public: ## 其他语言版本 +C: + +```c +char * reverseStr(char * s, int k){ + int len = strlen(s); + + for (int i = 0; i < len; i += (2 * k)) { + //判断剩余字符是否少于 k + k = i + k > len ? len - i : k; + + int left = i; + int right = i + k - 1; + while (left < right) { + char temp = s[left]; + s[left++] = s[right]; + s[right--] = temp; + } + } + + return s; +} +``` Java: + ```Java //解法一 class Solution { @@ -204,8 +227,23 @@ class Solution: return ''.join(res) ``` +Python3 (v2): + +```python +class Solution: + def reverseStr(self, s: str, k: int) -> str: + # Two pointers. Another is inside the loop. + p = 0 + while p < len(s): + p2 = p + k + # Written in this could be more pythonic. + s = s[:p] + s[p: p2][::-1] + s[p2:] + p = p + 2 * k + return s +``` Go: + ```go func reverseStr(s string, k int) string { ss := []byte(s) diff --git a/problems/0617.合并二叉树.md b/problems/0617.合并二叉树.md index f815d741..55786ea9 100644 --- a/problems/0617.合并二叉树.md +++ b/problems/0617.合并二叉树.md @@ -583,6 +583,56 @@ var mergeTrees = function(root1, root2) { ``` +## TypeScript + +> 递归法: + +```type +function mergeTrees(root1: TreeNode | null, root2: TreeNode | null): TreeNode | null { + if (root1 === null) return root2; + if (root2 === null) return root1; + const resNode: TreeNode = new TreeNode(root1.val + root2.val); + resNode.left = mergeTrees(root1.left, root2.left); + resNode.right = mergeTrees(root1.right, root2.right); + return resNode; +}; +``` + +> 迭代法: + +```typescript +function mergeTrees(root1: TreeNode | null, root2: TreeNode | null): TreeNode | null { + if (root1 === null) return root2; + if (root2 === null) return root1; + const helperQueue1: TreeNode[] = [], + helperQueue2: TreeNode[] = []; + helperQueue1.push(root1); + helperQueue2.push(root2); + let tempNode1: TreeNode, + tempNode2: TreeNode; + while (helperQueue1.length > 0) { + tempNode1 = helperQueue1.shift()!; + tempNode2 = helperQueue2.shift()!; + tempNode1.val += tempNode2.val; + if (tempNode1.left !== null && tempNode2.left !== null) { + helperQueue1.push(tempNode1.left); + helperQueue2.push(tempNode2.left); + } else if (tempNode1.left === null) { + tempNode1.left = tempNode2.left; + } + if (tempNode1.right !== null && tempNode2.right !== null) { + helperQueue1.push(tempNode1.right); + helperQueue2.push(tempNode2.right); + } else if (tempNode1.right === null) { + tempNode1.right = tempNode2.right; + } + } + return root1; +}; +``` + + + -----------------------
diff --git a/problems/0654.最大二叉树.md b/problems/0654.最大二叉树.md index 44c74f89..1c73354b 100644 --- a/problems/0654.最大二叉树.md +++ b/problems/0654.最大二叉树.md @@ -371,7 +371,56 @@ var constructMaximumBinaryTree = function (nums) { }; ``` +## TypeScript + +> 新建数组法: + +```typescript +function constructMaximumBinaryTree(nums: number[]): TreeNode | null { + if (nums.length === 0) return null; + let maxIndex: number = 0; + let maxVal: number = nums[0]; + for (let i = 1, length = nums.length; i < length; i++) { + if (nums[i] > maxVal) { + maxIndex = i; + maxVal = nums[i]; + } + } + const rootNode: TreeNode = new TreeNode(maxVal); + rootNode.left = constructMaximumBinaryTree(nums.slice(0, maxIndex)); + rootNode.right = constructMaximumBinaryTree(nums.slice(maxIndex + 1)); + return rootNode; +}; +``` + +> 使用数组索引法: + +```typescript +function constructMaximumBinaryTree(nums: number[]): TreeNode | null { + // 左闭右开区间[begin, end) + function recur(nums: number[], begin: number, end: number): TreeNode | null { + if (begin === end) return null; + let maxIndex: number = begin; + let maxVal: number = nums[begin]; + for (let i = begin + 1; i < end; i++) { + if (nums[i] > maxVal) { + maxIndex = i; + maxVal = nums[i]; + } + } + const rootNode: TreeNode = new TreeNode(maxVal); + rootNode.left = recur(nums, begin, maxIndex); + rootNode.right = recur(nums, maxIndex + 1, end); + return rootNode; + } + return recur(nums, 0, nums.length); +}; +``` + + + ## C + ```c struct TreeNode* traversal(int* nums, int left, int right) { //若左边界大于右边界,返回NULL diff --git a/problems/0700.二叉搜索树中的搜索.md b/problems/0700.二叉搜索树中的搜索.md index 1521514a..40cf4ea1 100644 --- a/problems/0700.二叉搜索树中的搜索.md +++ b/problems/0700.二叉搜索树中的搜索.md @@ -200,7 +200,7 @@ class Solution { if (val < root.val) root = root.left; else if (val > root.val) root = root.right; else return root; - return root; + return null; } } ``` @@ -236,7 +236,7 @@ class Solution: if val < root.val: root = root.left elif val > root.val: root = root.right else: return root - return root + return None ``` @@ -271,7 +271,7 @@ func searchBST(root *TreeNode, val int) *TreeNode { break } } - return root + return nil } ``` @@ -301,7 +301,6 @@ var searchBST = function (root, val) { return searchBST(root.left, val); if (root.val < val) return searchBST(root.right, val); - return null; }; ``` @@ -330,7 +329,37 @@ var searchBST = function (root, val) { else return root; } - return root; + return null; +}; +``` + +## TypeScript + +> 递归法 + +```typescript +function searchBST(root: TreeNode | null, val: number): TreeNode | null { + if (root === null || root.val === val) return root; + if (root.val < val) return searchBST(root.right, val); + if (root.val > val) return searchBST(root.left, val); + return null; +}; +``` + +> 迭代法 + +```typescript +function searchBST(root: TreeNode | null, val: number): TreeNode | null { + let resNode: TreeNode | null = root; + while (resNode !== null) { + if (resNode.val === val) return resNode; + if (resNode.val < val) { + resNode = resNode.right; + } else { + resNode = resNode.left; + } + } + return null; }; ``` diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index 379cb5fc..15e096a0 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -561,5 +561,51 @@ class Solution { } ``` +**C#:** +```csharp +//左闭右闭 +public class Solution { + public int Search(int[] nums, int target) { + int left = 0; + int right = nums.Length - 1; + while(left <= right){ + int mid = (right - left ) / 2 + left; + if(nums[mid] == target){ + return mid; + } + else if(nums[mid] < target){ + left = mid+1; + } + else if(nums[mid] > target){ + right = mid-1; + } + } + return -1; + } +} + +//左闭右开 +public class Solution{ + public int Search(int[] nums, int target){ + int left = 0; + int right = nums.Length; + while(left < right){ + int mid = (right - left) / 2 + left; + if(nums[mid] == target){ + return mid; + } + else if(nums[mid] < target){ + left = mid + 1; + } + else if(nums[mid] > target){ + right = mid; + } + } + return -1; + } +} +``` + + -----------------------
diff --git a/problems/0738.单调递增的数字.md b/problems/0738.单调递增的数字.md index e670bb31..c8ce8a2b 100644 --- a/problems/0738.单调递增的数字.md +++ b/problems/0738.单调递增的数字.md @@ -148,23 +148,19 @@ java版本1中创建了String数组,多次使用Integer.parseInt了方法, 版本2 class Solution { public int monotoneIncreasingDigits(int n) { - if (n==0)return 0; - char[] chars= Integer.toString(n).toCharArray(); - int start=Integer.MAX_VALUE;//start初始值设为最大值,这是为了防止当数字本身是单调递增时,没有一位数字需要改成9的情况 - for (int i=chars.length-1;i>0;i--){ - if (chars[i]= 0; i--) { + if (chars[i] > chars[i + 1]) { + chars[i]--; + start = i+1; } } - StringBuilder res=new StringBuilder(); - for (int i=0;i=start){ - res.append('9'); - }else res.append(chars[i]); + for (int i = start; i < s.length(); i++) { + chars[i] = '9'; } - return Integer.parseInt(res.toString()); + return Integer.parseInt(String.valueOf(chars)); } } ``` diff --git a/problems/0739.每日温度.md b/problems/0739.每日温度.md index d7489028..bdc75b96 100644 --- a/problems/0739.每日温度.md +++ b/problems/0739.每日温度.md @@ -177,34 +177,60 @@ public: Java: ```java -/** - * 单调栈,栈内顺序要么从大到小 要么从小到大,本题从大到小 - *

- * 入站元素要和当前栈内栈首元素进行比较 - * 若大于栈首则 则与元素下标做差 - * 若大于等于则放入 - * - * @param temperatures - * @return - */ - public static int[] dailyTemperatures(int[] temperatures) { - Stack stack = new Stack<>(); - int[] res = new int[temperatures.length]; - for (int i = 0; i < temperatures.length; i++) { - /** - * 取出下标进行元素值的比较 - */ - while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) { - int preIndex = stack.pop(); - res[preIndex] = i - preIndex; + +class Solution { + // 版本 1 + public int[] dailyTemperatures(int[] temperatures) { + + int lens=temperatures.length; + int []res=new int[lens]; + + /** + 如果当前遍历的元素 大于栈顶元素,表示 栈顶元素的 右边的最大的元素就是 当前遍历的元素, + 所以弹出 栈顶元素,并记录 + 如果栈不空的话,还要考虑新的栈顶与当前元素的大小关系 + 否则的话,可以直接入栈。 + 注意,单调栈里 加入的元素是 下标。 + */ + Stackstack=new Stack<>(); + stack.push(0); + for(int i=1;itemperatures[stack.peek()]){ + res[stack.peek()]=i-stack.peek(); + stack.pop(); + } + stack.push(i); } - /** - * 注意 放入的是元素位置 - */ - stack.push(i); } - return res; + + return res; } + + //--------这 是一条分界线 + // 版本 2 + class Solution { + public int[] dailyTemperatures(int[] temperatures) { + int lens=temperatures.length; + int []res=new int[lens]; + Stackstack=new Stack<>(); + for(int i=0;itemperatures[stack.peek()]){ + res[stack.peek()]=i-stack.peek(); + stack.pop(); + } + stack.push(i); + } + + return res; + } +} + +} ``` Python: ``` Python3 diff --git a/problems/0860.柠檬水找零.md b/problems/0860.柠檬水找零.md index 01bd1a3b..f48ecf4d 100644 --- a/problems/0860.柠檬水找零.md +++ b/problems/0860.柠檬水找零.md @@ -128,24 +128,24 @@ public: ```java class Solution { public boolean lemonadeChange(int[] bills) { - int cash_5 = 0; - int cash_10 = 0; + int five = 0; + int ten = 0; for (int i = 0; i < bills.length; i++) { if (bills[i] == 5) { - cash_5++; + five++; } else if (bills[i] == 10) { - cash_5--; - cash_10++; + five--; + ten++; } else if (bills[i] == 20) { - if (cash_10 > 0) { - cash_10--; - cash_5--; + if (ten > 0) { + ten--; + five--; } else { - cash_5 -= 3; + five -= 3; } } - if (cash_5 < 0 || cash_10 < 0) return false; + if (five < 0 || ten < 0) return false; } return true; diff --git a/problems/0968.监控二叉树.md b/problems/0968.监控二叉树.md index 433060a5..35c3ccdc 100644 --- a/problems/0968.监控二叉树.md +++ b/problems/0968.监控二叉树.md @@ -316,28 +316,44 @@ public: ### Java ```java class Solution { - private int count = 0; + int res=0; public int minCameraCover(TreeNode root) { - if (trval(root) == 0) count++; - return count; + // 对根节点的状态做检验,防止根节点是无覆盖状态 . + if(minCame(root)==0){ + res++; + } + return res; } - - 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++; + /** + 节点的状态值: + 0 表示无覆盖 + 1 表示 有摄像头 + 2 表示有覆盖 + 后序遍历,根据左右节点的情况,来判读 自己的状态 + */ + public int minCame(TreeNode root){ + if(root==null){ + // 空节点默认为 有覆盖状态,避免在叶子节点上放摄像头 return 2; } - - if (left == 2 || right == 2) { + int left=minCame(root.left); + int right=minCame(root.right); + + // 如果左右节点都覆盖了的话, 那么本节点的状态就应该是无覆盖,没有摄像头 + if(left==2&&right==2){ + //(2,2) + return 0; + }else if(left==0||right==0){ + // 左右节点都是无覆盖状态,那 根节点此时应该放一个摄像头 + // (0,0) (0,1) (0,2) (1,0) (2,0) + // 状态值为 1 摄像头数 ++; + res++; return 1; + }else{ + // 左右节点的 状态为 (1,1) (1,2) (2,1) 也就是左右节点至少存在 1个摄像头, + // 那么本节点就是处于被覆盖状态 + return 2; } - - return 0; } } ``` @@ -391,7 +407,7 @@ class Solution: result += 1 return result -``` +``` ### Go ```go diff --git a/problems/1002.查找常用字符.md b/problems/1002.查找常用字符.md index efad1e6a..36937b0b 100644 --- a/problems/1002.查找常用字符.md +++ b/problems/1002.查找常用字符.md @@ -256,38 +256,40 @@ var commonChars = function (words) { TypeScript ```ts -function commonChars(words: string[]): string[] { - let result: string[] = []; - if (words.length === 0) return result; - const size: number = 26; - const hash: number[] = new Array(size).fill(0); - const otherHash: number[] = new Array(size).fill(0); - let pivot: number = 'a'.charCodeAt(0); - // First word - for (let character of words[0]) { - hash[character.charCodeAt(0) - pivot]++; + console.time("test") + let str: string = "" + //设置一个用字母组成的map字典 + let map = new Map() + //给所有map设置初始值为0 + let wordInitial: [string, number][] = words[0] + .split("") + .map((item) => [item, 0]) + //如果有重复字母,就把重复字母的数量加1 + for (let word of words[0]) { + map.set(word, map.has(word) ? map.get(word) + 1 : 1) } - // Other words for (let i = 1; i < words.length; i++) { - for (let character of words[i]) { - otherHash[character.charCodeAt(0) - pivot]++; + const mapWord = new Map(wordInitial) + for (let j = 0; j < words[i].length; j++) { + if (!map.has(words[i][j])) continue + //mapWord中的字母的个数不能高于当前map的个数,多于则不能添加 + if (map.get(words[i][j]) > mapWord.get(words[i][j])) { + mapWord.set( + words[i][j], + mapWord.has(words[i][j]) ? mapWord!.get(words[i][j]) + 1 : 1 + ) + } } - // Update the first hash with min - for (let j = 0; j < size; j++) { - hash[j] = Math.min(hash[j], otherHash[j]); - } - // Reset otherHash - otherHash.fill(0); + //每次重新初始化map + map = mapWord } - // Construct the result - hash.forEach((element, index) => { - while (element-- > 0) { - result.push(String.fromCharCode(index + pivot)); - } - }); - return result; -} + for (let [key, value] of map) { + str += key.repeat(value) + } + console.timeEnd("test") + return str.split("") ``` + GO ```golang func commonChars(words []string) []string { diff --git a/problems/二叉树理论基础.md b/problems/二叉树理论基础.md index 62e3b19a..9c151e32 100644 --- a/problems/二叉树理论基础.md +++ b/problems/二叉树理论基础.md @@ -33,7 +33,7 @@ 什么是完全二叉树? -完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h -1  个节点。 +完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1)  个节点。 **大家要自己看完全二叉树的定义,很多同学对完全二叉树其实不是真正的懂了。** diff --git a/problems/二叉树的迭代遍历.md b/problems/二叉树的迭代遍历.md index ba38726b..8164724b 100644 --- a/problems/二叉树的迭代遍历.md +++ b/problems/二叉树的迭代遍历.md @@ -390,7 +390,7 @@ func inorderTraversal(root *TreeNode) []int { } ``` -javaScript +javaScript: ```js @@ -454,7 +454,7 @@ var postorderTraversal = function(root, res = []) { }; ``` -TypeScript: +TypeScript: ```typescript // 前序遍历(迭代法) @@ -509,77 +509,63 @@ function postorderTraversal(root: TreeNode | null): number[] { }; ``` -Swift: +Swift: -> 迭代法前序遍历 ```swift +// 前序遍历迭代法 func preorderTraversal(_ root: TreeNode?) -> [Int] { - var res = [Int]() - if root == nil { - return res - } - var stack = [TreeNode]() - stack.append(root!) + var result = [Int]() + guard let root = root else { return result } + var stack = [root] while !stack.isEmpty { - let node = stack.popLast()! - res.append(node.val) - if node.right != nil { - stack.append(node.right!) + let current = stack.removeLast() + // 先右后左,这样出栈的时候才是左右顺序 + if let node = current.right { // 右 + stack.append(node) } - if node.left != nil { - stack.append(node.left!) + if let node = current.left { // 左 + stack.append(node) } + result.append(current.val) // 中 } - return res + return result } -``` -> 迭代法中序遍历 -```swift -func inorderTraversal(_ root: TreeNode?) -> [Int] { - var res = [Int]() - if root == nil { - return res - } - var stack = [TreeNode]() - var cur: TreeNode? = root - while cur != nil || !stack.isEmpty { - if cur != nil { - stack.append(cur!) - cur = cur!.left - } else { - cur = stack.popLast() - res.append(cur!.val) - cur = cur!.right - } - } - return res -} -``` - -> 迭代法后序遍历 -```swift +// 后序遍历迭代法 func postorderTraversal(_ root: TreeNode?) -> [Int] { - var res = [Int]() - if root == nil { - return res - } - var stack = [TreeNode]() - stack.append(root!) - // res 存储 中 -> 右 -> 左 + var result = [Int]() + guard let root = root else { return result } + var stack = [root] while !stack.isEmpty { - let node = stack.popLast()! - res.append(node.val) - if node.left != nil { - stack.append(node.left!) + let current = stack.removeLast() + // 与前序相反,即中右左,最后结果还需反转才是后序 + if let node = current.left { // 左 + stack.append(node) } - if node.right != nil { - stack.append(node.right!) + if let node = current.right { // 右 + stack.append(node) + } + result.append(current.val) // 中 + } + return result.reversed() +} + +// 中序遍历迭代法 +func inorderTraversal(_ root: TreeNode?) -> [Int] { + var result = [Int]() + var stack = [TreeNode]() + var current: TreeNode! = root + while current != nil || !stack.isEmpty { + if current != nil { // 先访问到最左叶子 + stack.append(current) + current = current.left // 左 + } else { + current = stack.removeLast() + result.append(current.val) // 中 + current = current.right // 右 } } - // res 翻转 - res.reverse() - return res + return result } ``` diff --git a/problems/二叉树的递归遍历.md b/problems/二叉树的递归遍历.md index 2fef68da..35d19d7b 100644 --- a/problems/二叉树的递归遍历.md +++ b/problems/二叉树的递归遍历.md @@ -34,19 +34,19 @@ 1. **确定递归函数的参数和返回值**:因为要打印出前序遍历节点的数值,所以参数里需要传入vector在放节点的数值,除了这一点就不需要在处理什么数据了也不需要有返回值,所以递归函数返回类型就是void,代码如下: -``` +```cpp void traversal(TreeNode* cur, vector& vec) ``` 2. **确定终止条件**:在递归的过程中,如何算是递归结束了呢,当然是当前遍历的节点是空了,那么本层递归就要要结束了,所以如果当前遍历的这个节点是空,就直接return,代码如下: -``` +```cpp if (cur == NULL) return; ``` 3. **确定单层递归的逻辑**:前序遍历是中左右的循序,所以在单层递归的逻辑,是要先取中节点的数值,代码如下: -``` +```cpp vec.push_back(cur->val); // 中 traversal(cur->left, vec); // 左 traversal(cur->right, vec); // 右 diff --git a/problems/前序/ACM模式如何构建二叉树.md b/problems/前序/ACM模式如何构建二叉树.md index 28c4b6f7..bd2e9780 100644 --- a/problems/前序/ACM模式如何构建二叉树.md +++ b/problems/前序/ACM模式如何构建二叉树.md @@ -1,13 +1,4 @@ -

- - - - -

-

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

- - # 力扣上如何自己构造二叉树输入用例? 经常有录友问,二叉树的题目中输入用例在ACM模式下应该怎么构造呢? diff --git a/problems/前序/BAT级别技术面试流程和注意事项都在这里了.md b/problems/前序/BAT级别技术面试流程和注意事项都在这里了.md index 6678860d..27940f1b 100644 --- a/problems/前序/BAT级别技术面试流程和注意事项都在这里了.md +++ b/problems/前序/BAT级别技术面试流程和注意事项都在这里了.md @@ -1,12 +1,5 @@ -

- - - - -

-

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

- +# 大厂技术面试流程和注意事项 大型互联网企业一般通过几轮技术面试来考察大家的各项能力,一般流程如下: diff --git a/problems/前序/On的算法居然超时了,此时的n究竟是多大?.md b/problems/前序/On的算法居然超时了,此时的n究竟是多大?.md index 5257ceb9..20a48e19 100644 --- a/problems/前序/On的算法居然超时了,此时的n究竟是多大?.md +++ b/problems/前序/On的算法居然超时了,此时的n究竟是多大?.md @@ -1,18 +1,12 @@ -

- - - - -

-

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

+# On的算法居然超时了,此时的n究竟是多大? 一些同学可能对计算机运行的速度还没有概念,就是感觉计算机运行速度应该会很快,那么在leetcode上做算法题目的时候为什么会超时呢? 计算机究竟1s可以执行多少次操作呢? 接下来探讨一下这个问题。 -# 超时是怎么回事 +## 超时是怎么回事 ![程序超时](https://img-blog.csdnimg.cn/20200729112716117.png) @@ -24,7 +18,7 @@ 如果n的规模已经足够让$O(n)$的算法运行时间超过了1s,就应该考虑log(n)的解法了。 -# 从硬件配置看计算机的性能 +## 从硬件配置看计算机的性能 计算机的运算速度主要看CPU的配置,以2015年MacPro为例,CPU配置:2.7 GHz Dual-Core Intel Core i5 。 @@ -43,7 +37,7 @@ 所以我们的程序在计算机上究竟1s真正能执行多少次操作呢? -# 做个测试实验 +## 做个测试实验 在写测试程序测1s内处理多大数量级数据的时候,有三点需要注意: @@ -152,7 +146,7 @@ $O(n\log n)$的算法,1s内大概计算机可以运行 2 * (10^7)次计算, 至于 $O(\log n)$ 和 $O(n^3)$ 等等这些时间复杂度在1s内可以处理的多大的数据规模,大家可以自己写一写代码去测一下了。 -# 完整测试代码 +## 完整测试代码 ```CPP #include @@ -264,7 +258,7 @@ public class TimeComplexity { } ``` -# 总结 +## 总结 本文详细分析了在leetcode上做题程序为什么会有超时,以及从硬件配置上大体知道CPU的执行速度,然后亲自做一个实验来看看$O(n)$的算法,跑一秒钟,这个n究竟是做大,最后给出不同时间复杂度,一秒内可以运算出来的n的大小。 diff --git a/problems/前序/上海互联网公司总结.md b/problems/前序/上海互联网公司总结.md index ffcbe77b..6309ef58 100644 --- a/problems/前序/上海互联网公司总结.md +++ b/problems/前序/上海互联网公司总结.md @@ -1,11 +1,3 @@ -

- - - - -

-

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

- # 上海互联网公司总结 diff --git a/problems/前序/什么是核心代码模式,什么又是ACM模式?.md b/problems/前序/什么是核心代码模式,什么又是ACM模式?.md index 54c5b6ec..0b9d230f 100644 --- a/problems/前序/什么是核心代码模式,什么又是ACM模式?.md +++ b/problems/前序/什么是核心代码模式,什么又是ACM模式?.md @@ -1,11 +1,5 @@ -

- - - - -

-

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

+# 什么是核心代码模式,什么又是ACM模式? 现在很多企业都在牛客上进行面试,**很多录友和我反馈说搞不懂牛客上输入代码的ACM模式**。 diff --git a/problems/前序/代码风格.md b/problems/前序/代码风格.md index b48665e5..4ab94a51 100644 --- a/problems/前序/代码风格.md +++ b/problems/前序/代码风格.md @@ -1,13 +1,3 @@ -

- - - - -

-

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

- - - # 看了这么多代码,谈一谈代码风格! @@ -142,11 +132,6 @@ Google规范是 大括号和 控制语句保持同一行的,我个人也很认 就酱,以后我还会陆续分享,关于代码,求职,学习工作之类的内容。 - - - ----------------------- -* 作者微信:[程序员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/前序/关于时间复杂度,你不知道的都在这里!.md b/problems/前序/关于时间复杂度,你不知道的都在这里!.md index 478b82e4..b2acb7dd 100644 --- a/problems/前序/关于时间复杂度,你不知道的都在这里!.md +++ b/problems/前序/关于时间复杂度,你不知道的都在这里!.md @@ -1,11 +1,5 @@ -

- - - - -

-

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

+# 关于时间复杂度,你不知道的都在这里! 相信每一位录友都接触过时间复杂度,但又对时间复杂度的认识处于一种朦胧的状态,所以是时候对时间复杂度来一个深度的剖析了。 diff --git a/problems/前序/关于空间复杂度,可能有几个疑问?.md b/problems/前序/关于空间复杂度,可能有几个疑问?.md index d49b42a2..162dfe96 100644 --- a/problems/前序/关于空间复杂度,可能有几个疑问?.md +++ b/problems/前序/关于空间复杂度,可能有几个疑问?.md @@ -1,11 +1,3 @@ -

- - - - -

-

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

- # 空间复杂度分析 diff --git a/problems/前序/刷了这么多题,你了解自己代码的内存消耗么?.md b/problems/前序/刷了这么多题,你了解自己代码的内存消耗么?.md index 0364fc8b..f4aa4b6e 100644 --- a/problems/前序/刷了这么多题,你了解自己代码的内存消耗么?.md +++ b/problems/前序/刷了这么多题,你了解自己代码的内存消耗么?.md @@ -1,13 +1,6 @@ -

- - - - -

-

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

- +# 刷了这么多题,你了解自己代码的内存消耗么? 理解代码的内存消耗,最关键是要知道自己所用编程语言的内存管理。 diff --git a/problems/前序/力扣上的代码想在本地编译运行?.md b/problems/前序/力扣上的代码想在本地编译运行?.md index dca6eec3..bcef3886 100644 --- a/problems/前序/力扣上的代码想在本地编译运行?.md +++ b/problems/前序/力扣上的代码想在本地编译运行?.md @@ -1,10 +1,4 @@ -

- - - - -

-

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

+# 力扣上的代码想在本地编译运行? 很多录友都问过我一个问题,就是力扣上的代码如何在本地编译运行? diff --git a/problems/前序/北京互联网公司总结.md b/problems/前序/北京互联网公司总结.md index 02a877b7..a10cab06 100644 --- a/problems/前序/北京互联网公司总结.md +++ b/problems/前序/北京互联网公司总结.md @@ -1,15 +1,8 @@ -

- - - - -

+# 北京互联网公司总结 +

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

- -# 北京互联网公司总结 - **个人总结难免有所疏忽,欢迎大家补充,公司好坏没有排名哈!** 如果要在北京找工作,这份list可以作为一个大纲,寻找自己合适的公司。 diff --git a/problems/前序/广州互联网公司总结.md b/problems/前序/广州互联网公司总结.md index e83fcd2b..b8b1641b 100644 --- a/problems/前序/广州互联网公司总结.md +++ b/problems/前序/广州互联网公司总结.md @@ -1,14 +1,8 @@ -

- - - - -

+# 广州互联网公司总结 +

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

-# 广州互联网公司总结 - **个人总结难免有所疏忽,欢迎大家补充,公司好坏没有排名哈!** ## 一线互联网 diff --git a/problems/前序/成都互联网公司总结.md b/problems/前序/成都互联网公司总结.md index 7964f23c..f6a575f6 100644 --- a/problems/前序/成都互联网公司总结.md +++ b/problems/前序/成都互联网公司总结.md @@ -1,15 +1,7 @@ -

- - - - -

-

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

- - - # 成都互联网公司总结 +

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

+ **排名不分先后,个人总结难免有所疏漏,欢迎补充!** diff --git a/problems/前序/杭州互联网公司总结.md b/problems/前序/杭州互联网公司总结.md index 029ee380..6154cfe5 100644 --- a/problems/前序/杭州互联网公司总结.md +++ b/problems/前序/杭州互联网公司总结.md @@ -1,15 +1,8 @@ -

- - - - -

+# 杭州互联网公司总结 +

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

- -# 杭州互联网公司总结 - **个人总结难免有所疏忽,欢迎大家补充,公司好坏没有排名哈!** ## 一线互联网 diff --git a/problems/前序/深圳互联网公司总结.md b/problems/前序/深圳互联网公司总结.md index 61bd52e8..3d548abb 100644 --- a/problems/前序/深圳互联网公司总结.md +++ b/problems/前序/深圳互联网公司总结.md @@ -1,14 +1,8 @@ -

- - - - -

-

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

- # 深圳互联网公司总结 +

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

+ **个人总结难免有所疏忽,欢迎大家补充,公司好坏没有排名哈!** ## 一线互联网 diff --git a/problems/前序/程序员写文档工具.md b/problems/前序/程序员写文档工具.md index 5504ae7a..a2f6ee3b 100644 --- a/problems/前序/程序员写文档工具.md +++ b/problems/前序/程序员写文档工具.md @@ -1,16 +1,10 @@ -

- - - - -

+ +# 程序员应该用什么用具来写文档? +

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

- -# 程序员应该用什么用具来写文档? - Carl平时写东西,都是统一使用markdown,包括题解啊,笔记啊,所以这里给大家安利一波markdown对程序员的重要性! 程序员为什么要学习markdown呢? diff --git a/problems/前序/程序员简历.md b/problems/前序/程序员简历.md index 522fc5f7..e64f547a 100644 --- a/problems/前序/程序员简历.md +++ b/problems/前序/程序员简历.md @@ -1,16 +1,5 @@ -

- - - - -

-

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

- - - # 程序员的简历应该这么写!!(附简历模板) - Carl校招社招都拿过大厂的offer,同时也看过很多应聘者的简历,这里把自己总结的简历技巧以及常见问题给大家梳理一下。 ## 简历篇幅 @@ -116,7 +105,7 @@ Carl校招社招都拿过大厂的offer,同时也看过很多应聘者的简 ![简历模板](https://img-blog.csdnimg.cn/20200803175538158.png) -这里是简历模板中Markdown的代码:https://github.com/youngyangyang04/Markdown-Resume-Template ,可以fork到自己Github仓库上,按照这个模板来修改自己的简历。 +这里是简历模板中Markdown的代码:[https://github.com/youngyangyang04/Markdown-Resume-Template](https://github.com/youngyangyang04/Markdown-Resume-Template) ,可以fork到自己Github仓库上,按照这个模板来修改自己的简历。 **Word版本的简历,大家可以在公众号「代码随想录」后台回复:简历模板,就可以获取!** diff --git a/problems/前序/递归算法的时间与空间复杂度分析.md b/problems/前序/递归算法的时间与空间复杂度分析.md index 914cccfd..3c0d219c 100644 --- a/problems/前序/递归算法的时间与空间复杂度分析.md +++ b/problems/前序/递归算法的时间与空间复杂度分析.md @@ -1,11 +1,3 @@ -

- - - - -

-

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

- # 递归算法的时间与空间复杂度分析! diff --git a/problems/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.md b/problems/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.md index 849a025d..12af4dd8 100644 --- a/problems/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.md +++ b/problems/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.md @@ -1,13 +1,3 @@ -

- - - - -

-

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

- - - # 通过一道面试题目,讲一讲递归算法的时间复杂度! diff --git a/problems/剑指Offer05.替换空格.md b/problems/剑指Offer05.替换空格.md index 530545fb..21fc0602 100644 --- a/problems/剑指Offer05.替换空格.md +++ b/problems/剑指Offer05.替换空格.md @@ -121,6 +121,37 @@ for (int i = 0; i < a.size(); i++) { ## 其他语言版本 +C: +```C +char* replaceSpace(char* s){ + //统计空格数量 + int count = 0; + int len = strlen(s); + for (int i = 0; i < len; i++) { + if (s[i] == ' ') { + count++; + } + } + + //为新数组分配空间 + int newLen = len + count * 2; + char* result = malloc(sizeof(char) * newLen + 1); + //填充新数组并替换空格 + for (int i = len - 1, j = newLen - 1; i >= 0; i--, j--) { + if (s[i] != ' ') { + result[j] = s[i]; + } else { + result[j--] = '0'; + result[j--] = '2'; + result[j] = '%'; + } + } + result[newLen] = '\0'; + + return result; +} +``` + Java: ```Java @@ -260,8 +291,24 @@ class Solution: ``` +```python +class Solution: + def replaceSpace(self, s: str) -> str: + # method 1 - Very rude + return "%20".join(s.split(" ")) + + # method 2 - Reverse the s when counting in for loop, then update from the end. + n = len(s) + for e, i in enumerate(s[::-1]): + print(i, e) + if i == " ": + s = s[: n - (e + 1)] + "%20" + s[n - e:] + print("") + return s +``` javaScript: + ```js /** * @param {string} s diff --git a/problems/回溯总结.md b/problems/回溯总结.md index 671e0a4e..bd0db575 100644 --- a/problems/回溯总结.md +++ b/problems/回溯总结.md @@ -380,24 +380,24 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所 以下在计算空间复杂度的时候我都把系统栈(不是数据结构里的栈)所占空间算进去。 子集问题分析: -* 时间复杂度:$O(2^n)$,因为每一个元素的状态无外乎取与不取,所以时间复杂度为$O(2^n)$ -* 空间复杂度:$O(n)$,递归深度为n,所以系统栈所用空间为$O(n)$,每一层递归所用的空间都是常数级别,注意代码里的result和path都是全局变量,就算是放在参数里,传的也是引用,并不会新申请内存空间,最终空间复杂度为$O(n)$ +* 时间复杂度:O(2^n),因为每一个元素的状态无外乎取与不取,所以时间复杂度为$O(2^n)$ +* 空间复杂度:O(n),递归深度为n,所以系统栈所用空间为$O(n)$,每一层递归所用的空间都是常数级别,注意代码里的result和path都是全局变量,就算是放在参数里,传的也是引用,并不会新申请内存空间,最终空间复杂度为$O(n)$ 排列问题分析: -* 时间复杂度:$O(n!)$,这个可以从排列的树形图中很明显发现,每一层节点为n,第二层每一个分支都延伸了n-1个分支,再往下又是n-2个分支,所以一直到叶子节点一共就是 n * n-1 * n-2 * ..... 1 = n!。 -* 空间复杂度:$O(n)$,和子集问题同理。 +* 时间复杂度:O(n!),这个可以从排列的树形图中很明显发现,每一层节点为n,第二层每一个分支都延伸了n-1个分支,再往下又是n-2个分支,所以一直到叶子节点一共就是 n * n-1 * n-2 * ..... 1 = n!。 +* 空间复杂度:O(n),和子集问题同理。 组合问题分析: -* 时间复杂度:$O(2^n)$,组合问题其实就是一种子集的问题,所以组合问题最坏的情况,也不会超过子集问题的时间复杂度。 -* 空间复杂度:$O(n)$,和子集问题同理。 +* 时间复杂度:O(2^n),组合问题其实就是一种子集的问题,所以组合问题最坏的情况,也不会超过子集问题的时间复杂度。 +* 空间复杂度:O(n),和子集问题同理。 N皇后问题分析: -* 时间复杂度:$O(n!)$ ,其实如果看树形图的话,直觉上是$O(n^n)$,但皇后之间不能见面所以在搜索的过程中是有剪枝的,最差也就是O(n!),n!表示n * (n-1) * .... * 1。 -* 空间复杂度:$O(n)$,和子集问题同理。 +* 时间复杂度:O(n!) ,其实如果看树形图的话,直觉上是$O(n^n)$,但皇后之间不能见面所以在搜索的过程中是有剪枝的,最差也就是O(n!),n!表示n * (n-1) * .... * 1。 +* 空间复杂度:O(n),和子集问题同理。 解数独问题分析: -* 时间复杂度:$O(9^m)$ , m是'.'的数目。 -* 空间复杂度:$O(n^2)$,递归的深度是n^2 +* 时间复杂度:O(9^m) , m是'.'的数目。 +* 空间复杂度:O(n^2),递归的深度是n^2 **一般说道回溯算法的复杂度,都说是指数级别的时间复杂度,这也算是一个概括吧!** diff --git a/problems/根据身高重建队列(vector原理讲解).md b/problems/根据身高重建队列(vector原理讲解).md index 11a72e2d..28317e6c 100644 --- a/problems/根据身高重建队列(vector原理讲解).md +++ b/problems/根据身高重建队列(vector原理讲解).md @@ -171,6 +171,14 @@ Python: Go: +Go中slice的`append`操作和C++中vector的扩容机制基本相同。 + +说是基本呢,其实是因为大家平时刷题和工作中遇到的数据不会特别大。 + +具体来说,当当前slice的长度小于**1024**时,执行`append`操作,新slice的capacity会变成当前的2倍;而当slice长度大于等于**1024**时,slice的扩容变成了每次增加当前slice长度的**1/4**。 + +在Go Slice的底层实现中,如果capacity不够时,会做一个reslice的操作,底层数组也会重新被复制到另一块内存区域中,所以`append`一个元素,不一定是O(1), 也可能是O(n)哦。 + diff --git a/problems/知识星球精选/HR特意刁难非科班.md b/problems/知识星球精选/HR特意刁难非科班.md index c59debf2..d5d39fe3 100644 --- a/problems/知识星球精选/HR特意刁难非科班.md +++ b/problems/知识星球精选/HR特意刁难非科班.md @@ -1,6 +1,6 @@

- + @@ -8,7 +8,7 @@ 不少录友都是非科班转程序员,或者进军互联网的,但有一些HR在HR面的时候特意刁难大家。 -正如[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里,这位录友所遭受的情景。 +正如[知识星球](https://programmercarl.com/other/kstar.html)里,这位录友所遭受的情景。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211006230202.png) diff --git a/problems/知识星球精选/HR面注意事项.md b/problems/知识星球精选/HR面注意事项.md index 6a0a26f1..5dba672c 100644 --- a/problems/知识星球精选/HR面注意事项.md +++ b/problems/知识星球精选/HR面注意事项.md @@ -1,12 +1,12 @@

- + # HR面注意事项 -[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里已经有一些录友开始准备HR面。 +[知识星球](https://programmercarl.com/other/kstar.html)里已经有一些录友开始准备HR面。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210807155107.png) @@ -86,4 +86,4 @@ HR朋友的回答是:你不说真相,我会认为你可能对技术有追求 --------------- -加入「代码随想录」知识星球,[点击这里](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) +加入「代码随想录」知识星球,[点击这里](https://programmercarl.com/other/kstar.html) diff --git a/problems/知识星球精选/offer对比-决赛圈.md b/problems/知识星球精选/offer对比-决赛圈.md index 1f91730f..081ae5ec 100644 --- a/problems/知识星球精选/offer对比-决赛圈.md +++ b/problems/知识星球精选/offer对比-决赛圈.md @@ -1,5 +1,5 @@

- + @@ -7,7 +7,7 @@ 秋招已经结束了,该开奖的差不多都陆续开奖了,很多录友的也进入了offer决赛圈。 -我每天都在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里,回答十几个offer对比的问题,我也是结合自己过来人的经验给大家做做分析,我也选几个案例,在公众号上也给大家分享一下,希望对大家有所启发。 +我每天都在[知识星球](https://programmercarl.com/other/kstar.html)里,回答十几个offer对比的问题,我也是结合自己过来人的经验给大家做做分析,我也选几个案例,在公众号上也给大家分享一下,希望对大家有所启发。 以下是知识星球里的部分问答: diff --git a/problems/知识星球精选/offer总决赛,何去何从.md b/problems/知识星球精选/offer总决赛,何去何从.md index 01745ae3..e22c5d4a 100644 --- a/problems/知识星球精选/offer总决赛,何去何从.md +++ b/problems/知识星球精选/offer总决赛,何去何从.md @@ -1,12 +1,12 @@

- + # offer总决赛,何去何从! -最近在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)上,给至少300位录友做了offer选择,准对大家的情况,结合我的经验做一做分析。 +最近在[知识星球](https://programmercarl.com/other/kstar.html)上,给至少300位录友做了offer选择,准对大家的情况,结合我的经验做一做分析。 希望可以给大家带来不一样的分析视角,帮大家少走弯路。 diff --git a/problems/知识星球精选/offer的选择.md b/problems/知识星球精选/offer的选择.md index b9b40dea..106bc5f8 100644 --- a/problems/知识星球精选/offer的选择.md +++ b/problems/知识星球精选/offer的选择.md @@ -1,6 +1,6 @@

- + @@ -10,7 +10,7 @@ 不过大部分同学应该拿到的是 两个大厂offer,或者说拿到两个小厂offer,还要考虑岗位,业务,公司前景,那么就要纠结如何选择了。 -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里,我已经给很多录友提供了选择offer的建议,这里也分享出来,希望对大家在选择offer上有所启发。 +在[知识星球](https://programmercarl.com/other/kstar.html)里,我已经给很多录友提供了选择offer的建议,这里也分享出来,希望对大家在选择offer上有所启发。 ## 保研与工作 diff --git a/problems/知识星球精选/不一样的七夕.md b/problems/知识星球精选/不一样的七夕.md index a670e078..40d15ecd 100644 --- a/problems/知识星球精选/不一样的七夕.md +++ b/problems/知识星球精选/不一样的七夕.md @@ -1,11 +1,11 @@

- + # 特殊的七夕 -昨天在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)发了一个状态: +昨天在[知识星球](https://programmercarl.com/other/kstar.html)发了一个状态: ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210815084126.png) diff --git a/problems/知识星球精选/不喜欢写代码怎么办.md b/problems/知识星球精选/不喜欢写代码怎么办.md index 9bc624bb..84d372f0 100644 --- a/problems/知识星球精选/不喜欢写代码怎么办.md +++ b/problems/知识星球精选/不喜欢写代码怎么办.md @@ -1,7 +1,7 @@ # 看到代码就抵触!怎么办? -最近在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里,看到了不少录友,其实是不喜欢写代码,看到 哪些八股文都是很抵触的。 +最近在[知识星球](https://programmercarl.com/other/kstar.html)里,看到了不少录友,其实是不喜欢写代码,看到 哪些八股文都是很抵触的。 其实是一个普遍现象,我在星球里分享了一下,我对这一情况的一些想法。 diff --git a/problems/知识星球精选/不少录友想放弃秋招.md b/problems/知识星球精选/不少录友想放弃秋招.md index 721a9313..81c99503 100644 --- a/problems/知识星球精选/不少录友想放弃秋招.md +++ b/problems/知识星球精选/不少录友想放弃秋招.md @@ -1,5 +1,5 @@

- + @@ -7,7 +7,7 @@ 马上就要九月份了,互联网大厂的秋招的序幕早已拉开。 -发现[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里有一部分录友想放弃秋招,直接准备明年的春招,估计关注公众号的录友也有不少有这种想法的。 +发现[知识星球](https://programmercarl.com/other/kstar.html)里有一部分录友想放弃秋招,直接准备明年的春招,估计关注公众号的录友也有不少有这种想法的。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210813103515.png) @@ -50,7 +50,7 @@ 所以也给明年找工作的录友们(2023届)提一个醒,现在就要系统性的准备起来了,因为明年春季实习招聘 是一个很好的进大厂的机会,剩下的时间也不是很多了。 -来看看[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里,一位准大三的录友准备的情况 +来看看[知识星球](https://programmercarl.com/other/kstar.html)里,一位准大三的录友准备的情况 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/星球大三.jpg) @@ -60,7 +60,7 @@ **我已经预感到 这两位 等到秋招的时候就是稳稳的offer收割机**。 -[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)还有很多已经开始提前准备,或者看了 星球发文状态就开始着手准备的录友了。 +[知识星球](https://programmercarl.com/other/kstar.html)还有很多已经开始提前准备,或者看了 星球发文状态就开始着手准备的录友了。 所以 **所谓的大牛,都是 很早就规划自己要学的东西,很早就开始向过来人请教应该如何找工作,很早就知道自己应该学哪些技术,看哪些书, 这样等到找工作的时候,才是剑锋出鞘的时候**。 diff --git a/problems/知识星球精选/专业技能可以这么写.md b/problems/知识星球精选/专业技能可以这么写.md index dd616713..a1b7ba3a 100644 --- a/problems/知识星球精选/专业技能可以这么写.md +++ b/problems/知识星球精选/专业技能可以这么写.md @@ -1,5 +1,5 @@

- + @@ -8,7 +8,7 @@ # 你简历里的「专业技能」写的够专业么? -其实我几乎每天都要看一些简历,有一些写的不错的,我都会在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里分享一下。 +其实我几乎每天都要看一些简历,有一些写的不错的,我都会在[知识星球](https://programmercarl.com/other/kstar.html)里分享一下。 ![](https://code-thinking-1253855093.cos.ap-guangzhou.myqcloud.com/pics/20210626172902.png) 这次呢,我再专门说一说简历中的【专业技能】这一栏应该怎么写。 diff --git a/problems/知识星球精选/入职后担心代码能力跟不上.md b/problems/知识星球精选/入职后担心代码能力跟不上.md index c2704525..58b8c32c 100644 --- a/problems/知识星球精选/入职后担心代码能力跟不上.md +++ b/problems/知识星球精选/入职后担心代码能力跟不上.md @@ -1,12 +1,12 @@

- + # 入职后担心代码能力跟不上 -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)上,很多录友已经担心自己去了公司工作以后,代码能力跟不上,会压力很大。 +在[知识星球](https://programmercarl.com/other/kstar.html)上,很多录友已经担心自己去了公司工作以后,代码能力跟不上,会压力很大。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211031202952.png) diff --git a/problems/知识星球精选/关于实习大家的疑问.md b/problems/知识星球精选/关于实习大家的疑问.md index 5d4e695b..88de4436 100644 --- a/problems/知识星球精选/关于实习大家的疑问.md +++ b/problems/知识星球精选/关于实习大家的疑问.md @@ -1,11 +1,11 @@

- + # 关于实习,大家可能有点迷茫! -我在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里回答了很多关于实习相关的问题,其实很多录友可能都有这么样的疑问,主要关于实习的问题有如下四点: +我在[知识星球](https://programmercarl.com/other/kstar.html)里回答了很多关于实习相关的问题,其实很多录友可能都有这么样的疑问,主要关于实习的问题有如下四点: * 秋招什么时候开始准备 * 要不要准备实习 diff --git a/problems/知识星球精选/关于提前批的一些建议.md b/problems/知识星球精选/关于提前批的一些建议.md index 415a8b2f..6a316bd2 100644 --- a/problems/知识星球精选/关于提前批的一些建议.md +++ b/problems/知识星球精选/关于提前批的一些建议.md @@ -1,5 +1,5 @@

- + @@ -9,7 +9,7 @@ 以前提前批,都是 8月份,8月份中序左右,而不少大厂现在就已经提前批了。 -不少录友在 公众号留言,和[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里,表示提前批来的还是有点快。 +不少录友在 公众号留言,和[知识星球](https://programmercarl.com/other/kstar.html)里,表示提前批来的还是有点快。 ![](https://code-thinking-1253855093.cos.ap-guangzhou.myqcloud.com/pics/20210618162214.png) diff --git a/problems/知识星球精选/写简历的一些问题.md b/problems/知识星球精选/写简历的一些问题.md index af42cea1..426eb2a6 100644 --- a/problems/知识星球精选/写简历的一些问题.md +++ b/problems/知识星球精选/写简历的一些问题.md @@ -1,11 +1,11 @@

- + # 程序员应该这么写简历! -自运营[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)以来,我已经给星球里的录友们看了 一百多份简历,并准对大家简历上的问题都给出了对应的详细建议。 +自运营[知识星球](https://programmercarl.com/other/kstar.html)以来,我已经给星球里的录友们看了 一百多份简历,并准对大家简历上的问题都给出了对应的详细建议。 社招,校招,实习的都有,其实大家的简历看多了,发现有很多共性的问题,这里就和大家分享一下。 diff --git a/problems/知识星球精选/初入大三选择考研VS工作.md b/problems/知识星球精选/初入大三选择考研VS工作.md index ba675761..f602e9e9 100644 --- a/problems/知识星球精选/初入大三选择考研VS工作.md +++ b/problems/知识星球精选/初入大三选择考研VS工作.md @@ -1,6 +1,6 @@

- + @@ -8,7 +8,7 @@ 9月份开学季,已过,一些录友也升入大三了,升入大三摆在自己面前最大的问题就是,考研还是找工作? -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里就有录友问我这样一个问题, 其实每个人情况不一样,做出的选择也不一样,这里给大家分享一下,相信对你也会有启发。 +在[知识星球](https://programmercarl.com/other/kstar.html)里就有录友问我这样一个问题, 其实每个人情况不一样,做出的选择也不一样,这里给大家分享一下,相信对你也会有启发。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211002110618.png) diff --git a/problems/知识星球精选/刷力扣用不用库函数.md b/problems/知识星球精选/刷力扣用不用库函数.md index 73f2a2d5..b52e4d03 100644 --- a/problems/知识星球精选/刷力扣用不用库函数.md +++ b/problems/知识星球精选/刷力扣用不用库函数.md @@ -1,11 +1,11 @@

- + # 究竟什么时候用库函数,什么时候要自己实现 -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里有录友问我,刷题究竟要不要用库函数? 刷题的时候总是禁不住库函数的诱惑,如果都不用库函数一些题目做起来还很麻烦。 +在[知识星球](https://programmercarl.com/other/kstar.html)里有录友问我,刷题究竟要不要用库函数? 刷题的时候总是禁不住库函数的诱惑,如果都不用库函数一些题目做起来还很麻烦。 估计不少录友都有这个困惑,我来说一说对于库函数的使用。 diff --git a/problems/知识星球精选/刷题攻略要刷两遍.md b/problems/知识星球精选/刷题攻略要刷两遍.md index 1f4fd7f9..285a5728 100644 --- a/problems/知识星球精选/刷题攻略要刷两遍.md +++ b/problems/知识星球精选/刷题攻略要刷两遍.md @@ -1,5 +1,5 @@

- + @@ -27,7 +27,7 @@ 第三遍基本就得心应手了。 -在[「代码随想录」知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)中,我都是强调大家要至少刷两遍,有时间的话刷三遍, +在[「代码随想录」知识星球](https://programmercarl.com/other/kstar.html)中,我都是强调大家要至少刷两遍,有时间的话刷三遍, 可以看看星球里录友们的打卡: diff --git a/problems/知识星球精选/博士转行计算机.md b/problems/知识星球精选/博士转行计算机.md index 66769264..4da79e97 100644 --- a/problems/知识星球精选/博士转行计算机.md +++ b/problems/知识星球精选/博士转行计算机.md @@ -1,11 +1,11 @@

- + # 本硕非计算机博士,如果找计算机相关工作 -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里,有一位博士录友,本硕都不是计算机,博士转的计算机,问了这样一个问题 +在[知识星球](https://programmercarl.com/other/kstar.html)里,有一位博士录友,本硕都不是计算机,博士转的计算机,问了这样一个问题 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210903213924.png) diff --git a/problems/知识星球精选/合适自己的就是最好的.md b/problems/知识星球精选/合适自己的就是最好的.md index fda51afa..dc31f5a7 100644 --- a/problems/知识星球精选/合适自己的就是最好的.md +++ b/problems/知识星球精选/合适自己的就是最好的.md @@ -1,5 +1,5 @@

- + @@ -7,7 +7,7 @@ 秋招已经进入下半场了,不少同学也拿到了offer,但不是说非要进大厂,每个人情况都不一样,**合适自己的,就是最好的!**。 -[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里有一位录友,就终于拿到了合适自己的offer,并不是大厂,是南京的一家公司,**但很合适自己,其实就非常值得开心**。 +[知识星球](https://programmercarl.com/other/kstar.html)里有一位录友,就终于拿到了合适自己的offer,并不是大厂,是南京的一家公司,**但很合适自己,其实就非常值得开心**。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210910232502.png) @@ -33,5 +33,5 @@ 我在发文的时候 看了一遍她这几个月完整的打卡过程,还是深有感触的。 -[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里还有很多很多这样的录友在每日奋斗着,**我相信 等大家拿到offer之后,在回头看一下当初星球里曾经每日打卡的点点滴滴,不仅会感动自己 也会感动每一位见证者**。 +[知识星球](https://programmercarl.com/other/kstar.html)里还有很多很多这样的录友在每日奋斗着,**我相信 等大家拿到offer之后,在回头看一下当初星球里曾经每日打卡的点点滴滴,不仅会感动自己 也会感动每一位见证者**。 diff --git a/problems/知识星球精选/备战2022届秋招.md b/problems/知识星球精选/备战2022届秋招.md index 207a5e2a..55c2a3bf 100644 --- a/problems/知识星球精选/备战2022届秋招.md +++ b/problems/知识星球精选/备战2022届秋招.md @@ -1,11 +1,11 @@

- + # 要开始准备2022届的秋招了 -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里准备秋招的录友还真不少,也会回答过不少关于秋招的问题。 +在[知识星球](https://programmercarl.com/other/kstar.html)里准备秋招的录友还真不少,也会回答过不少关于秋招的问题。 ![](https://img-blog.csdnimg.cn/20210507195443924.png) diff --git a/problems/知识星球精选/大厂新人培养体系.md b/problems/知识星球精选/大厂新人培养体系.md index ccd2f1c2..0e905e42 100644 --- a/problems/知识星球精选/大厂新人培养体系.md +++ b/problems/知识星球精选/大厂新人培养体系.md @@ -1,11 +1,11 @@

- + # 大厂的新人培养体系是什么样的 -之前我一直在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)和大家讲,能进大厂一定要进大厂,大厂有比较好的培养体系。 +之前我一直在[知识星球](https://programmercarl.com/other/kstar.html)和大家讲,能进大厂一定要进大厂,大厂有比较好的培养体系。 也有录友在星球里问我,究竟培养体系应该是什么样的呢? 大厂都会这么培养新人么? diff --git a/problems/知识星球精选/天下乌鸦一般黑.md b/problems/知识星球精选/天下乌鸦一般黑.md index 29543747..ccd1c326 100644 --- a/problems/知识星球精选/天下乌鸦一般黑.md +++ b/problems/知识星球精选/天下乌鸦一般黑.md @@ -1,6 +1,6 @@

- + @@ -8,7 +8,7 @@ 相信大家应该经常在 各大论坛啊之类的 看到对各个互联网公司的评价,有风评好的,也有风评不好的。 -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里有录友问我这样一个问题: +在[知识星球](https://programmercarl.com/other/kstar.html)里有录友问我这样一个问题: ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211004095707.png) diff --git a/problems/知识星球精选/如何权衡实习与秋招复习.md b/problems/知识星球精选/如何权衡实习与秋招复习.md index 275588df..07e2bba6 100644 --- a/problems/知识星球精选/如何权衡实习与秋招复习.md +++ b/problems/知识星球精选/如何权衡实习与秋招复习.md @@ -1,11 +1,11 @@

- + # 已经在实习的录友如何准备秋招? -最近在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)一位录友问了实习生如何权衡工作和准备秋招的问题。 +最近在[知识星球](https://programmercarl.com/other/kstar.html)一位录友问了实习生如何权衡工作和准备秋招的问题。 ![](https://code-thinking-1253855093.cos.ap-guangzhou.myqcloud.com/pics/20210703230618.png) diff --git a/problems/知识星球精选/客三消.md b/problems/知识星球精选/客三消.md index 8a7b5fc6..6b81ab2c 100644 --- a/problems/知识星球精选/客三消.md +++ b/problems/知识星球精选/客三消.md @@ -1,5 +1,5 @@

- + @@ -17,7 +17,7 @@ 然后朋友圈就炸了,上百条的留言,问我这是为啥。 -其实这个问题在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里也有录友问过我。 +其实这个问题在[知识星球](https://programmercarl.com/other/kstar.html)里也有录友问过我。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210905091037.png) @@ -87,7 +87,7 @@ # 总结 -以上就是我在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里的详细回答。 +以上就是我在[知识星球](https://programmercarl.com/other/kstar.html)里的详细回答。 注意我这里说的一般情况,当然各个岗位都有佼佼者,或者说大牛,客户端也有大牛,也很香,不过这是极少数,就不在讨论范围内了。 diff --git a/problems/知识星球精选/技术不好如何选择技术方向.md b/problems/知识星球精选/技术不好如何选择技术方向.md index dd13f46b..4ad4659b 100644 --- a/problems/知识星球精选/技术不好如何选择技术方向.md +++ b/problems/知识星球精选/技术不好如何选择技术方向.md @@ -1,11 +1,11 @@

- + # 技术不太好,也不知道对技术有没有兴趣,我该怎么选? -最近在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里解答了不少录友们的疑惑,其实发现一个挺普遍的问题: +最近在[知识星球](https://programmercarl.com/other/kstar.html)里解答了不少录友们的疑惑,其实发现一个挺普遍的问题: * 我技术很一般 * 对技术也没有什么追求 diff --git a/problems/知识星球精选/提前批已经开始了.md b/problems/知识星球精选/提前批已经开始了.md index ba05b5a9..3e255746 100644 --- a/problems/知识星球精选/提前批已经开始了.md +++ b/problems/知识星球精选/提前批已经开始了.md @@ -1,5 +1,5 @@

- + @@ -7,7 +7,7 @@ 最近华为提前批已经开始了,不少同学已经陆续参加了提前批的面试。 -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)上就有录友问我这么个问题: +在[知识星球](https://programmercarl.com/other/kstar.html)上就有录友问我这么个问题: ![](https://code-thinking-1253855093.cos.ap-guangzhou.myqcloud.com/pics/20210711002802.png) diff --git a/problems/知识星球精选/秋招下半场依然没offer.md b/problems/知识星球精选/秋招下半场依然没offer.md index 829f82ba..5862dd32 100644 --- a/problems/知识星球精选/秋招下半场依然没offer.md +++ b/problems/知识星球精选/秋招下半场依然没offer.md @@ -1,11 +1,11 @@

- + # 秋招下半场依然没offer,怎么办? -[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里一些录友拿到了满意的offer,也有一些录友,依然没有offer,每天的状态已经不能用焦虑来形容了。 +[知识星球](https://programmercarl.com/other/kstar.html)里一些录友拿到了满意的offer,也有一些录友,依然没有offer,每天的状态已经不能用焦虑来形容了。 在星球里就有录友向我提问了这样一个问题: @@ -52,7 +52,7 @@ ## 在学点技术,冲春招? -[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里还有一位录友,也是类似的情况,秋招感觉很艰难,要不要在学一学微服务分布式之类的,再冲春招。 +[知识星球](https://programmercarl.com/other/kstar.html)里还有一位录友,也是类似的情况,秋招感觉很艰难,要不要在学一学微服务分布式之类的,再冲春招。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210921103343.png) @@ -71,13 +71,13 @@ ## 给参加明年秋招录友的劝告 -其实我在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里,**看到了太多太多 参加今年秋招的录友 埋怨自己 准备的太晚了,没想到要看的东西这么多,没想到竞争这么激烈**。 +其实我在[知识星球](https://programmercarl.com/other/kstar.html)里,**看到了太多太多 参加今年秋招的录友 埋怨自己 准备的太晚了,没想到要看的东西这么多,没想到竞争这么激烈**。 所以明年参加秋招的录友,要提前就开始准备,明确自己的岗位,知道岗位的要求,制定自己的计划,然后按计划执行。 **其实多早开始准备,都不算早!** -很多在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里的准大三,研一的录友,都能在星球里感受到 秋招的竞争与激烈。 +很多在[知识星球](https://programmercarl.com/other/kstar.html)里的准大三,研一的录友,都能在星球里感受到 秋招的竞争与激烈。 所以他们也就早早的开始准备了。 @@ -87,7 +87,7 @@ 估计大多数准大三或者准研一的同学都还没有这种意识。 -**但在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里,通过每天录友们的打卡,每天都能感受到这种紧迫感**。 +**但在[知识星球](https://programmercarl.com/other/kstar.html)里,通过每天录友们的打卡,每天都能感受到这种紧迫感**。 正如一位星球里的录友这么说: diff --git a/problems/知识星球精选/秋招开奖.md b/problems/知识星球精选/秋招开奖.md index 368596b6..82686785 100644 --- a/problems/知识星球精选/秋招开奖.md +++ b/problems/知识星球精选/秋招开奖.md @@ -1,6 +1,6 @@

- + @@ -8,7 +8,7 @@ 最近秋招的录友已经陆续开奖了,同时开奖多少,也是offer选择的一个重要因素,毕竟谁能和钱过意不去呢。 -[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里这位录友拿到的百度offer薪资确实很高 +[知识星球](https://programmercarl.com/other/kstar.html)里这位录友拿到的百度offer薪资确实很高 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211023102430.png) diff --git a/problems/知识星球精选/秋招总结1.md b/problems/知识星球精选/秋招总结1.md index efec67ee..2aec24dc 100644 --- a/problems/知识星球精选/秋招总结1.md +++ b/problems/知识星球精选/秋招总结1.md @@ -1,5 +1,5 @@

- + @@ -11,7 +11,7 @@ 时间总是过得很快,但曾经焦虑的小伙,现在也拿到几个offer了,不一定人人都要冲大厂,卷算法,卷后端,合适自己就好,要不然会把自己搞的很累。 -以下是他的秋招总结,**写的很用心,说了很多面试中使用的方法,发在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里,立刻就引来星球小伙伴们的围观**,算是给星球里明年要秋招的录友做了一个参考。 +以下是他的秋招总结,**写的很用心,说了很多面试中使用的方法,发在[知识星球](https://programmercarl.com/other/kstar.html)里,立刻就引来星球小伙伴们的围观**,算是给星球里明年要秋招的录友做了一个参考。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211109231150.png) diff --git a/problems/知识星球精选/秋招总结2.md b/problems/知识星球精选/秋招总结2.md index 7f4b6770..897a7ec3 100644 --- a/problems/知识星球精选/秋招总结2.md +++ b/problems/知识星球精选/秋招总结2.md @@ -1,10 +1,10 @@ -

+

# 倒霉透顶,触底反弹! -星球里不少录友秋招已经陆续结束了,很多录友都在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里写下了自己的秋招总结,但今天这位录友很特殊,甚至我给她修改简历的时候我都“有点愁”。 +星球里不少录友秋招已经陆续结束了,很多录友都在[知识星球](https://programmercarl.com/other/kstar.html)里写下了自己的秋招总结,但今天这位录友很特殊,甚至我给她修改简历的时候我都“有点愁”。 他的秋招过程也是极其坎坷,**逼签、被养鱼最后收到感谢信、校招流程收到实习offer,还有数不清的简历挂……**,可能是太倒霉了,最后触底反弹,接到了百度的offer,虽然是白菜价,但真的很不错了。 diff --git a/problems/知识星球精选/秋招总结3.md b/problems/知识星球精选/秋招总结3.md index 895c1b8c..05a677ed 100644 --- a/problems/知识星球精选/秋招总结3.md +++ b/problems/知识星球精选/秋招总结3.md @@ -1,4 +1,4 @@ -

+

@@ -6,7 +6,7 @@ 其实无论社招,还是校招,心态都很重要,例如,别人那个一堆offer,自己陷入深深的焦虑。 面试分明感觉自己表现的不错,结果就是挂了。面试中遇到了面试官的否定,然后就开始自我怀疑,等等等。 -如果你也遇到这些问题,可以认真读完[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里一位录友的总结,他是非科班,机械转码,今年5月份加入的星球,坚持打卡几个月,如果也获得自己心仪的offer,他的心路历程对大家会很有启发。 +如果你也遇到这些问题,可以认真读完[知识星球](https://programmercarl.com/other/kstar.html)里一位录友的总结,他是非科班,机械转码,今年5月份加入的星球,坚持打卡几个月,如果也获得自己心仪的offer,他的心路历程对大家会很有启发。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211121093438.png) diff --git a/problems/知识星球精选/秋招的上半场.md b/problems/知识星球精选/秋招的上半场.md index f404e611..6c817577 100644 --- a/problems/知识星球精选/秋招的上半场.md +++ b/problems/知识星球精选/秋招的上半场.md @@ -1,11 +1,11 @@

- + # 秋招上半场的总结 -八月份已经接近尾声,不少录友已经在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) 已经总结了秋招的上半场。 +八月份已经接近尾声,不少录友已经在[知识星球](https://programmercarl.com/other/kstar.html) 已经总结了秋招的上半场。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210829214839.png) diff --git a/problems/知识星球精选/秋招进行中的迷茫与焦虑.md b/problems/知识星球精选/秋招进行中的迷茫与焦虑.md index 6083c7b1..24e7760c 100644 --- a/problems/知识星球精选/秋招进行中的迷茫与焦虑.md +++ b/problems/知识星球精选/秋招进行中的迷茫与焦虑.md @@ -1,5 +1,5 @@

- + @@ -9,7 +9,7 @@ 特别是大三的同学吧,同时面临这找工作和考研两个方向的诱惑。 -一位录友就在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)问了我这个问题: +一位录友就在[知识星球](https://programmercarl.com/other/kstar.html)问了我这个问题: ![](https://code-thinking-1253855093.cos.ap-guangzhou.myqcloud.com/pics/20210724183240.png) diff --git a/problems/知识星球精选/英语到底重不重要.md b/problems/知识星球精选/英语到底重不重要.md index 32e6a39b..5ee7fc2d 100644 --- a/problems/知识星球精选/英语到底重不重要.md +++ b/problems/知识星球精选/英语到底重不重要.md @@ -1,11 +1,11 @@

- + # 对程序员来说,英语到底重不重要 -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)有一位录友问了我这么一个问题。 +在[知识星球](https://programmercarl.com/other/kstar.html)有一位录友问了我这么一个问题。 ![](https://gitee.com/programmercarl/pics/raw/master/pic1/20210605193955.png) diff --git a/problems/知识星球精选/要不要考研.md b/problems/知识星球精选/要不要考研.md index a5f2dfa0..180e5d13 100644 --- a/problems/知识星球精选/要不要考研.md +++ b/problems/知识星球精选/要不要考研.md @@ -1,11 +1,11 @@

- + # 到底要不要读研 -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里讨论了一下关于要不要读研的问题。 +在[知识星球](https://programmercarl.com/other/kstar.html)里讨论了一下关于要不要读研的问题。 ![](https://gitee.com/programmercarl/pics/raw/master/pic1/20210613230829.png) diff --git a/problems/知识星球精选/逼签.md b/problems/知识星球精选/逼签.md index 90e4e67d..f75e3642 100644 --- a/problems/知识星球精选/逼签.md +++ b/problems/知识星球精选/逼签.md @@ -7,7 +7,7 @@ 如果是心仪的公司要求三天内签三方,我相信大家就没有被逼签的感觉了,哈哈哈 -[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)里很多录友都问我,XX公司又要逼签了,怎么办。 我在公众号也分享一下,希望对大家有所帮助。 +[知识星球](https://programmercarl.com/other/kstar.html)里很多录友都问我,XX公司又要逼签了,怎么办。 我在公众号也分享一下,希望对大家有所帮助。 ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20211017093816.png) diff --git a/problems/知识星球精选/非科班2021秋招总结.md b/problems/知识星球精选/非科班2021秋招总结.md index c2c7ed33..b92420ad 100644 --- a/problems/知识星球精选/非科班2021秋招总结.md +++ b/problems/知识星球精选/非科班2021秋招总结.md @@ -1,6 +1,6 @@

- + @@ -10,7 +10,7 @@ 其中一位录友写的很好,所以想分享出来 给公众号上的录友也看一看,相信对大家有所启发,特别是明年要找工作的录友,值得好好看一看。 -这篇总结首发在代码随想录[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)上,立刻就获得了60个赞,很多评论,我这里放出一个截图: +这篇总结首发在代码随想录[知识星球](https://programmercarl.com/other/kstar.html)上,立刻就获得了60个赞,很多评论,我这里放出一个截图: ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210929220903.png) diff --git a/problems/知识星球精选/非科班的困扰.md b/problems/知识星球精选/非科班的困扰.md index d5fea532..470b233b 100644 --- a/problems/知识星球精选/非科班的困扰.md +++ b/problems/知识星球精选/非科班的困扰.md @@ -1,11 +1,11 @@

- + # 非科班的困扰! -在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) 里很多录友都是非科班转码的,也是要准备求职,或者准备明年秋招,非科班的录友其实对 准备找工作所需要的知识不太清楚,对其难度也不太清楚,所有总感觉准备起来心里没有底。 +在[知识星球](https://programmercarl.com/other/kstar.html) 里很多录友都是非科班转码的,也是要准备求职,或者准备明年秋招,非科班的录友其实对 准备找工作所需要的知识不太清楚,对其难度也不太清楚,所有总感觉准备起来心里没有底。 例如星球里有这位录友的提问: diff --git a/problems/知识星球精选/面试中发散性问题.md b/problems/知识星球精选/面试中发散性问题.md index 7fb9150f..5cade944 100644 --- a/problems/知识星球精选/面试中发散性问题.md +++ b/problems/知识星球精选/面试中发散性问题.md @@ -1,11 +1,11 @@

- + # 面试中遇到发散性问题,应该怎么办? -这周在[知识星球](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)有一位录友问了我这么一个问题,我感觉挺有代表性的,应该不少录友在面试中不论是社招还是校招都会遇到这一类的问题。 +这周在[知识星球](https://programmercarl.com/other/kstar.html)有一位录友问了我这么一个问题,我感觉挺有代表性的,应该不少录友在面试中不论是社招还是校招都会遇到这一类的问题。 问题如下: diff --git a/problems/背包理论基础01背包-1.md b/problems/背包理论基础01背包-1.md index 6ff32017..fe940b4c 100644 --- a/problems/背包理论基础01背包-1.md +++ b/problems/背包理论基础01背包-1.md @@ -271,7 +271,7 @@ int main() { ### java ```java - public static void main(string[] args) { + public static void main(String[] args) { int[] weight = {1, 3, 4}; int[] value = {15, 20, 30}; int bagsize = 4; @@ -292,16 +292,16 @@ int main() { if (j < weight[i - 1]){ dp[i][j] = dp[i - 1][j]; }else{ - dp[i][j] = math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1]); + dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1]); } } } //打印dp数组 for (int i = 0; i <= wlen; i++){ for (int j = 0; j <= bagsize; j++){ - system.out.print(dp[i][j] + " "); + System.out.print(dp[i][j] + " "); } - system.out.print("\n"); + System.out.print("\n"); } } ``` diff --git a/problems/背包问题理论基础多重背包.md b/problems/背包问题理论基础多重背包.md index 80b9f8a1..d05c3445 100644 --- a/problems/背包问题理论基础多重背包.md +++ b/problems/背包问题理论基础多重背包.md @@ -245,7 +245,94 @@ if __name__ == '__main__': Go: +```go +package theory +import "log" + +// 多重背包可以化解为 01 背包 +func multiplePack(weight, value, nums []int, bagWeight int) int { + + for i := 0; i < len(nums); i++ { + for nums[i] > 1 { + weight = append(weight, weight[i]) + value = append(value, value[i]) + nums[i]-- + } + } + log.Println(weight) + log.Println(value) + + res := make([]int, bagWeight+1) + for i := 0; i < len(weight); i++ { + for j := bagWeight; j >= weight[i]; j-- { + res[j] = getMax(res[j], res[j-weight[i]]+value[i]) + } + log.Println(res) + } + + return res[bagWeight] +} +``` + +> 单元测试 + +```go +package theory + +import "testing" + +func Test_multiplePack(t *testing.T) { + type args struct { + weight []int + value []int + nums []int + bagWeight int + } + tests := []struct { + name string + args args + want int + }{ + { + name: "one", + args: args{ + weight: []int{1, 3, 4}, + value: []int{15, 20, 30}, + nums: []int{2, 3, 2}, + bagWeight: 10, + }, + want: 90, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := multiplePack(tt.args.weight, tt.args.value, tt.args.nums, tt.args.bagWeight); got != tt.want { + t.Errorf("multiplePack() = %v, want %v", got, tt.want) + } + }) + } +} +``` + +> 输出 + +``` +=== RUN Test_multiplePack +=== RUN Test_multiplePack/one +2022/03/02 21:09:05 [1 3 4 1 3 3 4] +2022/03/02 21:09:05 [15 20 30 15 20 20 30] +2022/03/02 21:09:05 [0 15 15 15 15 15 15 15 15 15 15] +2022/03/02 21:09:05 [0 15 15 20 35 35 35 35 35 35 35] +2022/03/02 21:09:05 [0 15 15 20 35 45 45 50 65 65 65] +2022/03/02 21:09:05 [0 15 30 30 35 50 60 60 65 80 80] +2022/03/02 21:09:05 [0 15 30 30 35 50 60 60 70 80 80] +2022/03/02 21:09:05 [0 15 30 30 35 50 60 60 70 80 80] +2022/03/02 21:09:05 [0 15 30 30 35 50 60 60 70 80 90] +--- PASS: Test_multiplePack (0.00s) + --- PASS: Test_multiplePack/one (0.00s) +PASS +``` ----------------------- diff --git a/problems/背包问题理论基础完全背包.md b/problems/背包问题理论基础完全背包.md index 7abaf160..faa1dc46 100644 --- a/problems/背包问题理论基础完全背包.md +++ b/problems/背包问题理论基础完全背包.md @@ -94,7 +94,7 @@ dp状态图如下: 看了这两个图,大家就会理解,完全背包中,两个for循环的先后循序,都不影响计算dp[j]所需要的值(这个值就是下标j之前所对应的dp[j])。 -先遍历被背包在遍历物品,代码如下: +先遍历背包在遍历物品,代码如下: ```CPP // 先遍历背包,再遍历物品