diff --git a/problems/0001.两数之和.md b/problems/0001.两数之和.md index 77318294..4a1a987f 100644 --- a/problems/0001.两数之和.md +++ b/problems/0001.两数之和.md @@ -136,6 +136,21 @@ func twoSum(nums []int, target int) []int { } ``` +```go +// 使用map方式解题,降低时间复杂度 +func twoSum(nums []int, target int) []int { + m := make(map[int]int) + for index, val := range nums { + if preIndex, ok := m[target-val]; ok { + return []int{preIndex, index} + } else { + m[val] = index + } + } + return []int{} +} +``` + Rust ```rust diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md index 643f6055..59ded523 100644 --- a/problems/0024.两两交换链表中的节点.md +++ b/problems/0024.两两交换链表中的节点.md @@ -129,6 +129,23 @@ class Solution { ``` Python: +```python +class Solution: + def swapPairs(self, head: ListNode) -> ListNode: + dummy = ListNode(0) #设置一个虚拟头结点 + dummy.next = head + cur = dummy + while cur.next and cur.next.next: + tmp = cur.next #记录临时节点 + tmp1 = cur.next.next.next #记录临时节点 + + cur.next = cur.next.next #步骤一 + cur.next.next = tmp #步骤二 + cur.next.next.next = tmp1 #步骤三 + + cur = cur.next.next #cur移动两位,准备下一轮交换 + return dummy.next +``` Go: ```go diff --git a/problems/0039.组合总和.md b/problems/0039.组合总和.md index 0eba785f..e1023ec9 100644 --- a/problems/0039.组合总和.md +++ b/problems/0039.组合总和.md @@ -237,34 +237,28 @@ public: Java: ```Java +// 剪枝优化 class Solution { - List> lists = new ArrayList<>(); - Deque deque = new LinkedList<>(); - - public List> combinationSum3(int k, int n) { - int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; - backTracking(arr, n, k, 0); - return lists; + public List> combinationSum(int[] candidates, int target) { + List> res = new ArrayList<>(); + Arrays.sort(candidates); // 先进行排序 + backtracking(res, new ArrayList<>(), candidates, target, 0, 0); + return res; } - public void backTracking(int[] arr, int n, int k, int startIndex) { - //如果 n 小于0,没必要继续本次递归,已经不符合要求了 - if (n < 0) { + public void backtracking(List> res, List path, int[] candidates, int target, int sum, int idx) { + // 找到了数字和为 target 的组合 + if (sum == target) { + res.add(new ArrayList<>(path)); return; } - if (deque.size() == k) { - if (n == 0) { - lists.add(new ArrayList(deque)); - } - return; - } - for (int i = startIndex; i < arr.length - (k - deque.size()) + 1; i++) { - deque.push(arr[i]); - //减去当前元素 - n -= arr[i]; - backTracking(arr, n, k, i + 1); - //恢复n - n += deque.pop(); + + for (int i = idx; i < candidates.length; i++) { + // 如果 sum + candidates[i] > target 就终止遍历 + if (sum + candidates[i] > target) break; + path.add(candidates[i]); + backtracking(res, path, candidates, target, sum + candidates[i], i); + path.remove(path.size() - 1); // 回溯,移除路径 path 最后一个元素 } } } diff --git a/problems/0045.跳跃游戏II.md b/problems/0045.跳跃游戏II.md index 31b52b31..4128da4c 100644 --- a/problems/0045.跳跃游戏II.md +++ b/problems/0045.跳跃游戏II.md @@ -208,6 +208,26 @@ func jump(nums []int) int { } return dp[len(nums)-1] } +``` + +Javascript: +```Javascript +var jump = function(nums) { + let curIndex = 0 + let nextIndex = 0 + let steps = 0 + for(let i = 0; i < nums.length - 1; i++) { + nextIndex = Math.max(nums[i] + i, nextIndex) + if(i === curIndex) { + curIndex = nextIndex + steps++ + } + } + + return steps +}; +``` + /* dp[i]表示从起点到当前位置的最小跳跃次数 dp[i]=min(dp[j]+1,dp[i]) 表示从j位置用一步跳跃到当前位置,这个j位置可能有很多个,却最小一个就可以 diff --git a/problems/0056.合并区间.md b/problems/0056.合并区间.md index eb8e7bff..d4ffc554 100644 --- a/problems/0056.合并区间.md +++ b/problems/0056.合并区间.md @@ -141,16 +141,7 @@ Java: class Solution { public int[][] merge(int[][] intervals) { List res = new LinkedList<>(); - Arrays.sort(intervals, new Comparator() { - @Override - public int compare(int[] o1, int[] o2) { - if (o1[0] != o2[0]) { - return Integer.compare(o1[0],o2[0]); - } else { - return Integer.compare(o1[1],o2[1]); - } - } - }); + Arrays.sort(intervals, (o1, o2) -> Integer.compare(o1[0], o2[0])); int start = intervals[0][0]; for (int i = 1; i < intervals.length; i++) { diff --git a/problems/0101.对称二叉树.md b/problems/0101.对称二叉树.md index d8797d30..b58cef2e 100644 --- a/problems/0101.对称二叉树.md +++ b/problems/0101.对称二叉树.md @@ -363,6 +363,54 @@ Python: Go: +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +// 递归 +func defs(left *TreeNode, right *TreeNode) bool { + if left == nil && right == nil { + return true; + }; + if left == nil || right == nil { + return false; + }; + if left.Val != right.Val { + return false; + } + return defs(left.Left, right.Right) && defs(right.Left, left.Right); +} +func isSymmetric(root *TreeNode) bool { + return defs(root.Left, root.Right); +} + +// 迭代 +func isSymmetric(root *TreeNode) bool { + var queue []*TreeNode; + if root != nil { + queue = append(queue, root.Left, root.Right); + } + for len(queue) > 0 { + left := queue[0]; + right := queue[1]; + queue = queue[2:]; + if left == nil && right == nil { + continue; + } + if left == nil || right == nil || left.Val != right.Val { + return false; + }; + queue = append(queue, left.Left, right.Right, right.Left, left.Right); + } + return true; +} +``` + JavaScript ```javascript diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index ee93911e..51bd8510 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -836,6 +836,249 @@ func levelOrder(root *TreeNode) [][]int { return result } ``` +> 二叉树的层序遍历(GO语言完全版) + +```go +/** +102. 二叉树的层序遍历 + */ +func levelOrder(root *TreeNode) [][]int { + res:=[][]int{} + if root==nil{//防止为空 + return res + } + queue:=list.New() + queue.PushBack(root) + var tmpArr []int + for queue.Len()>0 { + length:=queue.Len()//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数) + for i:=0;i0{ + length:=queue.Len() + tmp:=[]int{} + for i:=0;i0{ + length:=queue.Len() + tmp:=[]int{} + for i:=0;i0 { + length:=queue.Len()//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数) + for i:=0;i0{ + length:=queue.Len()//记录当前层的数量 + var tmp []int + for T:=0;T0 { + length:=queue.Len()//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数) + for i:=0;i max { + max = val + } + } + return max +} +/** +116. 填充每个节点的下一个右侧节点指针 +117. 填充每个节点的下一个右侧节点指针 II + */ + +func connect(root *Node) *Node { + res:=[][]*Node{} + if root==nil{//防止为空 + return root + } + queue:=list.New() + queue.PushBack(root) + var tmpArr []*Node + for queue.Len()>0 { + length:=queue.Len()//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数) + for i:=0;i 二叉树的层序遍历(Javascript语言完全版) (迭代 + 递归) + +```js +/** + * 102. 二叉树的层序遍历 + * @param {TreeNode} root + * @return {number[][]} + */ + +// 迭代 + +var levelOrder = function(root) { + const queue = [], res = []; + root && queue.push(root); + while(len = queue.length) { + const val = []; + while(len--) { + const node = queue.shift(); + val.push(node.val); + node.left && queue.push(node.left); + node.right && queue.push(node.right); + } + res.push(val); + } + return res; +}; + +// 递归 +var levelOrder = function(root) { + const res = []; + function defs (root, i) { + if(!root) return; + if(!res[i]) res[i] = []; + res[i].push(root.val) + root.left && defs(root.left, i + 1); + root.right && defs(root.right, i + 1); + } + defs(root, 0); + return res; +}; + + +/** + * 107. 二叉树的层序遍历 II + * @param {TreeNode} root + * @return {number[][]} + */ + +// 迭代 + +var levelOrderBottom = function(root) { + const queue = [], res = []; + root && queue.push(root); + while(len = queue.length) { + const val = []; + while(len--) { + const node = queue.shift(); + val.push(node.val); + node.left && queue.push(node.left); + node.right && queue.push(node.right); + } + res.push(val); + } + return res.reverse() +}; + +// 递归 + +var levelOrderBottom = function(root) { + const res = []; + function defs (root, i) { + if(!root) return; + if(!res[i]) res[i] = []; + res[i].push(root.val); + root.left && defs(root.left, i + 1); + root.right && defs(root.right, i + 1); + } + defs(root, 0); + return res.reverse(); +}; + +/** + * 199. 二叉树的右视图 + * @param {TreeNode} root + * @return {number[]} + */ + +// 迭代 + +var rightSideView = function(root) { + const res = [], queue = []; + root && queue.push(root); + while(l = queue.length) { + while (l--) { + const {val, left, right} = queue.shift(); + !l && res.push(val); + left && queue.push(left); + right && queue.push(right); + } + } + return res; +}; + +// 递归 +var rightSideView = function(root) { + const res = []; + function defs(root, i) { + if(!root) return; + res[i] = root.val; + root.left && defs(root.left, i + 1); + root.right && defs(root.right, i + 1); + } + defs(root, 0); + return res; +}; + +/** + * 637. 二叉树的层平均值 + * @param {TreeNode} root + * @return {number[]} + */ + +// 迭代 +var averageOfLevels = function(root) { + const queue = [], res = []; + root && queue.push(root); + while(len = queue.length) { + let sum = 0, l = len; + while(l--) { + const {val, left, right} = queue.shift(); + sum += val; + left && queue.push(left); + right && queue.push(right); + } + res.push(sum/len); + } + return res; +}; + +// 递归 +var averageOfLevels = function(root) { + const resCount = [], res = []; + function defs(root, i) { + if(!root) return; + if(isNaN(res[i])) resCount[i] = res[i] = 0; + res[i] += root.val; + resCount[i]++; + root.left && defs(root.left, i + 1); + root.right && defs(root.right, i + 1); + } + defs(root, 0); + return res.map((val, i) => val / resCount[i]); +}; + +/** + * 515. 在每个树行中找最大值 + * @param {TreeNode} root + * @return {number[]} + */ + +// 迭代 +const MIN_G = Number.MIN_SAFE_INTEGER; +var largestValues = function(root) { + const queue = [], res = []; + root && queue.push(root); + while(len = queue.length) { + let max = MIN_G; + while(len--) { + const {val, left, right} = queue.shift(); + max = max > val ? max : val; + left && queue.push(left); + right && queue.push(right); + } + res.push(max); + } + return res; +}; + +// 递归 +var largestValues = function(root) { + const res = []; + function defs (root, i) { + if(!root) return; + if(isNaN(res[i])) res[i] = root.val; + res[i] = res[i] > root.val ? res[i] : root.val; + root.left && defs(root.left, i + 1); + root.right && defs(root.right, i + 1); + } + defs(root, 0); + return res; +}; + +/** + * 429. N 叉树的层序遍历 + * @param {Node|null} root + * @return {number[][]} + */ + +// 迭代 +var levelOrder = function(root) { + const queue = [], res = []; + root && queue.push(root); + while(len = queue.length) { + const vals = []; + while(len--) { + const {val, children} = queue.shift(); + vals.push(val); + for(const e of children) { + queue.push(e); + } + } + res.push(vals); + } + return res; +}; + +// 递归 + +var levelOrder = function(root) { + const res = []; + function defs (root, i) { + if(!root) return; + if(!res[i]) res[i] = []; + res[i].push(root.val); + for(const e of root.children) { + defs(e, i + 1); + } + } + defs(root, 0); + return res; +}; + +/** + * 116. 填充每个节点的下一个右侧节点指针 + * 117. 填充每个节点的下一个右侧节点指针 II + * @param {Node} root + * @return {Node} + */ + +// 迭代 +var connect = function(root) { + const queue = []; + root && queue.push(root); + while(len = queue.length) { + while(len--) { + const node1 = queue.shift(), + node2 = len ? queue[0] : null; + node1.next = node2; + node1.left && queue.push(node1.left); + node1.right && queue.push(node1.right); + } + } + return root; +}; + +// 递归 +var connect = function(root) { + const res = []; + function defs (root, i) { + if(!root) return; + if(res[i]) res[i].next = root; + res[i] = root; + root.left && defs(root.left, i + 1); + root.right && defs(root.right, i + 1); + } + defs(root, 0); + return root; +}; +``` + ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) diff --git a/problems/0104.二叉树的最大深度.md b/problems/0104.二叉树的最大深度.md index 756afb68..5f0fe411 100644 --- a/problems/0104.二叉树的最大深度.md +++ b/problems/0104.二叉树的最大深度.md @@ -284,6 +284,55 @@ Python: Go: +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func max (a, b int) int { + if a > b { + return a; + } + return b; +} +// 递归 +func maxDepth(root *TreeNode) int { + if root == nil { + return 0; + } + return max(maxDepth(root.Left), maxDepth(root.Right)) + 1; +} + +// 遍历 +func maxDepth(root *TreeNode) int { + levl := 0; + queue := make([]*TreeNode, 0); + if root != nil { + queue = append(queue, root); + } + for l := len(queue); l > 0; { + for ;l > 0;l-- { + node := queue[0]; + if node.Left != nil { + queue = append(queue, node.Left); + } + if node.Right != nil { + queue = append(queue, node.Right); + } + queue = queue[1:]; + } + levl++; + l = len(queue); + } + return levl; +} + +``` + JavaScript ```javascript diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md index 8ee15eac..48795722 100644 --- a/problems/0111.二叉树的最小深度.md +++ b/problems/0111.二叉树的最小深度.md @@ -301,6 +301,64 @@ class Solution: Go: +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func min(a, b int) int { + if a < b { + return a; + } + return b; +} +// 递归 +func minDepth(root *TreeNode) int { + if root == nil { + return 0; + } + if root.Left == nil && root.Right != nil { + return 1 + minDepth(root.Right); + } + if root.Right == nil && root.Left != nil { + return 1 + minDepth(root.Left); + } + return min(minDepth(root.Left), minDepth(root.Right)) + 1; +} + +// 迭代 + +func minDepth(root *TreeNode) int { + dep := 0; + queue := make([]*TreeNode, 0); + if root != nil { + queue = append(queue, root); + } + for l := len(queue); l > 0; { + dep++; + for ; l > 0; l-- { + node := queue[0]; + if node.Left == nil && node.Right == nil { + return dep; + } + if node.Left != nil { + queue = append(queue, node.Left); + } + if node.Right != nil { + queue = append(queue, node.Right); + } + queue = queue[1:]; + } + l = len(queue); + } + return dep; +} +``` + JavaScript: diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index b4a3f38b..4ccd8912 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -524,6 +524,62 @@ let pathSum = function (root, targetSum) { }; ``` +0112 路径总和 +```javascript +var hasPathSum = function(root, targetSum) { + //递归方法 + // 1. 确定函数参数 + const traversal = function(node,count){ + // 2. 确定终止条件 + if(node.left===null&&node.right===null&&count===0){ + return true; + } + if(node.left===null&&node.right===null){ + return false; + } + //3. 单层递归逻辑 + if(node.left){ + if(traversal(node.left,count-node.left.val)){ + return true; + } + } + if(node.right){ + if(traversal(node.right,count-node.right.val)){ + return true; + } + } + return false; + } + if(root===null){ + return false; + } + return traversal(root,targetSum-root.val); +}; +``` +113 路径总和 +```javascript +var pathSum = function(root, targetSum) { + //递归方法 + let resPath = [],curPath = []; + // 1. 确定递归函数参数 + const travelTree = function(node,count){ + curPath.push(node.val); + count-=node.val; + if(node.left===null&&node.right===null&&count===0){ + resPath.push([...curPath]); + } + node.left&&travelTree(node.left,count); + node.right&&travelTree(node.right,count); + let cur = curPath.pop(); + count-=cur; + } + if(root===null){ + return resPath; + } + travelTree(root,targetSum); + return resPath; +}; +``` diff --git a/problems/0134.加油站.md b/problems/0134.加油站.md index 5c3f70a8..dfed2d96 100644 --- a/problems/0134.加油站.md +++ b/problems/0134.加油站.md @@ -241,7 +241,28 @@ class Solution: Go: +Javascript: +```Javascript +var canCompleteCircuit = function(gas, cost) { + const gasLen = gas.length + let start = 0 + let curSum = 0 + let totalSum = 0 + for(let i = 0; i < gasLen; i++) { + curSum += gas[i] - cost[i] + totalSum += gas[i] - cost[i] + if(curSum < 0) { + curSum = 0 + start = i + 1 + } + } + + if(totalSum < 0) return -1 + + return start +}; +``` ----------------------- diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md index 512360fe..63499b71 100644 --- a/problems/0151.翻转字符串里的单词.md +++ b/problems/0151.翻转字符串里的单词.md @@ -318,9 +318,61 @@ class Solution { Python: - Go: +```go +import ( + "fmt" +) + +func reverseWords(s string) string { + //1.使用双指针删除冗余的空格 + slowIndex, fastIndex := 0, 0 + b := []byte(s) + //删除头部冗余空格 + for len(b) > 0 && fastIndex < len(b) && b[fastIndex] == ' ' { + fastIndex++ + } + //删除单词间冗余空格 + for ; fastIndex < len(b); fastIndex++ { + if fastIndex-1 > 0 && b[fastIndex-1] == b[fastIndex] && b[fastIndex] == ' ' { + continue + } + b[slowIndex] = b[fastIndex] + slowIndex++ + } + //删除尾部冗余空格 + if slowIndex-1 > 0 && b[slowIndex-1] == ' ' { + b = b[:slowIndex-1] + } else { + b = b[:slowIndex] + } + //2.反转整个字符串 + reverse(&b, 0, len(b)-1) + //3.反转单个单词 i单词开始位置,j单词结束位置 + i := 0 + for i < len(b) { + j := i + for ; j < len(b) && b[j] != ' '; j++ { + } + reverse(&b, i, j-1) + i = j + i++ + } + return string(b) +} + +func reverse(b *[]byte, left, right int) { + for left < right { + (*b)[left], (*b)[right] = (*b)[right], (*b)[left] + left++ + right-- + } +} +``` + + + @@ -328,4 +380,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0202.快乐数.md b/problems/0202.快乐数.md index c07405ec..d1bccd64 100644 --- a/problems/0202.快乐数.md +++ b/problems/0202.快乐数.md @@ -108,9 +108,49 @@ class Solution { ``` Python: - +```python +class Solution: + def isHappy(self, n: int) -> bool: + set_ = set() + while 1: + sum_ = self.getSum(n) + if sum_ == 1: + return True + #如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false + if sum_ in set_: + return False + else: + set_.add(sum_) + n = sum_ + + #取数值各个位上的单数之和 + def getSum(self, n): + sum_ = 0 + while n > 0: + sum_ += (n%10) * (n%10) + n //= 10 + return sum_ +``` Go: +```go +func isHappy(n int) bool { + m := make(map[int]bool) + for n != 1 && !m[n] { + n, m[n] = getSum(n), true + } + return n == 1 +} + +func getSum(n int) int { + sum := 0 + for n > 0 { + sum += (n % 10) * (n % 10) + n = n / 10 + } + return sum +} +``` javaScript: diff --git a/problems/0239.滑动窗口最大值.md b/problems/0239.滑动窗口最大值.md index 6cc355ca..47383a47 100644 --- a/problems/0239.滑动窗口最大值.md +++ b/problems/0239.滑动窗口最大值.md @@ -263,10 +263,75 @@ class Solution { ``` Python: +```python +class MyQueue: #单调队列(从大到小 + def __init__(self): + self.queue = [] #使用list来实现单调队列 + + #每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。 + #同时pop之前判断队列当前是否为空。 + def pop(self, value): + if self.queue and value == self.queue[0]: + self.queue.pop(0)#list.pop()时间复杂度为O(n),这里可以使用collections.deque() + + #如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。 + #这样就保持了队列里的数值是单调从大到小的了。 + def push(self, value): + while self.queue and value > self.queue[-1]: + self.queue.pop() + self.queue.append(value) + + #查询当前队列里的最大值 直接返回队列前端也就是front就可以了。 + def front(self): + return self.queue[0] + +class Solution: + def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]: + que = MyQueue() + result = [] + for i in range(k): #先将前k的元素放进队列 + que.push(nums[i]) + result.append(que.front()) #result 记录前k的元素的最大值 + for i in range(k, len(nums)): + que.pop(nums[i - k]) #滑动窗口移除最前面元素 + que.push(nums[i]) #滑动窗口前加入最后面的元素 + result.append(que.front()) #记录对应的最大值 + return result +``` Go: +```go +func maxSlidingWindow(nums []int, k int) []int { + var queue []int + var rtn []int + + for f := 0; f < len(nums); f++ { + //维持队列递减, 将 k 插入合适的位置, queue中 <=k 的 元素都不可能是窗口中的最大值, 直接弹出 + for len(queue) > 0 && nums[f] > nums[queue[len(queue)-1]] { + queue = queue[:len(queue)-1] + } + // 等大的后来者也应入队 + if len(queue) == 0 || nums[f] <= nums[queue[len(queue)-1]] { + queue = append(queue, f) + } + + if f >= k - 1 { + rtn = append(rtn, nums[queue[0]]) + //弹出离开窗口的队首 + if f - k + 1 == queue[0] { + queue = queue[1:] + } + } + } + + return rtn + +} + +``` + Javascript: ```javascript var maxSlidingWindow = function (nums, k) { diff --git a/problems/0242.有效的字母异位词.md b/problems/0242.有效的字母异位词.md index 6a6faf63..ba942f70 100644 --- a/problems/0242.有效的字母异位词.md +++ b/problems/0242.有效的字母异位词.md @@ -113,7 +113,22 @@ class Solution { ``` Python: - +```python +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + record = [0] * 26 + for i in range(len(s)): + #并不需要记住字符a的ASCII,只要求出一个相对数值就可以了 + record[ord(s[i]) - ord("a")] += 1 + print(record) + for i in range(len(t)): + record[ord(t[i]) - ord("a")] -= 1 + for i in range(26): + if record[i] != 0: + #record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。 + return False + return True +``` Go: ```go diff --git a/problems/0347.前K个高频元素.md b/problems/0347.前K个高频元素.md index 841584b4..71af618e 100644 --- a/problems/0347.前K个高频元素.md +++ b/problems/0347.前K个高频元素.md @@ -162,7 +162,33 @@ class Solution { Python: - +```python +#时间复杂度:O(nlogk) +#空间复杂度:O(n) +import heapq +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + #要统计元素出现频率 + map_ = {} #nums[i]:对应出现的次数 + for i in range(len(nums)): + map_[nums[i]] = map_.get(nums[i], 0) + 1 + + #对频率排序 + #定义一个小顶堆,大小为k + pri_que = [] #小顶堆 + + #用固定大小为k的小顶堆,扫面所有频率的数值 + for key, freq in map_.items(): + heapq.heappush(pri_que, (freq, key)) + if len(pri_que) > k: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k + heapq.heappop(pri_que) + + #找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒叙来输出到数组 + result = [0] * k + for i in range(k-1, -1, -1): + result[i] = heapq.heappop(pri_que)[1] + return result +``` Go: diff --git a/problems/0383.赎金信.md b/problems/0383.赎金信.md index fd8175db..23e2c5fd 100644 --- a/problems/0383.赎金信.md +++ b/problems/0383.赎金信.md @@ -166,6 +166,21 @@ class Solution(object): ``` Go: +```go +func canConstruct(ransomNote string, magazine string) bool { + record := make([]int, 26) + for _, v := range magazine { + record[v-'a']++ + } + for _, v := range ransomNote { + record[v-'a']-- + if record[v-'a'] < 0 { + return false + } + } + return true +} +``` javaScript: diff --git a/problems/0416.分割等和子集.md b/problems/0416.分割等和子集.md index e69eb1a4..55d200e2 100644 --- a/problems/0416.分割等和子集.md +++ b/problems/0416.分割等和子集.md @@ -222,8 +222,18 @@ class Solution { ``` Python: - - +```python +class Solution: + def canPartition(self, nums: List[int]) -> bool: + taraget = sum(nums) + if taraget % 2 == 1: return False + taraget //= 2 + dp = [0] * 10001 + for i in range(len(nums)): + for j in range(taraget, nums[i] - 1, -1): + dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]) + return taraget == dp[taraget] +``` Go: diff --git a/problems/0452.用最少数量的箭引爆气球.md b/problems/0452.用最少数量的箭引爆气球.md index a8b55ca9..9b0cc925 100644 --- a/problems/0452.用最少数量的箭引爆气球.md +++ b/problems/0452.用最少数量的箭引爆气球.md @@ -142,16 +142,8 @@ Java: ```java class Solution { public int findMinArrowShots(int[][] points) { - Arrays.sort(points, new Comparator() { - @Override - public int compare(int[] o1, int[] o2) { - if (o1[0] != o2[0]) { - return Integer.compare(o1[0],o2[0]); - } else { - return Integer.compare(o1[0],o2[0]); - } - } - }); + if (points.length == 0) return 0; + Arrays.sort(points, (o1, o2) -> Integer.compare(o1[0], o2[0])); int count = 1; for (int i = 1; i < points.length; i++) { diff --git a/problems/0454.四数相加II.md b/problems/0454.四数相加II.md index 2c648f58..5291060c 100644 --- a/problems/0454.四数相加II.md +++ b/problems/0454.四数相加II.md @@ -154,6 +154,23 @@ class Solution(object): Go: +```go +func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int { + m := make(map[int]int) + count := 0 + for _, v1 := range nums1 { + for _, v2 := range nums2 { + m[v1+v2]++ + } + } + for _, v3 := range nums3 { + for _, v4 := range nums4 { + count += m[-v3-v4] + } + } + return count +} +``` javaScript: diff --git a/problems/0459.重复的子字符串.md b/problems/0459.重复的子字符串.md index d9dfc62c..51a903ef 100644 --- a/problems/0459.重复的子字符串.md +++ b/problems/0459.重复的子字符串.md @@ -184,6 +184,55 @@ class Solution { Python: +这里使用了前缀表统一减一的实现方式 + +```python +class Solution: + def repeatedSubstringPattern(self, s: str) -> bool: + if len(s) == 0: + return False + nxt = [0] * len(s) + self.getNext(nxt, s) + if nxt[-1] != -1 and len(s) % (len(s) - (nxt[-1] + 1)) == 0: + return True + return False + + def getNext(self, nxt, s): + nxt[0] = -1 + j = -1 + for i in range(1, len(s)): + while j >= 0 and s[i] != s[j+1]: + j = nxt[j] + if s[i] == s[j+1]: + j += 1 + nxt[i] = j + return nxt +``` + +前缀表(不减一)的代码实现 + +```python +class Solution: + def repeatedSubstringPattern(self, s: str) -> bool: + if len(s) == 0: + return False + nxt = [0] * len(s) + self.getNext(nxt, s) + if nxt[-1] != 0 and len(s) % (len(s) - nxt[-1]) == 0: + return True + return False + + def getNext(self, nxt, s): + nxt[0] = 0 + j = 0 + for i in range(1, len(s)): + while j > 0 and s[i] != s[j]: + j = nxt[j - 1] + if s[i] == s[j]: + j += 1 + nxt[i] = j + return nxt +``` Go: diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md index a9ddc768..c917ed5c 100644 --- a/problems/0494.目标和.md +++ b/problems/0494.目标和.md @@ -150,7 +150,7 @@ dp[j] 表示:填满j(包括j)这么大容积的包,有dp[i]种方法 有哪些来源可以推出dp[j]呢? -不考虑nums[i]的情况下,填满容量为j - nums[i]的背包,有dp[j - nums[i]]中方法。 +不考虑nums[i]的情况下,填满容量为j - nums[i]的背包,有dp[j - nums[i]]种方法。 那么只要搞到nums[i]的话,凑成dp[j]就有dp[j - nums[i]] 种方法。 @@ -261,10 +261,50 @@ class Solution { ``` Python: - +```python +class Solution: + def findTargetSumWays(self, nums: List[int], target: int) -> int: + sumValue = sum(nums) + if target > sumValue or (sumValue + target) % 2 == 1: return 0 + bagSize = (sumValue + target) // 2 + dp = [0] * (bagSize + 1) + dp[0] = 1 + for i in range(len(nums)): + for j in range(bagSize, nums[i] - 1, -1): + dp[j] += dp[j - nums[i]] + return dp[bagSize] +``` Go: - +```go +func findTargetSumWays(nums []int, target int) int { + sum := 0 + for _, v := range nums { + sum += v + } + if target > sum { + return 0 + } + if (sum+target)%2 == 1 { + return 0 + } + // 计算背包大小 + bag := (sum + target) / 2 + // 定义dp数组 + dp := make([]int, bag+1) + // 初始化 + dp[0] = 1 + // 遍历顺序 + for i := 0; i < len(nums); i++ { + for j := bag; j >= nums[i]; j-- { + //推导公式 + dp[j] += dp[j-nums[i]] + //fmt.Println(dp) + } + } + return dp[bag] +} +``` diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index 5c9613e5..97464e3d 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -298,6 +298,53 @@ class Solution: ``` Go: +JavaScript: +1. 递归版本 +```javascript +var findBottomLeftValue = function(root) { + //首先考虑递归遍历 前序遍历 找到最大深度的叶子节点即可 + let maxPath = 0,resNode = null; + // 1. 确定递归函数的函数参数 + const dfsTree = function(node,curPath){ + // 2. 确定递归函数终止条件 + if(node.left===null&&node.right===null){ + if(curPath>maxPath){ + maxPath = curPath; + resNode = node.val; + } + // return ; + } + node.left&&dfsTree(node.left,curPath+1); + node.right&&dfsTree(node.right,curPath+1); + } + dfsTree(root,1); + return resNode; +}; +``` +2. 层序遍历 +```javascript +var findBottomLeftValue = function(root) { + //考虑层序遍历 记录最后一行的第一个节点 + let queue = []; + if(root===null){ + return null; + } + queue.push(root); + let resNode; + while(queue.length){ + let length = queue.length; + for(let i=0; i { + return Math.abs(b) - Math.abs(a) + }) + for(let i = 0; i < nums.length; i++) { + if(nums[i] < 0 && k > 0) { + nums[i] *= -1 + k-- + } + } + if(k > 0 && k % 2 === 1) { + nums[nums.length - 1] *= -1 + } + k = 0 + + return nums.reduce((a, b) => { + return a + b + }) +}; +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md index 9ca08c96..305a287d 100644 --- a/problems/1047.删除字符串中的所有相邻重复项.md +++ b/problems/1047.删除字符串中的所有相邻重复项.md @@ -186,6 +186,23 @@ class Solution: Go: +```go +func removeDuplicates(s string) string { + var stack []byte + for i := 0; i < len(s);i++ { + // 栈不空 且 与栈顶元素不等 + if len(stack) > 0 && stack[len(stack)-1] == s[i] { + // 弹出栈顶元素 并 忽略当前元素(s[i]) + stack = stack[:len(stack)-1] + }else{ + // 入栈 + stack = append(stack, s[i]) + } + } + return string(stack) +} +``` + javaScript: ```js diff --git a/problems/1049.最后一块石头的重量II.md b/problems/1049.最后一块石头的重量II.md index fcd3712a..c09e476a 100644 --- a/problems/1049.最后一块石头的重量II.md +++ b/problems/1049.最后一块石头的重量II.md @@ -178,10 +178,46 @@ class Solution { ``` Python: - +```python +class Solution: + def lastStoneWeightII(self, stones: List[int]) -> int: + sumweight = sum(stones) + target = sumweight // 2 + dp = [0] * 15001 + for i in range(len(stones)): + for j in range(target, stones[i] - 1, -1): + dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]) + return sumweight - 2 * dp[target] +``` Go: +```go +func lastStoneWeightII(stones []int) int { + // 15001 = 30 * 1000 /2 +1 + dp := make([]int, 15001) + // 求target + sum := 0 + for _, v := range stones { + sum += v + } + target := sum / 2 + // 遍历顺序 + for i := 0; i < len(stones); i++ { + for j := target; j >= stones[i]; j-- { + // 推导公式 + dp[j] = max(dp[j], dp[j-stones[i]]+stones[i]) + } + } + return sum - 2 * dp[target] +} +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` diff --git a/problems/二叉树的统一迭代法.md b/problems/二叉树的统一迭代法.md index dca5d3e3..533bdfe7 100644 --- a/problems/二叉树的统一迭代法.md +++ b/problems/二叉树的统一迭代法.md @@ -239,7 +239,78 @@ Java: ``` Python: +> 迭代法前序遍历 +```python +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + st= [] + if root: + st.append(root) + while st: + node = st.pop() + if node != None: + if node.right: #右 + st.append(node.right) + if node.left: #左 + st.append(node.left) + st.append(node) #中 + st.append(None) + else: + node = st.pop() + result.append(node.val) + return result +``` + +> 迭代法中序遍历 +```python +class Solution: + def inorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + st = [] + if root: + st.append(root) + while st: + node = st.pop() + if node != None: + if node.right: #添加右节点(空节点不入栈) + st.append(node.right) + + st.append(node) #添加中节点 + st.append(None) #中节点访问过,但是还没有处理,加入空节点做为标记。 + + if node.left: #添加左节点(空节点不入栈) + st.append(node.left) + else: #只有遇到空节点的时候,才将下一个节点放进结果集 + node = st.pop() #重新取出栈中元素 + result.append(node.val) #加入到结果集 + return result +``` + +> 迭代法后序遍历 +```python +class Solution: + def postorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + st = [] + if root: + st.append(root) + while st: + node = st.pop() + if node != None: + st.append(node) #中 + st.append(None) + + if node.right: #右 + st.append(node.right) + if node.left: #左 + st.append(node.left) + else: + node = st.pop() + result.append(node.val) + return result +``` Go: > 前序遍历统一迭代法 @@ -374,6 +445,86 @@ func postorderTraversal(root *TreeNode) []int { } ``` +javaScript: + +> 前序遍历统一迭代法 + +```js + +// 前序遍历:中左右 +// 压栈顺序:右左中 + +var preorderTraversal = function(root, res = []) { + const stack = []; + if (root) stack.push(root); + while(stack.length) { + const node = stack.pop(); + if(!node) { + res.push(stack.pop().val); + continue; + } + if (node.right) stack.push(node.right); // 右 + if (node.left) stack.push(node.left); // 左 + stack.push(node); // 中 + stack.push(null); + }; + return res; +}; + +``` + +> 中序遍历统一迭代法 + +```js + +// 中序遍历:左中右 +// 压栈顺序:右中左 + +var inorderTraversal = function(root, res = []) { + const stack = []; + if (root) stack.push(root); + while(stack.length) { + const node = stack.pop(); + if(!node) { + res.push(stack.pop().val); + continue; + } + if (node.right) stack.push(node.right); // 右 + stack.push(node); // 中 + stack.push(null); + if (node.left) stack.push(node.left); // 左 + }; + return res; +}; + +``` + +> 后序遍历统一迭代法 + +```js + +// 后续遍历:左右中 +// 压栈顺序:中右左 + +var postorderTraversal = function(root, res = []) { + const stack = []; + if (root) stack.push(root); + while(stack.length) { + const node = stack.pop(); + if(!node) { + res.push(stack.pop().val); + continue; + } + stack.push(node); // 中 + stack.push(null); + if (node.right) stack.push(node.right); // 右 + if (node.left) stack.push(node.left); // 左 + }; + return res; +}; + +``` + ----------------------- diff --git a/problems/前序/关于时间复杂度,你不知道的都在这里!.md b/problems/前序/关于时间复杂度,你不知道的都在这里!.md index bd3bd284..3f5bc156 100644 --- a/problems/前序/关于时间复杂度,你不知道的都在这里!.md +++ b/problems/前序/关于时间复杂度,你不知道的都在这里!.md @@ -117,7 +117,7 @@ O(2 * n^2 + 10 * n + 1000) < O(3 * n^2),所以说最后省略掉常数项系 ![时间复杂度1.png](https://img-blog.csdnimg.cn/20200728191447349.png) -假如有两个算法的时间复杂度,分别是log以2为底n的对数和log以10为底n的对数,那么这里如果还记得高中数学的话,应该不能理解`以2为底n的对数 = 以2为底10的对数 * 以10为底n的对数`。 +假如有两个算法的时间复杂度,分别是log以2为底n的对数和log以10为底n的对数,那么这里如果还记得高中数学的话,应该不难理解`以2为底n的对数 = 以2为底10的对数 * 以10为底n的对数`。 而以2为底10的对数是一个常数,在上文已经讲述了我们计算时间复杂度是忽略常数项系数的。 diff --git a/problems/剑指Offer58-II.左旋转字符串.md b/problems/剑指Offer58-II.左旋转字符串.md index 648546c1..39c8382c 100644 --- a/problems/剑指Offer58-II.左旋转字符串.md +++ b/problems/剑指Offer58-II.左旋转字符串.md @@ -23,7 +23,7 @@ https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/ 示例 2: 输入: s = "lrloseumgh", k = 6 输出: "umghlrlose" -  + 限制: 1 <= k < s.length <= 10000 @@ -119,9 +119,31 @@ class Solution { ``` Python: - Go: +```go +func reverseLeftWords(s string, n int) string { + b := []byte(s) + // 1. 反转前n个字符 + // 2. 反转第n到end字符 + // 3. 反转整个字符 + reverse(b, 0, n-1) + reverse(b, n, len(b)-1) + reverse(b, 0, len(b)-1) + return string(b) +} +// 切片是引用传递 +func reverse(b []byte, left, right int){ + for left < right{ + b[left], b[right] = b[right],b[left] + left++ + right-- + } +} +``` + + + @@ -129,4 +151,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/背包理论基础01背包-2.md b/problems/背包理论基础01背包-2.md index a169425a..e831d88f 100644 --- a/problems/背包理论基础01背包-2.md +++ b/problems/背包理论基础01背包-2.md @@ -55,7 +55,7 @@ dp[j]为 容量为j的背包所背的最大价值,那么如何推导dp[j]呢? -dp[j]可以通过dp[j - weight[j]]推导出来,dp[j - weight[i]]表示容量为j - weight[i]的背包所背的最大价值。 +dp[j]可以通过dp[j - weight[i]]推导出来,dp[j - weight[i]]表示容量为j - weight[i]的背包所背的最大价值。 dp[j - weight[i]] + value[i] 表示 容量为 j - 物品i重量 的背包 加上 物品i的价值。(也就是容量为j的背包,放入物品i了之后的价值即:dp[j])