Merge branch 'youngyangyang04:master' into master

This commit is contained in:
lizhendong128
2022-05-19 11:11:02 +08:00
committed by GitHub
29 changed files with 734 additions and 162 deletions

View File

@ -254,7 +254,7 @@
33. [二叉树:构造一棵搜索树](./problems/0108.将有序数组转换为二叉搜索树.md)
34. [二叉树:搜索树转成累加树](./problems/0538.把二叉搜索树转换为累加树.md)
35. [二叉树:总结篇!(需要掌握的二叉树技能都在这里了)](./problems/二叉树总结篇.md)
## 回溯算法
题目分类大纲如下:

View File

@ -313,54 +313,36 @@ func threeSum(nums []int)[][]int{
javaScript:
```js
/**
* @param {number[]} nums
* @return {number[][]}
*/
// 循环内不考虑去重
var threeSum = function(nums) {
const len = nums.length;
if(len < 3) return [];
nums.sort((a, b) => a - b);
const resSet = new Set();
for(let i = 0; i < len - 2; i++) {
if(nums[i] > 0) break;
let l = i + 1, r = len - 1;
const res = [], len = nums.length
// 将数组排序
nums.sort((a, b) => a - b)
for (let i = 0; i < len; i++) {
let l = i + 1, r = len - 1, iNum = nums[i]
// 数组排过序如果第一个数大于0直接返回res
if (iNum > 0) return res
// 去重
if (iNum == nums[i - 1]) continue
while(l < r) {
const sum = nums[i] + nums[l] + nums[r];
if(sum < 0) { l++; continue };
if(sum > 0) { r--; continue };
resSet.add(`${nums[i]},${nums[l]},${nums[r]}`);
l++;
r--;
let lNum = nums[l], rNum = nums[r], threeSum = iNum + lNum + rNum
// 三数之和小于0则左指针向右移动
if (threeSum < 0) l++
else if (threeSum > 0) r--
else {
res.push([iNum, lNum, rNum])
// 去重
while(l < r && nums[l] == nums[l + 1]){
l++
}
while(l < r && nums[r] == nums[r - 1]) {
r--
}
l++
r--
}
}
}
return Array.from(resSet).map(i => i.split(","));
};
// 去重优化
var threeSum = function(nums) {
const len = nums.length;
if(len < 3) return [];
nums.sort((a, b) => a - b);
const res = [];
for(let i = 0; i < len - 2; i++) {
if(nums[i] > 0) break;
// a去重
if(i > 0 && nums[i] === nums[i - 1]) continue;
let l = i + 1, r = len - 1;
while(l < r) {
const sum = nums[i] + nums[l] + nums[r];
if(sum < 0) { l++; continue };
if(sum > 0) { r--; continue };
res.push([nums[i], nums[l], nums[r]])
// b c 去重
while(l < r && nums[l] === nums[++l]);
while(l < r && nums[r] === nums[--r]);
}
}
return res;
return res
};
```
TypeScript:

View File

@ -318,6 +318,31 @@ func searchInsert(_ nums: [Int], _ target: Int) -> Int {
```
### PHP
```php
// 二分法(1)[左闭右闭]
function searchInsert($nums, $target)
{
$n = count($nums);
$l = 0;
$r = $n - 1;
while ($l <= $r) {
$mid = floor(($l + $r) / 2);
if ($nums[$mid] > $target) {
// 下次搜索在左区间:[$l,$mid-1]
$r = $mid - 1;
} else if ($nums[$mid] < $target) {
// 下次搜索在右区间:[$mid+1,$r]
$l = $mid + 1;
} else {
// 命中返回
return $mid;
}
}
return $r + 1;
}
```
-----------------------

View File

@ -370,18 +370,17 @@ func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int)
```js
var combinationSum = function(candidates, target) {
const res = [], path = [];
candidates.sort(); // 排序
candidates.sort((a,b)=>a-b); // 排序
backtracking(0, 0);
return res;
function backtracking(j, sum) {
if (sum > target) return;
if (sum === target) {
res.push(Array.from(path));
return;
}
for(let i = j; i < candidates.length; i++ ) {
const n = candidates[i];
if(n > target - sum) continue;
if(n > target - sum) break;
path.push(n);
sum += n;
backtracking(i, sum);

View File

@ -508,22 +508,27 @@ func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int)
*/
var combinationSum2 = function(candidates, target) {
const res = []; path = [], len = candidates.length;
candidates.sort();
candidates.sort((a,b)=>a-b);
backtracking(0, 0);
return res;
function backtracking(sum, i) {
if (sum > target) return;
if (sum === target) {
res.push(Array.from(path));
return;
}
let f = -1;
for(let j = i; j < len; j++) {
const n = candidates[j];
if(n > target - sum || n === f) continue;
if(j > i && candidates[j] === candidates[j-1]){
//若当前元素和前一个元素相等
//则本次循环结束,防止出现重复组合
continue;
}
//如果当前元素值大于目标值-总和的值
//由于数组已排序,那么该元素之后的元素必定不满足条件
//直接终止当前层的递归
if(n > target - sum) break;
path.push(n);
sum += n;
f = n;
backtracking(sum, j + 1);
path.pop();
sum -= n;

View File

@ -140,7 +140,7 @@ public:
## 其他语言版本
### Java
### Java
```java
class Solution {
public int maxSubArray(int[] nums) {
@ -180,7 +180,7 @@ class Solution {
}
```
### Python
### Python
```python
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
@ -195,7 +195,7 @@ class Solution:
return result
```
### Go
### Go
```go
func maxSubArray(nums []int) int {
@ -212,6 +212,20 @@ func maxSubArray(nums []int) int {
}
```
### Rust
```rust
pub fn max_sub_array(nums: Vec<i32>) -> i32 {
let mut max_sum = i32::MIN;
let mut curr = 0;
for n in nums.iter() {
curr += n;
max_sum = max_sum.max(curr);
curr = curr.max(0);
}
max_sum
}
```
### Javascript:
```Javascript
var maxSubArray = function(nums) {

View File

@ -273,7 +273,7 @@ public:
return dp[m-1][n-1];
}
```
```
### Python
```python
@ -347,7 +347,35 @@ var uniquePaths = function(m, n) {
};
```
### TypeScript
```typescript
function uniquePaths(m: number, n: number): number {
/**
dp[i][j]: 到达(i, j)的路径数
dp[0][*]: 1;
dp[*][0]: 1;
...
dp[i][j]: dp[i - 1][j] + dp[i][j - 1];
*/
const dp: number[][] = new Array(m).fill(0).map(_ => []);
for (let i = 0; i < m; i++) {
dp[i][0] = 1;
}
for (let i = 0; i < n; i++) {
dp[0][i] = 1;
}
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
};
```
### C
```c
//初始化dp数组
int **initDP(int m, int n) {

View File

@ -352,7 +352,38 @@ var uniquePathsWithObstacles = function(obstacleGrid) {
};
```
C
### TypeScript
```typescript
function uniquePathsWithObstacles(obstacleGrid: number[][]): number {
/**
dp[i][j]: 到达(i, j)的路径数
dp[0][*]: 用u表示第一个障碍物下标则u之前为1u之后含u为0
dp[*][0]: 同上
...
dp[i][j]: obstacleGrid[i][j] === 1 ? 0 : dp[i-1][j] + dp[i][j-1];
*/
const m: number = obstacleGrid.length;
const n: number = obstacleGrid[0].length;
const dp: number[][] = new Array(m).fill(0).map(_ => new Array(n).fill(0));
for (let i = 0; i < m && obstacleGrid[i][0] === 0; i++) {
dp[i][0] = 1;
}
for (let i = 0; i < n && obstacleGrid[0][i] === 0; i++) {
dp[0][i] = 1;
}
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
if (obstacleGrid[i][j] === 1) continue;
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
};
```
### C
```c
//初始化dp数组
int **initDP(int m, int n, int** obstacleGrid) {

View File

@ -308,7 +308,58 @@ var climbStairs = function(n) {
};
```
TypeScript
> 爬2阶
```typescript
function climbStairs(n: number): number {
/**
dp[i]: i阶楼梯的方法种数
dp[1]: 1;
dp[2]: 2;
...
dp[i]: dp[i - 1] + dp[i - 2];
*/
const dp: number[] = [];
dp[1] = 1;
dp[2] = 2;
for (let i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
};
```
> 爬m阶
```typescript
function climbStairs(n: number): number {
/**
一次可以爬m阶
dp[i]: i阶楼梯的方法种数
dp[1]: 1;
dp[2]: 2;
dp[3]: dp[2] + dp[1];
...
dp[i]: dp[i - 1] + dp[i - 2] + ... + dp[max(i - m, 1)]; 从i-1加到max(i-m, 1)
*/
const m: number = 2; // 本题m为2
const dp: number[] = new Array(n + 1).fill(0);
dp[1] = 1;
dp[2] = 2;
for (let i = 3; i <= n; i++) {
const end: number = Math.max(i - m, 1);
for (let j = i - 1; j >= end; j--) {
dp[i] += dp[j];
}
}
return dp[n];
};
```
### C
```c
int climbStairs(int n){
//若n<=2返回n

View File

@ -454,31 +454,36 @@ var partition = function(s) {
```typescript
function partition(s: string): string[][] {
function isPalindromeStr(s: string, left: number, right: number): boolean {
while (left < right) {
if (s[left++] !== s[right--]) {
return false;
const res: string[][] = []
const path: string[] = []
const isHuiwen = (
str: string,
startIndex: number,
endIndex: number
): boolean => {
for (; startIndex < endIndex; startIndex++, endIndex--) {
if (str[startIndex] !== str[endIndex]) {
return false
}
}
return true;
return true
}
function backTracking(s: string, startIndex: number, route: string[]): void {
let length: number = s.length;
if (length === startIndex) {
resArr.push(route.slice());
return;
const rec = (str: string, index: number): void => {
if (index >= str.length) {
res.push([...path])
return
}
for (let i = startIndex; i < length; i++) {
if (isPalindromeStr(s, startIndex, i)) {
route.push(s.slice(startIndex, i + 1));
backTracking(s, i + 1, route);
route.pop();
for (let i = index; i < str.length; i++) {
if (!isHuiwen(str, index, i)) {
continue
}
path.push(str.substring(index, i + 1))
rec(str, i + 1)
path.pop()
}
}
const resArr: string[][] = [];
backTracking(s, 0, []);
return resArr;
rec(s, 0)
return res
};
```

View File

@ -126,11 +126,11 @@ public:
## 其他语言版本
### Java
### Java
```java
class Solution {
/**
分两个阶段
/**
分两个阶段
1、起点下标1 从左往右,只要 右边 比 左边 大,右边的糖果=左边 + 1
2、起点下标 ratings.length - 2 从右往左, 只要左边 比 右边 大,此时 左边的糖果应该 取本身的糖果数(符合比它左边大) 和 右边糖果数 + 1 二者的最大值,这样才符合 它比它左边的大,也比它右边大
*/
@ -160,7 +160,7 @@ class Solution {
}
```
### Python
### Python
```python
class Solution:
def candy(self, ratings: List[int]) -> int:
@ -213,6 +213,25 @@ func findMax(num1 int ,num2 int) int{
}
```
### Rust
```rust
pub fn candy(ratings: Vec<i32>) -> i32 {
let mut candies = vec![1i32; ratings.len()];
for i in 1..ratings.len() {
if ratings[i - 1] < ratings[i] {
candies[i] = candies[i - 1] + 1;
}
}
for i in (0..ratings.len()-1).rev() {
if ratings[i] > ratings[i + 1] {
candies[i] = candies[i].max(candies[i + 1] + 1);
}
}
candies.iter().sum()
}
```
### Javascript:
```Javascript
var candy = function(ratings) {
@ -229,7 +248,7 @@ var candy = function(ratings) {
candys[i] = Math.max(candys[i], candys[i + 1] + 1)
}
}
let count = candys.reduce((a, b) => {
return a + b
})

View File

@ -168,6 +168,56 @@ func lengthOfLIS(nums []int ) int {
}
```
```go
// 动态规划求解
func lengthOfLIS(nums []int) int {
// dp数组的定义 dp[i]表示取第i个元素的时候表示子序列的长度其中包括 nums[i] 这个元素
dp := make([]int, len(nums))
// 初始化所有的元素都应该初始化为1
for i := range dp {
dp[i] = 1
}
ans := dp[0]
for i := 1; i < len(nums); i++ {
for j := 0; j < i; j++ {
if nums[i] > nums[j] {
dp[i] = max(dp[i], dp[j] + 1)
}
}
if dp[i] > ans {
ans = dp[i]
}
}
return ans
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
```
Rust:
```rust
pub fn length_of_lis(nums: Vec<i32>) -> i32 {
let mut dp = vec![1; nums.len() + 1];
let mut result = 1;
for i in 1..nums.len() {
for j in 0..i {
if nums[j] < nums[i] {
dp[i] = dp[i].max(dp[j] + 1);
}
result = result.max(dp[i]);
}
}
result
}
```
Javascript
```javascript
const lengthOfLIS = (nums) => {

View File

@ -220,7 +220,7 @@ class Solution:
for j in range(coin, amount + 1):
dp[j] = min(dp[j], dp[j - coin] + 1)
return dp[amount] if dp[amount] < amount + 1 else -1
def coinChange1(self, coins: List[int], amount: int) -> int:
'''版本二'''
# 初始化
@ -302,6 +302,24 @@ func min(a, b int) int {
```
Rust:
```rust
pub fn coin_change(coins: Vec<i32>, amount: i32) -> i32 {
let amount = amount as usize;
let mut dp = vec![i32::MAX; amount + 1];
dp[0] = 0;
for i in 0..coins.len() {
for j in coins[i] as usize..=amount {
if dp[j - coins[i] as usize] != i32::MAX {
dp[j] = dp[j].min(dp[j - coins[i] as usize] + 1);
}
}
}
if dp[amount] == i32::MAX { -1 } else { dp[amount] }
}
```
Javascript
```javascript
const coinChange = (coins, amount) => {

View File

@ -114,23 +114,25 @@ Java
```Java
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
//记录杂志字符串出现的次数
int[] arr = new int[26];
int temp;
for (int i = 0; i < magazine.length(); i++) {
temp = magazine.charAt(i) - 'a';
arr[temp]++;
// 定义一个哈希映射数组
int[] record = new int[26];
// 遍历
for(char c : magazine.toCharArray()){
record[c - 'a'] += 1;
}
for (int i = 0; i < ransomNote.length(); i++) {
temp = ransomNote.charAt(i) - 'a';
//对于金信中的每一个字符都在数组中查找
//找到相应位减一否则找不到返回false
if (arr[temp] > 0) {
arr[temp]--;
} else {
for(char c : ransomNote.toCharArray()){
record[c - 'a'] -= 1;
}
// 如果数组中存在负数说明ransomNote字符串总存在magazine中没有的字符
for(int i : record){
if(i < 0){
return false;
}
}
return true;
}
}

View File

@ -106,7 +106,7 @@ public:
## 其他语言版本
### Java
### Java
```java
class Solution {
// 思路1优先考虑饼干小饼干先喂饱小胃口
@ -145,7 +145,7 @@ class Solution {
}
```
### Python
### Python
```python
class Solution:
# 思路1优先考虑胃饼干
@ -166,13 +166,13 @@ class Solution:
s.sort()
start, count = len(s) - 1, 0
for index in range(len(g) - 1, -1, -1): # 先喂饱大胃口
if start >= 0 and g[index] <= s[start]:
if start >= 0 and g[index] <= s[start]:
start -= 1
count += 1
return count
```
### Go
### Go
```golang
//排序后,局部最优
func findContentChildren(g []int, s []int) int {
@ -191,7 +191,27 @@ func findContentChildren(g []int, s []int) int {
}
```
### Javascript
### Rust
```rust
pub fn find_content_children(children: Vec<i32>, cookie: Vec<i32>) -> i32 {
let mut children = children;
let mut cookies = cookie;
children.sort();
cookies.sort();
let (mut child, mut cookie) = (0usize, 0usize);
while child < children.len() && cookie < cookies.len() {
// 优先选择最小饼干喂饱孩子
if children[child] <= cookies[cookie] {
child += 1;
}
cookie += 1
}
child as i32
}
```
### Javascript
```js
var findContentChildren = function(g, s) {
g = g.sort((a, b) => a - b)
@ -203,7 +223,7 @@ var findContentChildren = function(g, s) {
result++
index--
}
}
}
return result
};
@ -251,7 +271,7 @@ function findContentChildren(g: number[], s: number[]): number {
};
```
### C
### C
```c
int cmp(int* a, int* b) {
@ -261,7 +281,7 @@ int cmp(int* a, int* b) {
int findContentChildren(int* g, int gSize, int* s, int sSize){
if(sSize == 0)
return 0;
//将两个数组排序为升序
qsort(g, gSize, sizeof(int), cmp);
qsort(s, sSize, sizeof(int), cmp);

View File

@ -244,6 +244,39 @@ class Solution:
```
Go
> 未精简版本
```go
func nextGreaterElement(nums1 []int, nums2 []int) []int {
res := make([]int, len(nums1))
for i := range res { res[i] = -1 }
m := make(map[int]int, len(nums1))
for k, v := range nums1 { m[v] = k }
stack := []int{0}
for i := 1; i < len(nums2); i++ {
top := stack[len(stack)-1]
if nums2[i] < nums2[top] {
stack = append(stack, i)
} else if nums2[i] == nums2[top] {
stack = append(stack, i)
} else {
for len(stack) != 0 && nums2[i] > nums2[top] {
if v, ok := m[nums2[top]]; ok {
res[v] = nums2[i]
}
stack = stack[:len(stack)-1]
if len(stack) != 0 {
top = stack[len(stack)-1]
}
}
stack = append(stack, i)
}
}
return res
}
```
> 精简版本
```go
func nextGreaterElement(nums1 []int, nums2 []int) []int {
res := make([]int, len(nums1))

View File

@ -245,7 +245,29 @@ var fib = function(n) {
};
```
TypeScript
```typescript
function fib(n: number): number {
/**
dp[i]: 第i个斐波那契数
dp[0]: 0;
dp[1]1
...
dp[i] = dp[i - 1] + dp[i - 2];
*/
const dp: number[] = [];
dp[0] = 0;
dp[1] = 1;
for (let i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
};
```
### C
动态规划:
```c
int fib(int n){

View File

@ -242,6 +242,22 @@ func change(amount int, coins []int) int {
}
```
Rust:
```rust
pub fn change(amount: i32, coins: Vec<i32>) -> i32 {
let amount = amount as usize;
let coins = coins.iter().map(|&c|c as usize).collect::<Vec<usize>>();
let mut dp = vec![0usize; amount + 1];
dp[0] = 1;
for i in 0..coins.len() {
for j in coins[i]..=amount {
dp[j] += dp[j - coins[i]];
}
}
dp[amount] as i32
}
```
Javascript
```javascript
const change = (amount, coins) => {

View File

@ -218,6 +218,7 @@ class Solution:
return result
```
> 贪心法:
```python
class Solution:
@ -236,6 +237,63 @@ class Solution:
```
Go
> 动态规划:
```go
func findLengthOfLCIS(nums []int) int {
if len(nums) == 0 {return 0}
res, count := 1, 1
for i := 0; i < len(nums)-1; i++ {
if nums[i+1] > nums[i] {
count++
}else {
count = 1
}
if count > res {
res = count
}
}
return res
}
```
> 贪心算法:
```go
func findLengthOfLCIS(nums []int) int {
if len(nums) == 0 {return 0}
dp := make([]int, len(nums))
for i := 0; i < len(dp); i++ {
dp[i] = 1
}
res := 1
for i := 0; i < len(nums)-1; i++ {
if nums[i+1] > nums[i] {
dp[i+1] = dp[i] + 1
}
if dp[i+1] > res {
res = dp[i+1]
}
}
return res
}
```
Rust:
```rust
pub fn find_length_of_lcis(nums: Vec<i32>) -> i32 {
if nums.is_empty() {
return 0;
}
let mut result = 1;
let mut dp = vec![1; nums.len()];
for i in 1..nums.len() {
if nums[i - 1] < nums[i] {
dp[i] = dp[i - 1] + 1;
result = result.max(dp[i]);
}
}
result
}
```
Javascript

View File

@ -293,6 +293,50 @@ var maxProfit = function(prices, fee) {
};
```
TypeScript
> 贪心
```typescript
function maxProfit(prices: number[], fee: number): number {
if (prices.length === 0) return 0;
let minPrice: number = prices[0];
let profit: number = 0;
for (let i = 1, length = prices.length; i < length; i++) {
if (minPrice > prices[i]) {
minPrice = prices[i];
}
if (minPrice + fee < prices[i]) {
profit += prices[i] - minPrice - fee;
minPrice = prices[i] - fee;
}
}
return profit;
};
```
> 动态规划
```typescript
function maxProfit(prices: number[], fee: number): number {
/**
dp[i][1]: 第i天不持有股票的最大所剩现金
dp[i][0]: 第i天持有股票的最大所剩现金
*/
const length: number = prices.length;
const dp: number[][] = new Array(length).fill(0).map(_ => []);
dp[0][1] = 0;
dp[0][0] = -prices[0];
for (let i = 1, length = prices.length; i < length; i++) {
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
}
return Math.max(dp[length - 1][0], dp[length - 1][1]);
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -225,6 +225,28 @@ var monotoneIncreasingDigits = function(n) {
};
```
### TypeScript
```typescript
function monotoneIncreasingDigits(n: number): number {
let strArr: number[] = String(n).split('').map(i => parseInt(i));
const length = strArr.length;
let flag: number = length;
for (let i = length - 2; i >= 0; i--) {
if (strArr[i] > strArr[i + 1]) {
strArr[i] -= 1;
flag = i + 1;
}
}
for (let i = flag; i < length; i++) {
strArr[i] = 9;
}
return parseInt(strArr.join(''));
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -34,7 +34,7 @@
那么单调栈的原理是什么呢为什么时间复杂度是O(n)就可以找到每一个元素的右边第一个比它大的元素位置呢?
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素的元素,优点是只需要遍历一次。
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素的元素,优点是只需要遍历一次。
在使用单调栈的时候首先要明确如下几点:
@ -233,7 +233,7 @@ class Solution {
}
```
Python
``` Python3
```python
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
answer = [0]*len(temperatures)
@ -277,8 +277,36 @@ func dailyTemperatures(t []int) []int {
}
```
> 单调栈法
> 单调栈法(未精简版本)
```go
func dailyTemperatures(temperatures []int) []int {
res := make([]int, len(temperatures))
// 初始化栈顶元素为第一个下标索引0
stack := []int{0}
for i := 1; i < len(temperatures); i++ {
top := stack[len(stack)-1]
if temperatures[i] < temperatures[top] {
stack = append(stack, i)
} else if temperatures[i] == temperatures[top] {
stack = append(stack, i)
} else {
for len(stack) != 0 && temperatures[i] > temperatures[top] {
res[top] = i - top
stack = stack[:len(stack)-1]
if len(stack) != 0 {
top = stack[len(stack)-1]
}
}
stack = append(stack, i)
}
}
return res
}
```
> 单调栈法(精简版本)
```go
// 单调递减栈
func dailyTemperatures(num []int) []int {

View File

@ -266,7 +266,30 @@ var minCostClimbingStairs = function(cost) {
};
```
### TypeScript
```typescript
function minCostClimbingStairs(cost: number[]): number {
/**
dp[i]: 走到第i阶需要花费的最少金钱
dp[0]: cost[0];
dp[1]: cost[1];
...
dp[i]: min(dp[i - 1], dp[i - 2]) + cost[i];
*/
const dp: number[] = [];
const length: number = cost.length;
dp[0] = cost[0];
dp[1] = cost[1];
for (let i = 2; i <= length; i++) {
dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i];
}
return Math.min(dp[length - 1], dp[length - 2]);
};
```
### C
```c
int minCostClimbingStairs(int* cost, int costSize){
//开辟dp数组大小为costSize

View File

@ -476,7 +476,35 @@ var minCameraCover = function(root) {
};
```
### TypeScript
```typescript
function minCameraCover(root: TreeNode | null): number {
/** 0-无覆盖, 1-有摄像头, 2-有覆盖 */
type statusCode = 0 | 1 | 2;
let resCount: number = 0;
if (recur(root) === 0) resCount++;
return resCount;
function recur(node: TreeNode | null): statusCode {
if (node === null) return 2;
const left: statusCode = recur(node.left),
right: statusCode = recur(node.right);
let resStatus: statusCode = 0;
if (left === 0 || right === 0) {
resStatus = 1;
resCount++;
} else if (left === 1 || right === 1) {
resStatus = 2;
} else {
resStatus = 0;
}
return resStatus;
}
};
```
### C
```c
/*
**函数后序遍历二叉树。判断一个结点状态时,根据其左右孩子结点的状态进行判断

View File

@ -111,7 +111,6 @@ class Solution:
Golang:
```go
func maxUncrossedLines(A []int, B []int) int {
m, n := len(A), len(B)
dp := make([][]int, m+1)
@ -140,7 +139,26 @@ func max(a, b int) int {
}
```
Rust:
```rust
pub fn max_uncrossed_lines(nums1: Vec<i32>, nums2: Vec<i32>) -> i32 {
let (n, m) = (nums1.len(), nums2.len());
let mut last = vec![0; m + 1]; // 记录滚动数组
let mut dp = vec![0; m + 1];
for i in 1..=n {
dp.swap_with_slice(&mut last);
for j in 1..=m {
if nums1[i - 1] == nums2[j - 1] {
dp[j] = last[j - 1] + 1;
} else {
dp[j] = last[j].max(dp[j - 1]);
}
}
}
dp[m]
}
```
JavaScript

View File

@ -4,40 +4,40 @@
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
## 1143.最长公共子序列
## 1143.最长公共子序列
[力扣题目链接](https://leetcode-cn.com/problems/longest-common-subsequence/)
给定两个字符串 text1 和 text2返回这两个字符串的最长公共子序列的长度。
给定两个字符串 text1 和 text2返回这两个字符串的最长公共子序列的长度。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。
若这两个字符串没有公共子序列,则返回 0。
若这两个字符串没有公共子序列,则返回 0。
示例 1:
示例 1:
输入text1 = "abcde", text2 = "ace"
输出3
解释:最长公共子序列是 "ace",它的长度为 3。
输入text1 = "abcde", text2 = "ace"
输出3
解释:最长公共子序列是 "ace",它的长度为 3。
示例 2:
输入text1 = "abc", text2 = "abc"
输出3
解释:最长公共子序列是 "abc",它的长度为 3。
示例 2:
输入text1 = "abc", text2 = "abc"
输出3
解释:最长公共子序列是 "abc",它的长度为 3。
示例 3:
输入text1 = "abc", text2 = "def"
输出0
解释:两个字符串没有公共子序列,返回 0。
示例 3:
输入text1 = "abc", text2 = "def"
输出0
解释:两个字符串没有公共子序列,返回 0。
提示:
提示:
* 1 <= text1.length <= 1000
* 1 <= text2.length <= 1000
输入的字符串只含有小写英文字符。
## 思路
## 思路
本题和[动态规划718. 最长重复子数组](https://programmercarl.com/0718.最长重复子数组.html)区别在于这里不要求是连续的了,但要有相对顺序,即:"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
@ -45,21 +45,21 @@
1. 确定dp数组dp table以及下标的含义
dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
有同学会问:为什么要定义长度为[0, i - 1]的字符串text1定义为长度为[0, i]的字符串text1不香么
有同学会问:为什么要定义长度为[0, i - 1]的字符串text1定义为长度为[0, i]的字符串text1不香么
这样定义是为了后面代码实现方便,如果非要定义为为长度为[0, i]的字符串text1也可以大家可以试一试
2. 确定递推公式
主要就是两大情况: text1[i - 1] 与 text2[j - 1]相同text1[i - 1] 与 text2[j - 1]不相同
主要就是两大情况: text1[i - 1] 与 text2[j - 1]相同text1[i - 1] 与 text2[j - 1]不相同
如果text1[i - 1] 与 text2[j - 1]相同那么找到了一个公共元素所以dp[i][j] = dp[i - 1][j - 1] + 1;
如果text1[i - 1] 与 text2[j - 1]相同那么找到了一个公共元素所以dp[i][j] = dp[i - 1][j - 1] + 1;
如果text1[i - 1] 与 text2[j - 1]不相同那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的。
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
代码如下:
@ -71,9 +71,9 @@ if (text1[i - 1] == text2[j - 1]) {
}
```
3. dp数组如何初始化
3. dp数组如何初始化
先看看dp[i][0]应该是多少呢?
先看看dp[i][0]应该是多少呢?
test1[0, i-1]和空串的最长公共子序列自然是0所以dp[i][0] = 0;
@ -101,7 +101,7 @@ vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));
![1143.最长公共子序列1](https://img-blog.csdnimg.cn/20210210150215918.jpg)
最后红框dp[text1.size()][text2.size()]为最终结果
最后红框dp[text1.size()][text2.size()]为最终结果
以上分析完毕C++代码如下:
@ -158,7 +158,7 @@ class Solution:
for i in range(1, len2):
for j in range(1, len1): # 开始列出状态转移方程
if text1[j-1] == text2[i-1]:
dp[i][j] = dp[i-1][j-1]+1
dp[i][j] = dp[i-1][j-1]+1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
return dp[-1][-1]
@ -189,10 +189,32 @@ func longestCommonSubsequence(text1 string, text2 string) int {
func max(a,b int)int {
if a>b{
return a
return a
}
return b
}
```
Rust:
```rust
pub fn longest_common_subsequence(text1: String, text2: String) -> i32 {
let (n, m) = (text1.len(), text2.len());
let (s1, s2) = (text1.as_bytes(), text2.as_bytes());
let mut dp = vec![0; m + 1];
let mut last = vec![0; m + 1];
for i in 1..=n {
dp.swap_with_slice(&mut last);
for j in 1..=m {
dp[j] = if s1[i - 1] == s2[j - 1] {
last[j - 1] + 1
} else {
last[j].max(dp[j - 1])
};
}
}
dp[m]
}
```
Javascript

View File

@ -11,9 +11,9 @@
看完本篇大家可以使用迭代法再重新解决如下三道leetcode上的题目
* 144.二叉树的前序遍历
* 94.二叉树的中序遍历
* 145.二叉树的后序遍历
* [144.二叉树的前序遍历](https://leetcode-cn.com/problems/binary-tree-preorder-traversal/)
* [94.二叉树的中序遍历](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/)
* [145.二叉树的后序遍历](https://leetcode-cn.com/problems/binary-tree-postorder-traversal/)
为什么可以用迭代法(非递归的方式)来实现二叉树的前后中序遍历呢?

View File

@ -99,9 +99,9 @@ void traversal(TreeNode* cur, vector<int>& vec) {
此时大家可以做一做leetcode上三道题目分别是
* 144.二叉树的前序遍历
* 145.二叉树的后序遍历
* 94.二叉树的中序遍历
* [144.二叉树的前序遍历](https://leetcode-cn.com/problems/binary-tree-preorder-traversal/)
* [145.二叉树的后序遍历](https://leetcode-cn.com/problems/binary-tree-postorder-traversal/)
* [94.二叉树的中序遍历](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/)
可能有同学感觉前后中序遍历的递归太简单了,要打迭代法(非递归),别急,我们明天打迭代法,打个通透!

View File

@ -380,28 +380,37 @@ func main() {
### javascript
```js
function testweightbagproblem (wight, value, size) {
const len = wight.length,
dp = array.from({length: len + 1}).map(
() => array(size + 1).fill(0)
);
for(let i = 1; i <= len; i++) {
for(let j = 0; j <= size; j++) {
if(wight[i - 1] <= j) {
dp[i][j] = math.max(
dp[i - 1][j],
value[i - 1] + dp[i - 1][j - wight[i - 1]]
)
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
/**
*
* @param {Number []} weight
* @param {Number []} value
* @param {Number} size
* @returns
*/
// console.table(dp);
function testWeightBagProblem(weight, value, size) {
const len = weight.length,
dp = Array.from({length: len}).map(
() => Array(size + 1)) //JavaScript 数组是引用类型
for(let i = 0; i < len; i++) { //初始化最左一列即背包容量为0时的情况
dp[i][0] = 0;
}
for(let j = 1; j < size+1; j++) { //初始化第0行, 只有一件物品的情况
if(weight[0] <= j) {
dp[0][j] = value[0];
} else {
dp[0][j] = 0;
}
}
for(let i = 1; i < len; i++) { //dp[i][j]由其左上方元素推导得出
for(let j = 1; j < size+1; j++) {
if(j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j - weight[i]] + value[i]);
}
}
return dp[len][size];
return dp[len-1][size] //满足条件的最大值
}
function testWeightBagProblem2 (wight, value, size) {