diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md index 69f8c9d6..fc14a34a 100644 --- a/problems/0028.实现strStr.md +++ b/problems/0028.实现strStr.md @@ -808,7 +808,93 @@ func strStr(haystack string, needle string) int { } ``` +JavaScript版本 +> 前缀表统一减一 + +```javascript +/** + * @param {string} haystack + * @param {string} needle + * @return {number} + */ +var strStr = function (haystack, needle) { + if (needle.length === 0) + return 0; + + const getNext = (needle) => { + let next = []; + let j = -1; + next.push(j); + + for (let i = 1; i < needle.length; ++i) { + while (j >= 0 && needle[i] !== needle[j + 1]) + j = next[j]; + if (needle[i] === needle[j + 1]) + j++; + next.push(j); + } + + return next; + } + + let next = getNext(needle); + let j = -1; + for (let i = 0; i < haystack.length; ++i) { + while (j >= 0 && haystack[i] !== needle[j + 1]) + j = next[j]; + if (haystack[i] === needle[j + 1]) + j++; + if (j === needle.length - 1) + return (i - needle.length + 1); + } + + return -1; +}; +``` + +> 前缀表统一不减一 + +```javascript +/** + * @param {string} haystack + * @param {string} needle + * @return {number} + */ +var strStr = function (haystack, needle) { + if (needle.length === 0) + return 0; + + const getNext = (needle) => { + let next = []; + let j = 0; + next.push(j); + + for (let i = 1; i < needle.length; ++i) { + while (j > 0 && needle[i] !== needle[j]) + j = next[j - 1]; + if (needle[i] === needle[j]) + j++; + next.push(j); + } + + return next; + } + + let next = getNext(needle); + let j = 0; + for (let i = 0; i < haystack.length; ++i) { + while (j > 0 && haystack[i] !== needle[j]) + j = next[j - 1]; + if (haystack[i] === needle[j]) + j++; + if (j === needle.length) + return (i - needle.length + 1); + } + + return -1; +}; +``` diff --git a/problems/0031.下一个排列.md b/problems/0031.下一个排列.md index fbe31eb3..53e6644d 100644 --- a/problems/0031.下一个排列.md +++ b/problems/0031.下一个排列.md @@ -99,6 +99,24 @@ public: ## Java ```java +class Solution { + public void nextPermutation(int[] nums) { + for (int i = nums.length - 1; i >= 0; i--) { + for (int j = nums.length - 1; j > i; j--) { + if (nums[j] > nums[i]) { + // 交换 + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + // [i + 1, nums.length) 内元素升序排序 + Arrays.sort(nums, i + 1, nums.length); + return; + } + } + } + Arrays.sort(nums); // 不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。 + } +} ``` ## Python diff --git a/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md b/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md index 04f5eaf7..f6b01dae 100644 --- a/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md +++ b/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md @@ -14,7 +14,7 @@ 如果数组中不存在目标值 target,返回 [-1, -1]。 进阶:你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗? -  + 示例 1: * 输入:nums = [5,7,7,8,8,10], target = 8 @@ -173,8 +173,105 @@ private: ## Java ```java +class Solution { + int[] searchRange(int[] nums, int target) { + int leftBorder = getLeftBorder(nums, target); + int rightBorder = getRightBorder(nums, target); + // 情况一 + if (leftBorder == -2 || rightBorder == -2) return new int[]{-1, -1}; + // 情况三 + if (rightBorder - leftBorder > 1) return new int[]{leftBorder + 1, rightBorder - 1}; + // 情况二 + return new int[]{-1, -1}; + } + + int getRightBorder(int[] nums, int target) { + int left = 0; + int right = nums.length - 1; + int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况 + while (left <= right) { + int middle = left + ((right - left) / 2); + if (nums[middle] > target) { + right = middle - 1; + } else { // 寻找右边界,nums[middle] == target的时候更新left + left = middle + 1; + rightBorder = left; + } + } + return rightBorder; + } + + int getLeftBorder(int[] nums, int target) { + int left = 0; + int right = nums.length - 1; + int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况 + while (left <= right) { + int middle = left + ((right - left) / 2); + if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right + right = middle - 1; + leftBorder = right; + } else { + left = middle + 1; + } + } + return leftBorder; + } +} ``` +```java +// 解法2 +// 1、首先,在 nums 数组中二分查找 target; +// 2、如果二分查找失败,则 binarySearch 返回 -1,表明 nums 中没有 target。此时,searchRange 直接返回 {-1, -1}; +// 3、如果二分查找成功,则 binarySearch 返回 nums 中值为 target 的一个下标。然后,通过左右滑动指针,来找到符合题意的区间 + +class Solution { + public int[] searchRange(int[] nums, int target) { + int index = binarySearch(nums, target); // 二分查找 + + if (index == -1) { // nums 中不存在 target,直接返回 {-1, -1} + return new int[] {-1, -1}; // 匿名数组 + } + // nums 中存在 targe,则左右滑动指针,来找到符合题意的区间 + int left = index; + int right = index; + // 向左滑动,找左边界 + while (left - 1 >= 0 && nums[left - 1] == nums[index]) { // 防止数组越界。逻辑短路,两个条件顺序不能换 + left--; + } + // 向左滑动,找右边界 + while (right + 1 < nums.length && nums[right + 1] == nums[index]) { // 防止数组越界。 + right++; + } + return new int[] {left, right}; + } + + /** + * 二分查找 + * @param nums + * @param target + */ + public int binarySearch(int[] nums, int target) { + int left = 0; + int right = nums.length - 1; // 不变量:左闭右闭区间 + + while (left <= right) { // 不变量:左闭右闭区间 + int mid = left + (right - left) / 2; + if (nums[mid] == target) { + return mid; + } else if (nums[mid] < target) { + left = mid + 1; + } else { + right = mid - 1; // 不变量:左闭右闭区间 + } + } + return -1; // 不存在 + } +} +``` + + + ## Python ```python @@ -196,4 +293,3 @@ private: * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
- diff --git a/problems/0053.最大子序和(动态规划).md b/problems/0053.最大子序和(动态规划).md index dd0e513b..ada378b2 100644 --- a/problems/0053.最大子序和(动态规划).md +++ b/problems/0053.最大子序和(动态规划).md @@ -138,7 +138,35 @@ class Solution: ``` Go: +```Go +// solution +// 1, dp +// 2, 贪心 +func maxSubArray(nums []int) int { + n := len(nums) + // 这里的dp[i] 表示,最大的连续子数组和,包含num[i] 元素 + dp := make([]int,n) + // 初始化,由于dp 状态转移方程依赖dp[0] + dp[0] = nums[0] + // 初始化最大的和 + mx := nums[0] + for i:=1;ib { + return a + } + return b +} +``` diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index 4c5a70a0..4bdc228d 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -654,43 +654,68 @@ class Solution { ``` Python: + 105.从前序与中序遍历序列构造二叉树 ```python -# Definition for a binary tree node. -# class TreeNode: -# def __init__(self, val=0, left=None, right=None): -# self.val = val -# self.left = left -# self.right = right -//递归法 class Solution: def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode: - if not preorder: return None //特殊情况 - root = TreeNode(preorder[0]) //新建父节点 - p=inorder.index(preorder[0]) //找到父节点在中序遍历的位置(因为没有重复的元素,才可以这样找) - root.left = self.buildTree(preorder[1:p+1],inorder[:p]) //注意左节点时分割中序数组和前续数组的开闭环 - root.right = self.buildTree(preorder[p+1:],inorder[p+1:]) //分割中序数组和前续数组 - return root + # 第一步: 特殊情况讨论: 树为空. 或者说是递归终止条件 + if not preorder: + return None + + # 第二步: 前序遍历的第一个就是当前的中间节点. + root_val = preorder[0] + root = TreeNode(root_val) + + # 第三步: 找切割点. + separator_idx = inorder.index(root_val) + + # 第四步: 切割inorder数组. 得到inorder数组的左,右半边. + inorder_left = inorder[:separator_idx] + inorder_right = inorder[separator_idx + 1:] + + # 第五步: 切割preorder数组. 得到preorder数组的左,右半边. + # ⭐️ 重点1: 中序数组大小一定跟前序数组大小是相同的. + preorder_left = preorder[1:1 + len(inorder_left)] + preorder_right = preorder[1 + len(inorder_left):] + + # 第六步: 递归 + root.left = self.buildTree(preorder_left, inorder_left) + root.right = self.buildTree(preorder_right, inorder_right) + + return root ``` 106.从中序与后序遍历序列构造二叉树 ```python -# Definition for a binary tree node. -# class TreeNode: -# def __init__(self, val=0, left=None, right=None): -# self.val = val -# self.left = left -# self.right = right -//递归法 class Solution: def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode: - if not postorder: return None //特殊情况 - root = TreeNode(postorder[-1]) //新建父节点 - p=inorder.index(postorder[-1]) //找到父节点在中序遍历的位置*因为没有重复的元素,才可以这样找 - root.left = self.buildTree(inorder[:p],postorder[:p]) //分割中序数组和后续数组 - root.right = self.buildTree(inorder[p+1:],postorder[p:-1]) //注意右节点时分割中序数组和后续数组的开闭环 - return root + # 第一步: 特殊情况讨论: 树为空. (递归终止条件) + if not postorder: + return None + + # 第二步: 后序遍历的最后一个就是当前的中间节点. + root_val = postorder[-1] + root = TreeNode(root_val) + + # 第三步: 找切割点. + separator_idx = inorder.index(root_val) + + # 第四步: 切割inorder数组. 得到inorder数组的左,右半边. + inorder_left = inorder[:separator_idx] + inorder_right = inorder[separator_idx + 1:] + + # 第五步: 切割postorder数组. 得到postorder数组的左,右半边. + # ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的. + postorder_left = postorder[:len(inorder_left)] + postorder_right = postorder[len(inorder_left): len(postorder) - 1] + + # 第六步: 递归 + root.left = self.buildTree(inorder_left, postorder_left) + root.right = self.buildTree(inorder_right, postorder_right) + + return root ``` Go: > 106 从中序与后序遍历序列构造二叉树 diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index ae9a9267..474e17da 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -416,6 +416,8 @@ class Solution { Python: 0112.路径总和 + +**递归** ```python # Definition for a binary tree node. # class TreeNode: @@ -424,28 +426,56 @@ Python: # self.left = left # self.right = right -// 递归法 - class Solution: def hasPathSum(self, root: TreeNode, targetSum: int) -> bool: - def isornot(root,targetSum)->bool: - if (not root.left) and (not root.right) and targetSum == 0:return True // 遇到叶子节点,并且计数为0 - if (not root.left) and (not root.right):return False //遇到叶子节点,计数不为0 + def isornot(root, targetSum) -> bool: + if (not root.left) and (not root.right) and targetSum == 0: + return True # 遇到叶子节点,并且计数为0 + if (not root.left) and (not root.right): + return False # 遇到叶子节点,计数不为0 if root.left: - targetSum -= root.left.val //左节点 - if isornot(root.left,targetSum):return True //递归,处理左节点 - targetSum += root.left.val //回溯 + targetSum -= root.left.val # 左节点 + if isornot(root.left, targetSum): return True # 递归,处理左节点 + targetSum += root.left.val # 回溯 if root.right: - targetSum -= root.right.val //右节点 - if isornot(root.right,targetSum):return True //递归,处理右节点 - targetSum += root.right.val //回溯 + targetSum -= root.right.val # 右节点 + if isornot(root.right, targetSum): return True # 递归,处理右节点 + targetSum += root.right.val # 回溯 return False - - if root == None:return False //别忘记处理空TreeNode - else:return isornot(root,targetSum-root.val) + + if root == None: + return False # 别忘记处理空TreeNode + else: + return isornot(root, targetSum - root.val) ``` +**迭代 - 层序遍历** +```python +class Solution: + def hasPathSum(self, root: TreeNode, targetSum: int) -> bool: + if not root: + return False + + stack = [] # [(当前节点,路径数值), ...] + stack.append((root, root.val)) + + while stack: + cur_node, path_sum = stack.pop() + + if not cur_node.left and not cur_node.right and path_sum == targetSum: + return True + + if cur_node.right: + stack.append((cur_node.right, path_sum + cur_node.right.val)) + + if cur_node.left: + stack.append((cur_node.left, path_sum + cur_node.left.val)) + + return False +``` 0113.路径总和-ii + +**递归** ```python # Definition for a binary tree node. # class TreeNode: @@ -453,35 +483,36 @@ class Solution: # self.val = val # self.left = left # self.right = right -//递归法 class Solution: def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]: - path=[] - res=[] - def pathes(root,targetSum): - if (not root.left) and (not root.right) and targetSum == 0: // 遇到叶子节点,并且计数为0 - res.append(path[:]) //找到一种路径,记录到res中,注意必须是path[:]而不是path - return - if (not root.left) and (not root.right):return // 遇到叶子节点直接返回 - if root.left: //左 - targetSum -= root.left.val - path.append(root.left.val) //递归前记录节点 - pathes(root.left,targetSum) //递归 - targetSum += root.left.val //回溯 - path.pop() //回溯 - if root.right: //右 - targetSum -= root.right.val - path.append(root.right.val) //递归前记录节点 - pathes(root.right,targetSum) //递归 - targetSum += root.right.val //回溯 - path.pop() //回溯 - return - - if root == None:return [] //处理空TreeNode - else: - path.append(root.val) //首先处理根节点 - pathes(root,targetSum-root.val) - return res + + def traversal(cur_node, remain): + if not cur_node.left and not cur_node.right and remain == 0: + result.append(path[:]) + return + + if not cur_node.left and not cur_node.right: return + + if cur_node.left: + path.append(cur_node.left.val) + remain -= cur_node.left.val + traversal(cur_node.left, remain) + path.pop() + remain += cur_node.left.val + + if cur_node.right: + path.append(cur_node.right.val) + remain -= cur_node.right.val + traversal(cur_node.right, remain) + path.pop() + remain += cur_node.right.val + + result, path = [], [] + if not root: + return [] + path.append(root.val) + traversal(root, targetSum - root.val) + return result ``` Go: diff --git a/problems/0141.环形链表.md b/problems/0141.环形链表.md index 4a40f953..0871202d 100644 --- a/problems/0141.环形链表.md +++ b/problems/0141.环形链表.md @@ -14,7 +14,7 @@ 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。 如果链表中存在环,则返回 true 。 否则,返回 false 。 -  + ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210727173600.png) # 思路 @@ -74,6 +74,21 @@ public: ## Java ```java +public class Solution { + public boolean hasCycle(ListNode head) { + ListNode fast = head; + ListNode slow = head; + // 空链表、单节点链表一定不会有环 + while (fast != null && fast.next != null) { + fast = fast.next.next; // 快指针,一次移动两步 + slow = slow.next; // 慢指针,一次移动一步 + if (fast == slow) { // 快慢指针相遇,表明有环 + return true; + } + } + return false; // 正常走到链表末尾,表明没有环 + } +} ``` ## Python diff --git a/problems/0143.重排链表.md b/problems/0143.重排链表.md index c4e8d8f7..dc0095d3 100644 --- a/problems/0143.重排链表.md +++ b/problems/0143.重排链表.md @@ -1,4 +1,3 @@ -

@@ -63,6 +62,7 @@ public: ## 方法二 把链表放进双向队列,然后通过双向队列一前一后弹出数据,来构造新的链表。这种方法比操作数组容易一些,不用双指针模拟一前一后了 + ```C++ class Solution { public: @@ -176,6 +176,51 @@ public: Java: +```java +public class ReorderList { + public void reorderList(ListNode head) { + ListNode fast = head, slow = head; + //求出中点 + while (fast.next != null && fast.next.next != null) { + slow = slow.next; + fast = fast.next.next; + } + //right就是右半部分 12345 就是45 1234 就是34 + ListNode right = slow.next; + //断开左部分和右部分 + slow.next = null; + //反转右部分 right就是反转后右部分的起点 + right = reverseList(right); + //左部分的起点 + ListNode left = head; + //进行左右部分来回连接 + //这里左部分的节点个数一定大于等于右部分的节点个数 因此只判断right即可 + while (right != null) { + ListNode curLeft = left.next; + left.next = right; + left = curLeft; + + ListNode curRight = right.next; + right.next = left; + right = curRight; + } + } + + public ListNode reverseList(ListNode head) { + ListNode headNode = new ListNode(0); + ListNode cur = head; + ListNode next = null; + while (cur != null) { + next = cur.next; + cur.next = headNode.next; + headNode.next = cur; + cur = next; + } + return headNode.next; + } +} +``` + Python: Go: @@ -183,8 +228,10 @@ Go: JavaScript: ----------------------- + * 作者微信:[程序员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/0205.同构字符串.md b/problems/0205.同构字符串.md index 4e963ece..7ffa3fbf 100644 --- a/problems/0205.同构字符串.md +++ b/problems/0205.同构字符串.md @@ -68,6 +68,25 @@ public: ## Java ```java +class Solution { + public boolean isIsomorphic(String s, String t) { + Map map1 = new HashMap<>(); + Map map2 = new HashMap<>(); + for (int i = 0, j = 0; i < s.length(); i++, j++) { + if (!map1.containsKey(s.charAt(i))) { + map1.put(s.charAt(i), t.charAt(j)); // map1保存 s[i] 到 t[j]的映射 + } + if (!map2.containsKey(t.charAt(j))) { + map2.put(t.charAt(j), s.charAt(i)); // map2保存 t[j] 到 s[i]的映射 + } + // 无法映射,返回 false + if (map1.get(s.charAt(i)) != t.charAt(j) || map2.get(t.charAt(j)) != s.charAt(i)) { + return false; + } + } + return true; + } +} ``` ## Python diff --git a/problems/0206.翻转链表.md b/problems/0206.翻转链表.md index 963d7916..4efdda3b 100644 --- a/problems/0206.翻转链表.md +++ b/problems/0206.翻转链表.md @@ -275,7 +275,50 @@ var reverseList = function(head) { }; ``` +Ruby: +```ruby +# 双指针 +# Definition for singly-linked list. +# class ListNode +# attr_accessor :val, :next +# def initialize(val = 0, _next = nil) +# @val = val +# @next = _next +# end +# end +def reverse_list(head) + # return nil if head.nil? # 循环判断条件亦能起到相同作用因此不必单独判断 + cur, per = head, nil + until cur.nil? + tem = cur.next + cur.next = per + per = cur + cur = tem + end + per +end + +# 递归 +# Definition for singly-linked list. +# class ListNode +# attr_accessor :val, :next +# def initialize(val = 0, _next = nil) +# @val = val +# @next = _next +# end +# end +def reverse_list(head) + reverse(nil, head) +end + +def reverse(pre, cur) + return pre if cur.nil? + tem = cur.next + cur.next = pre + reverse(cur, tem) # 通过递归实现双指针法中的更新操作 +end +``` ----------------------- diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md index 6890fc2b..32476d6f 100644 --- a/problems/0232.用栈实现队列.md +++ b/problems/0232.用栈实现队列.md @@ -384,7 +384,7 @@ func (this *MyQueue) Peek() int { func (this *MyQueue) Empty() bool { return len(this.stack) == 0 && len(this.back) == 0 } - +``` javaScript: @@ -442,8 +442,6 @@ MyQueue.prototype.empty = function() { ``` - - ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) diff --git a/problems/0283.移动零.md b/problems/0283.移动零.md index 56f96b2f..8db42a0a 100644 --- a/problems/0283.移动零.md +++ b/problems/0283.移动零.md @@ -64,6 +64,21 @@ public: Java: +```java +public void moveZeroes(int[] nums) { + int slow = 0; + for (int fast = 0; fast < nums.length; fast++) { + if (nums[fast] != 0) { + nums[slow++] = nums[fast]; + } + } + // 后面的元素全变成 0 + for (int j = slow; j < nums.length; j++) { + nums[j] = 0; + } + } +``` + Python: ```python diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md index aa758367..2a76a461 100644 --- a/problems/0404.左叶子之和.md +++ b/problems/0404.左叶子之和.md @@ -205,25 +205,51 @@ class Solution { Python: -```Python + **递归** -# Definition for a binary tree node. -# class TreeNode: -# def __init__(self, val=0, left=None, right=None): -# self.val = val -# self.left = left -# self.right = right +```python class Solution: def sumOfLeftLeaves(self, root: TreeNode) -> int: - self.res=0 - def areleftleaves(root): - if not root:return - if root.left and (not root.left.left) and (not root.left.right):self.res+=root.left.val - areleftleaves(root.left) - areleftleaves(root.right) - areleftleaves(root) - return self.res + if not root: + return 0 + + left_left_leaves_sum = self.sumOfLeftLeaves(root.left) # 左 + right_left_leaves_sum = self.sumOfLeftLeaves(root.right) # 右 + + cur_left_leaf_val = 0 + if root.left and not root.left.left and not root.left.right: + cur_left_leaf_val = root.left.val # 中 + + return cur_left_leaf_val + left_left_leaves_sum + right_left_leaves_sum ``` + +**迭代** +```python +class Solution: + def sumOfLeftLeaves(self, root: TreeNode) -> int: + """ + Idea: Each time check current node's left node. + If current node don't have one, skip it. + """ + stack = [] + if root: + stack.append(root) + res = 0 + + while stack: + # 每次都把当前节点的左节点加进去. + cur_node = stack.pop() + if cur_node.left and not cur_node.left.left and not cur_node.left.right: + res += cur_node.left.val + + if cur_node.left: + stack.append(cur_node.left) + if cur_node.right: + stack.append(cur_node.right) + + return res +``` + Go: > 递归法 diff --git a/problems/0435.无重叠区间.md b/problems/0435.无重叠区间.md index 37bb0b5d..d32c2ebb 100644 --- a/problems/0435.无重叠区间.md +++ b/problems/0435.无重叠区间.md @@ -211,6 +211,29 @@ class Solution { } ``` +Java: +按左边排序,不管右边顺序。相交的时候取最小的右边。 +```java +class Solution { + public int eraseOverlapIntervals(int[][] intervals) { + + Arrays.sort(intervals,(a,b)->{ + return Integer.compare(a[0],b[0]); + }); + int remove = 0; + int pre = intervals[0][1]; + for(int i=1;iintervals[i][0]) { + remove++; + pre = Math.min(pre,intervals[i][1]); + } + else pre = intervals[i][1]; + } + return remove; + } +} +``` + Python: ```python class Solution: diff --git a/problems/0459.重复的子字符串.md b/problems/0459.重复的子字符串.md index f012811d..25b52e86 100644 --- a/problems/0459.重复的子字符串.md +++ b/problems/0459.重复的子字符串.md @@ -289,8 +289,79 @@ func repeatedSubstringPattern(s string) bool { } ``` +JavaScript版本 +> 前缀表统一减一 +```javascript +/** + * @param {string} s + * @return {boolean} + */ +var repeatedSubstringPattern = function (s) { + if (s.length === 0) + return false; + + const getNext = (s) => { + let next = []; + let j = -1; + + next.push(j); + + for (let i = 1; i < s.length; ++i) { + while (j >= 0 && s[i] !== s[j + 1]) + j = next[j]; + if (s[i] === s[j + 1]) + j++; + next.push(j); + } + + return next; + } + + let next = getNext(s); + + if (next[next.length - 1] !== -1 && s.length % (s.length - (next[next.length - 1] + 1)) === 0) + return true; + return false; +}; +``` + +> 前缀表统一不减一 + +```javascript +/** + * @param {string} s + * @return {boolean} + */ +var repeatedSubstringPattern = function (s) { + if (s.length === 0) + return false; + + const getNext = (s) => { + let next = []; + let j = 0; + + next.push(j); + + for (let i = 1; i < s.length; ++i) { + while (j > 0 && s[i] !== s[j]) + j = next[j - 1]; + if (s[i] === s[j]) + j++; + next.push(j); + } + + return next; + } + + let next = getNext(s); + + if (next[next.length - 1] !== 0 && s.length % (s.length - next[next.length - 1]) === 0) + return true; + return false; +}; +``` diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index 17d15fde..27c6e83c 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -274,27 +274,51 @@ class Solution { Python: + +**递归 - 回溯** ```python -//递归法 -# Definition for a binary tree node. -# class TreeNode: -# def __init__(self, val=0, left=None, right=None): -# self.val = val -# self.left = left -# self.right = right class Solution: def findBottomLeftValue(self, root: TreeNode) -> int: - depth=0 - self.res=[] - def level(root,depth): - if not root:return - if depth==len(self.res): - self.res.append([]) - self.res[depth].append(root.val) - level(root.left,depth+1) - level(root.right,depth+1) - level(root,depth) - return self.res[-1][0] + max_depth = -float("INF") + leftmost_val = 0 + + def __traverse(root, cur_depth): + nonlocal max_depth, leftmost_val + if not root.left and not root.right: + if cur_depth > max_depth: + max_depth = cur_depth + leftmost_val = root.val + if root.left: + cur_depth += 1 + __traverse(root.left, cur_depth) + cur_depth -= 1 + if root.right: + cur_depth += 1 + __traverse(root.right, cur_depth) + cur_depth -= 1 + + __traverse(root, 0) + return leftmost_val +``` +**迭代 - 层序遍历** +```python +class Solution: + def findBottomLeftValue(self, root: TreeNode) -> int: + queue = deque() + if root: + queue.append(root) + result = 0 + while queue: + q_len = len(queue) + for i in range(q_len): + if i == 0: + result = queue[i].val + cur = queue.popleft() + if cur.left: + queue.append(cur.left) + if cur.right: + queue.append(cur.right) + return result ``` Go: diff --git a/problems/0657.机器人能否返回原点.md b/problems/0657.机器人能否返回原点.md index cd26836c..9b43ea6c 100644 --- a/problems/0657.机器人能否返回原点.md +++ b/problems/0657.机器人能否返回原点.md @@ -71,21 +71,84 @@ public: ## Java ```java +// 时间复杂度:O(n) +// 空间复杂度:如果采用 toCharArray,则是 O(n);如果使用 charAt,则是 O(1) +class Solution { + public boolean judgeCircle(String moves) { + int x = 0; + int y = 0; + for (char c : moves.toCharArray()) { + if (c == 'U') y++; + if (c == 'D') y--; + if (c == 'L') x++; + if (c == 'R') x--; + } + return x == 0 && y == 0; + } +} ``` ## Python ```python +# 时间复杂度:O(n) +# 空间复杂度:O(1) +class Solution: + def judgeCircle(self, moves: str) -> bool: + x = 0 # 记录当前位置 + y = 0 + for i in range(len(moves)): + if (moves[i] == 'U'): + y += 1 + if (moves[i] == 'D'): + y -= 1 + if (moves[i] == 'L'): + x += 1 + if (moves[i] == 'R'): + x -= 1 + return x == 0 and y == 0 ``` ## Go ```go +func judgeCircle(moves string) bool { + x := 0 + y := 0 + for i := 0; i < len(moves); i++ { + if moves[i] == 'U' { + y++ + } + if moves[i] == 'D' { + y-- + } + if moves[i] == 'L' { + x++ + } + if moves[i] == 'R' { + x-- + } + } + return x == 0 && y == 0; +} ``` ## JavaScript ```js +// 时间复杂度:O(n) +// 空间复杂度:O(1) +var judgeCircle = function(moves) { + var x = 0; // 记录当前位置 + var y = 0; + for (var i = 0; i < moves.length; i++) { + if (moves[i] == 'U') y++; + if (moves[i] == 'D') y--; + if (moves[i] == 'L') x++; + if (moves[i] == 'R') x--; + } + return x == 0 && y == 0; +}; ``` ----------------------- diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index cce471ae..ed0e2eed 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -235,8 +235,6 @@ class Solution: return -1 ``` - - **Go:** (版本一)左闭右闭区间 @@ -279,7 +277,7 @@ func search(nums []int, target int) int { } ``` -**javaScript:** +**JavaScript:** ```js @@ -316,7 +314,43 @@ var search = function(nums, target) { ``` +**Ruby:** +```ruby +# (版本一)左闭右闭区间 + +def search(nums, target) + left, right = 0, nums.length - 1 + while left <= right # 由于定义target在一个在左闭右闭的区间里,因此极限情况下存在left==right + middle = (left + right) / 2 + if nums[middle] > target + right = middle - 1 + elsif nums[middle] < target + left = middle + 1 + else + return middle # return兼具返回与跳出循环的作用 + end + end + -1 +end + +# (版本二)左闭右开区间 + +def search(nums, target) + left, right = 0, nums.length + while left < right # 由于定义target在一个在左闭右开的区间里,因此极限情况下right=left+1 + middle = (left + right) / 2 + if nums[middle] > target + right = middle + elsif nums[middle] < target + left = middle + 1 + else + return middle + end + end + -1 +end +``` diff --git a/problems/0718.最长重复子数组.md b/problems/0718.最长重复子数组.md index 9ee94a3d..959ed39e 100644 --- a/problems/0718.最长重复子数组.md +++ b/problems/0718.最长重复子数组.md @@ -252,6 +252,33 @@ func findLength(A []int, B []int) int { } ``` +JavaScript: + +> 动态规划 + +```javascript +const findLength = (A, B) => { + // A、B数组的长度 + const [m, n] = [A.length, B.length]; + // dp数组初始化,都初始化为0 + const dp = new Array(m + 1).fill(0).map(x => new Array(n + 1).fill(0)); + // 初始化最大长度为0 + let res = 0; + for (let i = 1; i <= m; i++) { + for (let j = 1; j <= n; j++) { + // 遇到A[i - 1] === B[j - 1],则更新dp数组 + if (A[i - 1] === B[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } + // 更新res + res = dp[i][j] > res ? dp[i][j] : res; + } + } + // 遍历完成,返回res + return res; +}; +``` + ----------------------- diff --git a/problems/0724.寻找数组的中心索引.md b/problems/0724.寻找数组的中心索引.md index bf989979..09966e05 100644 --- a/problems/0724.寻找数组的中心索引.md +++ b/problems/0724.寻找数组的中心索引.md @@ -67,6 +67,24 @@ public: ## Java ```java +class Solution { + public int pivotIndex(int[] nums) { + int sum = 0; + for (int i = 0; i < nums.length; i++) { + sum += nums[i]; // 总和 + } + int leftSum = 0; + int rightSum = 0; + for (int i = 0; i < nums.length; i++) { + leftSum += nums[i]; + rightSum = sum - leftSum + nums[i]; // leftSum 里面已经有 nums[i],多减了一次,所以加上 + if (leftSum == rightSum) { + return i; + } + } + return -1; // 不存在 + } +} ``` ## Python @@ -90,4 +108,3 @@ public: * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
- diff --git a/problems/0844.比较含退格的字符串.md b/problems/0844.比较含退格的字符串.md index 9f37959d..4b4ff63b 100644 --- a/problems/0844.比较含退格的字符串.md +++ b/problems/0844.比较含退格的字符串.md @@ -14,7 +14,7 @@ 给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。 注意:如果对空文本输入退格字符,文本继续为空。 -  + 示例 1: * 输入:S = "ab#c", T = "ad#c" * 输出:true @@ -160,6 +160,32 @@ public: Java: +```java +// 普通方法(使用栈的思路) +class Solution { + public boolean backspaceCompare(String s, String t) { + StringBuilder ssb = new StringBuilder(); // 模拟栈 + StringBuilder tsb = new StringBuilder(); // 模拟栈 + // 分别处理两个 String + for (char c : s.toCharArray()) { + if (c != '#') { + ssb.append(c); // 模拟入栈 + } else if (ssb.length() > 0){ // 栈非空才能弹栈 + ssb.deleteCharAt(ssb.length() - 1); // 模拟弹栈 + } + } + for (char c : t.toCharArray()) { + if (c != '#') { + tsb.append(c); // 模拟入栈 + } else if (tsb.length() > 0){ // 栈非空才能弹栈 + tsb.deleteCharAt(tsb.length() - 1); // 模拟弹栈 + } + } + return ssb.toString().equals(tsb.toString()); + } +} +``` + Python: Go: diff --git a/problems/0922.按奇偶排序数组II.md b/problems/0922.按奇偶排序数组II.md index bb609c12..d4c1be7a 100644 --- a/problems/0922.按奇偶排序数组II.md +++ b/problems/0922.按奇偶排序数组II.md @@ -120,6 +120,31 @@ public: ## Java ```java +// 方法一 +class Solution { + public int[] sortArrayByParityII(int[] nums) { + // 分别存放 nums 中的奇数、偶数 + int len = nums.length; + int evenIndex = 0; + int oddIndex = 0; + int[] even = new int[len / 2]; + int[] odd = new int[len / 2]; + for (int i = 0; i < len; i++) { + if (nums[i] % 2 == 0) { + even[evenIndex++] = nums[i]; + } else { + odd[oddIndex++] = nums[i]; + } + } + // 把奇偶数组重新存回 nums + int index = 0; + for (int i = 0; i < even.length; i++) { + nums[index++] = even[i]; + nums[index++] = odd[i]; + } + return nums; + } +} ``` ## Python @@ -143,4 +168,3 @@ public: * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
- diff --git a/problems/0941.有效的山脉数组.md b/problems/0941.有效的山脉数组.md index 6dbc3da2..167cfb1a 100644 --- a/problems/0941.有效的山脉数组.md +++ b/problems/0941.有效的山脉数组.md @@ -18,7 +18,7 @@ https://leetcode-cn.com/problems/valid-mountain-array/ C++代码如下: -``` +```c++ class Solution { public: bool validMountainArray(vector& A) { @@ -38,6 +38,33 @@ public: } }; ``` +Java 版本如下: + +```java +class Solution { + public boolean validMountainArray(int[] arr) { + if (arr.length < 3) { // 此时,一定不是有效的山脉数组 + return false; + } + // 双指针 + int left = 0; + int right = arr.length - 1; + // 注意防止指针越界 + while (left + 1 < arr.length && arr[left] < arr[left + 1]) { + left++; + } + // 注意防止指针越界 + while (right > 0 && arr[right] < arr[right - 1]) { + right--; + } + // 如果left或者right都在起始位置,说明不是山峰 + if (left == right && left != 0 && right != arr.length - 1) { + return true; + } + return false; + } +} +``` + 如果想系统学一学双指针的话, 可以看一下这篇[双指针法:总结篇!](https://mp.weixin.qq.com/s/_p7grwjISfMh0U65uOyCjA) - diff --git a/problems/1207.独一无二的出现次数.md b/problems/1207.独一无二的出现次数.md index 377d9ebf..c1720430 100644 --- a/problems/1207.独一无二的出现次数.md +++ b/problems/1207.独一无二的出现次数.md @@ -77,6 +77,28 @@ public: Java: +```java +class Solution { + public boolean uniqueOccurrences(int[] arr) { + int[] count = new int[2002]; + for (int i = 0; i < arr.length; i++) { + count[arr[i] + 1000]++; // 防止负数作为下标 + } + boolean[] flag = new boolean[1002]; // 标记相同频率是否重复出现 + for (int i = 0; i <= 2000; i++) { + if (count[i] > 0) { + if (flag[count[i]] == false) { + flag[count[i]] = true; + } else { + return false; + } + } + } + return true; + } +} +``` + Python: Go: @@ -89,4 +111,3 @@ JavaScript: * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
- diff --git a/problems/1356.根据数字二进制下1的数目排序.md b/problems/1356.根据数字二进制下1的数目排序.md index e464f716..a3d724fa 100644 --- a/problems/1356.根据数字二进制下1的数目排序.md +++ b/problems/1356.根据数字二进制下1的数目排序.md @@ -16,7 +16,7 @@ 换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 nums[j] < nums[i] 。 以数组形式返回答案。 -  + 示例 1: 输入:nums = [8,1,2,2,3] @@ -35,7 +35,7 @@ 示例 3: 输入:nums = [7,7,7,7] 输出:[0,0,0,0] -  + 提示: * 2 <= nums.length <= 500 * 0 <= nums[i] <= 100 @@ -120,8 +120,51 @@ public: ## Java ```java +/** +* 解法一:暴力 +* 时间复杂度:O(n^2) +* 空间复杂度:O(n) +*/ +class Solution { + public int[] smallerNumbersThanCurrent(int[] nums) { + int[] res = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { + for (int j = 0; j < nums.length; j++) { + if (nums[j] < nums[i] && j != i) { // 注意 j 不能和 i 重合 + res[i]++; + } + } + } + return res; + } +} ``` +```java +/** +* 优化:排序 + 哈希表 +* 时间复杂度:O(nlogn) +* 空间复杂度:O(n) +*/ +class Solution { + public int[] smallerNumbersThanCurrent(int[] nums) { + int[] res = Arrays.copyOf(nums, nums.length); + Arrays.sort(res); // 是对 res 排序,nums 中顺序还要保持 + int[] hash = new int[101]; // 使用哈希表,记录比当前元素小的元素个数 + for (int i = res.length - 1; i >= 0; i--) { // 注意:从后向前 + hash[res[i]] = i; // 排序后,当前下标即表示比当前元素小的元素个数 + } + // 此时 hash中保存的每一个元素数值 便是 小于这个数值的个数 + for (int i = 0; i < res.length; i++) { + res[i] = hash[nums[i]]; + } + return res; + } +} +``` + + + ## Python ```python @@ -143,4 +186,3 @@ public: * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
- diff --git a/problems/二叉树的递归遍历.md b/problems/二叉树的递归遍历.md index 2b5a44dd..220ccf65 100644 --- a/problems/二叉树的递归遍历.md +++ b/problems/二叉树的递归遍历.md @@ -222,7 +222,7 @@ Go: 前序遍历: ```go -func PreorderTraversal(root *TreeNode) (res []int) { +func preorderTraversal(root *TreeNode) (res []int) { var traversal func(node *TreeNode) traversal = func(node *TreeNode) { if node == nil { @@ -240,7 +240,7 @@ func PreorderTraversal(root *TreeNode) (res []int) { 中序遍历: ```go -func InorderTraversal(root *TreeNode) (res []int) { +func inorderTraversal(root *TreeNode) (res []int) { var traversal func(node *TreeNode) traversal = func(node *TreeNode) { if node == nil { @@ -257,7 +257,7 @@ func InorderTraversal(root *TreeNode) (res []int) { 后序遍历: ```go -func PostorderTraversal(root *TreeNode) (res []int) { +func postorderTraversal(root *TreeNode) (res []int) { var traversal func(node *TreeNode) traversal = func(node *TreeNode) { if node == nil { diff --git a/problems/剑指Offer58-II.左旋转字符串.md b/problems/剑指Offer58-II.左旋转字符串.md index 3c3eaef0..fe4c3473 100644 --- a/problems/剑指Offer58-II.左旋转字符串.md +++ b/problems/剑指Offer58-II.左旋转字符串.md @@ -165,6 +165,22 @@ func reverse(b []byte, left, right int){ ``` +JavaScript: + +```javascript +var reverseLeftWords = function (s, n) { + const reverse = (str, left, right) => { + let strArr = str.split(""); + for (; left < right; left++, right--) { + [strArr[left], strArr[right]] = [strArr[right], strArr[left]]; + } + return strArr.join(""); + } + s = reverse(s, 0, n - 1); + s = reverse(s, n, s.length - 1); + return reverse(s, 0, s.length - 1); +}; +```