diff --git a/problems/0053.最大子序和(动态规划).md b/problems/0053.最大子序和(动态规划).md index 4c883cb6..99aa7acf 100644 --- a/problems/0053.最大子序和(动态规划).md +++ b/problems/0053.最大子序和(动态规划).md @@ -186,6 +186,24 @@ const maxSubArray = nums => { }; ``` +TypeScript: + +```typescript +function maxSubArray(nums: number[]): number { + /** + dp[i]:以nums[i]结尾的最大和 + */ + const dp: number[] = [] + dp[0] = nums[0]; + let resMax: number = 0; + for (let i = 1; i < nums.length; i++) { + dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]); + resMax = Math.max(resMax, dp[i]); + } + return resMax; +}; +``` + ----------------------- diff --git a/problems/0072.编辑距离.md b/problems/0072.编辑距离.md index 3802c228..530774ee 100644 --- a/problems/0072.编辑距离.md +++ b/problems/0072.编辑距离.md @@ -327,5 +327,42 @@ const minDistance = (word1, word2) => { }; ``` +TypeScript: + +```typescript +function minDistance(word1: string, word2: string): number { + /** + dp[i][j]: word1前i个字符,word2前j个字符,最少操作数 + dp[0][0]=0:表示word1前0个字符为'', word2前0个字符为'' + */ + const length1: number = word1.length, + length2: number = word2.length; + const dp: number[][] = new Array(length1 + 1).fill(0) + .map(_ => new Array(length2 + 1).fill(0)); + for (let i = 0; i <= length1; i++) { + dp[i][0] = i; + } + for (let i = 0; i <= length2; i++) { + dp[0][i] = i; + } + for (let i = 1; i <= length1; i++) { + for (let j = 1; j <= length2; j++) { + if (word1[i - 1] === word2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = Math.min( + dp[i - 1][j], + dp[i][j - 1], + dp[i - 1][j - 1] + ) + 1; + } + } + } + return dp[length1][length2]; +}; +``` + + + -----------------------
diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md index 6401824b..d5eaa8ab 100644 --- a/problems/0093.复原IP地址.md +++ b/problems/0093.复原IP地址.md @@ -444,7 +444,7 @@ var restoreIpAddresses = function(s) { return; } for(let j = i; j < s.length; j++) { - const str = s.substr(i, j - i + 1); + const str = s.slice(i, j + 1); if(str.length > 3 || +str > 255) break; if(str.length > 1 && str[0] === "0") break; path.push(str); diff --git a/problems/0101.对称二叉树.md b/problems/0101.对称二叉树.md index 1eb43589..c79fde0e 100644 --- a/problems/0101.对称二叉树.md +++ b/problems/0101.对称二叉树.md @@ -725,5 +725,25 @@ func isSymmetric3(_ root: TreeNode?) -> Bool { } ``` +## Scala + +递归: +```scala +object Solution { + def isSymmetric(root: TreeNode): Boolean = { + if (root == null) return true // 如果等于空直接返回true + def compare(left: TreeNode, right: TreeNode): Boolean = { + if (left == null && right == null) return true // 如果左右都为空,则为true + if (left == null && right != null) return false // 如果左空右不空,不对称,返回false + if (left != null && right == null) return false // 如果左不空右空,不对称,返回false + // 如果左右的值相等,并且往下递归 + left.value == right.value && compare(left.left, right.right) && compare(left.right, right.left) + } + // 分别比较左子树和右子树 + compare(root.left, root.right) + } +} +``` + -----------------------
diff --git a/problems/0115.不同的子序列.md b/problems/0115.不同的子序列.md index 0f762969..ca66e20d 100644 --- a/problems/0115.不同的子序列.md +++ b/problems/0115.不同的子序列.md @@ -267,6 +267,36 @@ const numDistinct = (s, t) => { }; ``` +TypeScript: + +```typescript +function numDistinct(s: string, t: string): number { + /** + dp[i][j]: s前i个字符,t前j个字符,s子序列中t出现的个数 + dp[0][0]=1, 表示s前0个字符为'',t前0个字符为'' + */ + const sLen: number = s.length, + tLen: number = t.length; + const dp: number[][] = new Array(sLen + 1).fill(0) + .map(_ => new Array(tLen + 1).fill(0)); + for (let m = 0; m < sLen; m++) { + dp[m][0] = 1; + } + for (let i = 1; i <= sLen; i++) { + for (let j = 1; j <= tLen; j++) { + if (s[i - 1] === t[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; + } else { + dp[i][j] = dp[i - 1][j]; + } + } + } + return dp[sLen][tLen]; +}; +``` + + + -----------------------
diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md index 7a702898..6a370fb4 100644 --- a/problems/0131.分割回文串.md +++ b/problems/0131.分割回文串.md @@ -442,7 +442,7 @@ var partition = function(s) { } for(let j = i; j < len; j++) { if(!isPalindrome(s, i, j)) continue; - path.push(s.substr(i, j - i + 1)); + path.push(s.slice(i, j + 1)); backtracking(j + 1); path.pop(); } diff --git a/problems/0202.快乐数.md b/problems/0202.快乐数.md index be8686f7..7738b2f6 100644 --- a/problems/0202.快乐数.md +++ b/problems/0202.快乐数.md @@ -417,6 +417,7 @@ object Solution { } sum } +``` C#: diff --git a/problems/0209.长度最小的子数组.md b/problems/0209.长度最小的子数组.md index fbef7692..69e0da4f 100644 --- a/problems/0209.长度最小的子数组.md +++ b/problems/0209.长度最小的子数组.md @@ -5,7 +5,7 @@

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

-## 209.长度最小的子数组 +# 209.长度最小的子数组 [力扣题目链接](https://leetcode-cn.com/problems/minimum-size-subarray-sum/) @@ -17,6 +17,9 @@ 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。 +# 思路 + +为了易于大家理解,我特意录制了[拿下滑动窗口! | LeetCode 209 长度最小的子数组](https://www.bilibili.com/video/BV1tZ4y1q7XE) ## 暴力解法 @@ -47,8 +50,8 @@ public: } }; ``` -时间复杂度:O(n^2) -空间复杂度:O(1) +* 时间复杂度:O(n^2) +* 空间复杂度:O(1) ## 滑动窗口 @@ -56,6 +59,20 @@ public: 所谓滑动窗口,**就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果**。 +在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。 + +那么滑动窗口如何用一个for循环来完成这个操作呢。 + +首先要思考 如果用一个for循环,那么应该表示 滑动窗口的起始位置,还是终止位置。 + +如果只用一个for循环来表示 滑动窗口的起始位置,那么如何遍历剩下的终止位置? + +此时难免再次陷入 暴力解法的怪圈。 + +所以 只用一个for循环,那么这个循环的索引,一定是表示 滑动窗口的终止位置。 + +那么问题来了, 滑动窗口的起始位置如何移动呢? + 这里还是以题目中的示例来举例,s=7, 数组是 2,3,1,2,4,3,来看一下查找的过程: ![209.长度最小的子数组](https://code-thinking.cdn.bcebos.com/gifs/209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.gif) @@ -74,7 +91,7 @@ public: 窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。 -窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,窗口的起始位置设置为数组的起始位置就可以了。 +窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。 解题的关键在于 窗口的起始位置如何移动,如图所示: @@ -107,8 +124,8 @@ public: }; ``` -时间复杂度:O(n) -空间复杂度:O(1) +* 时间复杂度:O(n) +* 空间复杂度:O(1) **一些录友会疑惑为什么时间复杂度是O(n)**。 diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index 32b1347e..66ca7ff7 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -360,39 +360,30 @@ func backTree(n,k,startIndex int,track *[]int,result *[][]int){ ## javaScript ```js -// 等差数列 -var maxV = k => k * (9 + 10 - k) / 2; -var minV = k => k * (1 + k) / 2; +/** + * @param {number} k + * @param {number} n + * @return {number[][]} + */ var combinationSum3 = function(k, n) { - if (k > 9 || k < 1) return []; - // if (n > maxV(k) || n < minV(k)) return []; - // if (n === maxV(k)) return [Array.from({length: k}).map((v, i) => 9 - i)]; - // if (n === minV(k)) return [Array.from({length: k}).map((v, i) => i + 1)]; - - const res = [], path = []; - backtracking(k, n, 1, 0); - return res; - function backtracking(k, n, i, sum){ - const len = path.length; - if (len > k || sum > n) return; - if (maxV(k - len) < n - sum) return; - if (minV(k - len) > n - sum) return; - - if(len === k && sum == n) { - res.push(Array.from(path)); + const backtrack = (start) => { + const l = path.length; + if (l === k) { + const sum = path.reduce((a, b) => a + b); + if (sum === n) { + res.push([...path]); + } return; } - - const min = Math.min(n - sum, 9 + len - k + 1); - - for(let a = i; a <= min; a++) { - path.push(a); - sum += a; - backtracking(k, n, a + 1, sum); + for (let i = start; i <= 9 - (k - l) + 1; i++) { + path.push(i); + backtrack(i + 1); path.pop(); - sum -= a; } } + let res = [], path = []; + backtrack(1); + return res; }; ``` diff --git a/problems/0226.翻转二叉树.md b/problems/0226.翻转二叉树.md index af5b8043..9b5cfbae 100644 --- a/problems/0226.翻转二叉树.md +++ b/problems/0226.翻转二叉树.md @@ -818,5 +818,53 @@ func invertTree(_ root: TreeNode?) -> TreeNode? { } ``` +### Scala + +深度优先遍历(前序遍历): +```scala +object Solution { + def invertTree(root: TreeNode): TreeNode = { + if (root == null) return root + // 递归 + def process(node: TreeNode): Unit = { + if (node == null) return + // 翻转节点 + val curNode = node.left + node.left = node.right + node.right = curNode + process(node.left) + process(node.right) + } + process(root) + root + } +} +``` + +广度优先遍历(层序遍历): +```scala +object Solution { + import scala.collection.mutable + def invertTree(root: TreeNode): TreeNode = { + if (root == null) return root + val queue = mutable.Queue[TreeNode]() + queue.enqueue(root) + while (!queue.isEmpty) { + val len = queue.size + for (i <- 0 until len) { + var curNode = queue.dequeue() + if (curNode.left != null) queue.enqueue(curNode.left) + if (curNode.right != null) queue.enqueue(curNode.right) + // 翻转 + var tmpNode = curNode.left + curNode.left = curNode.right + curNode.right = tmpNode + } + } + root + } +} +``` + -----------------------
diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index f7dab3d7..4fbdd414 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -356,6 +356,8 @@ object Solution { } } +``` + C#: ```csharp diff --git a/problems/0383.赎金信.md b/problems/0383.赎金信.md index 75dafb72..9c3dda8c 100644 --- a/problems/0383.赎金信.md +++ b/problems/0383.赎金信.md @@ -425,6 +425,7 @@ object Solution { true } } +``` C#: diff --git a/problems/0392.判断子序列.md b/problems/0392.判断子序列.md index 671576f7..3f7eb11d 100644 --- a/problems/0392.判断子序列.md +++ b/problems/0392.判断子序列.md @@ -201,7 +201,32 @@ const isSubsequence = (s, t) => { }; ``` +TypeScript: + +```typescript +function isSubsequence(s: string, t: string): boolean { + /** + dp[i][j]: s的前i-1个,t的前j-1个,最长公共子序列的长度 + */ + const sLen: number = s.length, + tLen: number = t.length; + const dp: number[][] = new Array(sLen + 1).fill(0) + .map(_ => new Array(tLen + 1).fill(0)); + for (let i = 1; i <= sLen; i++) { + for (let j = 1; j <= tLen; j++) { + if (s[i - 1] === t[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + return dp[sLen][tLen] === s.length; +}; +``` + Go: + ```go func isSubsequence(s string, t string) bool { dp := make([][]int,len(s)+1) diff --git a/problems/0454.四数相加II.md b/problems/0454.四数相加II.md index bfdee26e..726fdb15 100644 --- a/problems/0454.四数相加II.md +++ b/problems/0454.四数相加II.md @@ -354,6 +354,7 @@ object Solution { res } } +``` C#: ```csharp diff --git a/problems/0583.两个字符串的删除操作.md b/problems/0583.两个字符串的删除操作.md index 53c1a125..00f11700 100644 --- a/problems/0583.两个字符串的删除操作.md +++ b/problems/0583.两个字符串的删除操作.md @@ -229,6 +229,67 @@ const minDistance = (word1, word2) => { }; ``` +TypeScript: + +> dp版本一: + +```typescript +function minDistance(word1: string, word2: string): number { + /** + dp[i][j]: word1前i个字符,word2前j个字符,所需最小步数 + dp[0][0]=0: word1前0个字符为'', word2前0个字符为'' + */ + const length1: number = word1.length, + length2: number = word2.length; + const dp: number[][] = new Array(length1 + 1).fill(0) + .map(_ => new Array(length2 + 1).fill(0)); + for (let i = 0; i <= length1; i++) { + dp[i][0] = i; + } + for (let i = 0; i <= length2; i++) { + dp[0][i] = i; + } + for (let i = 1; i <= length1; i++) { + for (let j = 1; j <= length2; j++) { + if (word1[i - 1] === word2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1; + } + } + } + return dp[length1][length2]; +}; +``` + +> dp版本二: + +```typescript +function minDistance(word1: string, word2: string): number { + /** + dp[i][j]: word1前i个字符,word2前j个字符,最长公共子序列的长度 + dp[0][0]=0: word1前0个字符为'', word2前0个字符为'' + */ + const length1: number = word1.length, + length2: number = word2.length; + const dp: number[][] = new Array(length1 + 1).fill(0) + .map(_ => new Array(length2 + 1).fill(0)); + for (let i = 1; i <= length1; i++) { + for (let j = 1; j <= length2; j++) { + if (word1[i - 1] === word2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]); + } + } + } + const maxLen: number = dp[length1][length2]; + return length1 + length2 - maxLen * 2; +}; +``` + + + -----------------------
diff --git a/problems/0763.划分字母区间.md b/problems/0763.划分字母区间.md index 2210cffa..2f4d1b48 100644 --- a/problems/0763.划分字母区间.md +++ b/problems/0763.划分字母区间.md @@ -158,6 +158,71 @@ class Solution { return list; } } + +class Solution{ + /*解法二: 上述c++补充思路的Java代码实现*/ + + public int[][] findPartitions(String s) { + List temp = new ArrayList<>(); + int[][] hash = new int[26][2];//26个字母2列 表示该字母对应的区间 + + for (int i = 0; i < s.length(); i++) { + //更新字符c对应的位置i + char c = s.charAt(i); + if (hash[c - 'a'][0] == 0) hash[c - 'a'][0] = i; + + hash[c - 'a'][1] = i; + + //第一个元素区别对待一下 + hash[s.charAt(0) - 'a'][0] = 0; + } + + + List> h = new LinkedList<>(); + //组装区间 + for (int i = 0; i < 26; i++) { + //if (hash[i][0] != hash[i][1]) { + temp.clear(); + temp.add(hash[i][0]); + temp.add(hash[i][1]); + //System.out.println(temp); + h.add(new ArrayList<>(temp)); + // } + } + // System.out.println(h); + // System.out.println(h.size()); + int[][] res = new int[h.size()][2]; + for (int i = 0; i < h.size(); i++) { + List list = h.get(i); + res[i][0] = list.get(0); + res[i][1] = list.get(1); + } + + return res; + + } + + public List partitionLabels(String s) { + int[][] partitions = findPartitions(s); + List res = new ArrayList<>(); + Arrays.sort(partitions, (o1, o2) -> Integer.compare(o1[0], o2[0])); + int right = partitions[0][1]; + int left = 0; + for (int i = 0; i < partitions.length; i++) { + if (partitions[i][0] > right) { + //左边界大于右边界即可纪委一次分割 + res.add(right - left + 1); + left = partitions[i][0]; + } + right = Math.max(right, partitions[i][1]); + + } + //最右端 + res.add(right - left + 1); + return res; + + } +} ``` ### Python diff --git a/problems/1035.不相交的线.md b/problems/1035.不相交的线.md index 279ed816..4463c5f7 100644 --- a/problems/1035.不相交的线.md +++ b/problems/1035.不相交的线.md @@ -183,6 +183,30 @@ const maxUncrossedLines = (nums1, nums2) => { }; ``` +TypeScript: + +```typescript +function maxUncrossedLines(nums1: number[], nums2: number[]): number { + /** + dp[i][j]: nums1前i-1个,nums2前j-1个,最大连线数 + */ + const length1: number = nums1.length, + length2: number = nums2.length; + const dp: number[][] = new Array(length1 + 1).fill(0) + .map(_ => new Array(length2 + 1).fill(0)); + for (let i = 1; i <= length1; i++) { + for (let j = 1; j <= length2; j++) { + if (nums1[i - 1] === nums2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + return dp[length1][length2]; +}; +``` + diff --git a/problems/qita/server.md b/problems/qita/server.md index 16995d70..1d7a1d6b 100644 --- a/problems/qita/server.md +++ b/problems/qita/server.md @@ -1,6 +1,9 @@ # 一台服务器有什么用! +* [阿里云活动期间服务器购买](https://www.aliyun.com/minisite/goods?taskCode=shareNew2205&recordId=3641992&userCode=roof0wob) +* [腾讯云活动期间服务器购买](https://curl.qcloud.com/EiaMXllu) + 但在组织这场活动的时候,了解到大家都有一个共同的问题: **这个服务器究竟有啥用??** 这真是一个好问题,而且我一句两句还说不清楚,所以就专门发文来讲一讲。