mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-09 03:34:02 +08:00
Merge branch 'youngyangyang04:master' into master
This commit is contained in:
@ -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;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -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];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -417,6 +417,7 @@ object Solution {
|
||||
}
|
||||
sum
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
C#:
|
||||
|
@ -5,7 +5,7 @@
|
||||
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||
|
||||
|
||||
## 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,来看一下查找的过程:
|
||||
|
||||

|
||||
@ -74,7 +91,7 @@ public:
|
||||
|
||||
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
|
||||
|
||||
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,窗口的起始位置设置为数组的起始位置就可以了。
|
||||
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
|
||||
|
||||
解题的关键在于 窗口的起始位置如何移动,如图所示:
|
||||
|
||||
@ -107,8 +124,8 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
时间复杂度:O(n)
|
||||
空间复杂度:O(1)
|
||||
* 时间复杂度:O(n)
|
||||
* 空间复杂度:O(1)
|
||||
|
||||
**一些录友会疑惑为什么时间复杂度是O(n)**。
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -356,6 +356,8 @@ object Solution {
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
C#:
|
||||
```csharp
|
||||
|
@ -425,6 +425,7 @@ object Solution {
|
||||
true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
C#:
|
||||
|
@ -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)
|
||||
|
@ -354,6 +354,7 @@ object Solution {
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
C#:
|
||||
```csharp
|
||||
|
@ -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;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -158,6 +158,71 @@ class Solution {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
class Solution{
|
||||
/*解法二: 上述c++补充思路的Java代码实现*/
|
||||
|
||||
public int[][] findPartitions(String s) {
|
||||
List<Integer> 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<List<Integer>> 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<Integer> list = h.get(i);
|
||||
res[i][0] = list.get(0);
|
||||
res[i][1] = list.get(1);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
public List<Integer> partitionLabels(String s) {
|
||||
int[][] partitions = findPartitions(s);
|
||||
List<Integer> 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
|
||||
|
@ -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];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
|
||||
# 一台服务器有什么用!
|
||||
|
||||
* [阿里云活动期间服务器购买](https://www.aliyun.com/minisite/goods?taskCode=shareNew2205&recordId=3641992&userCode=roof0wob)
|
||||
* [腾讯云活动期间服务器购买](https://curl.qcloud.com/EiaMXllu)
|
||||
|
||||
但在组织这场活动的时候,了解到大家都有一个共同的问题: **这个服务器究竟有啥用??**
|
||||
|
||||
这真是一个好问题,而且我一句两句还说不清楚,所以就专门发文来讲一讲。
|
||||
|
Reference in New Issue
Block a user