Merge branch 'master' of github.com:youngyangyang04/leetcode-master

This commit is contained in:
youngyangyang04
2021-09-18 09:04:04 +08:00
33 changed files with 1568 additions and 50 deletions

View File

@ -409,6 +409,66 @@ var letterCombinations = function(digits) {
};
```
C:
```c
char* path;
int pathTop;
char** result;
int resultTop;
char* letterMap[10] = {"", //0
"", //1
"abc", //2
"def", //3
"ghi", //4
"jkl", //5
"mno", //6
"pqrs", //7
"tuv", //8
"wxyz", //9
};
void backTracking(char* digits, int index) {
//若当前下标等于digits数组长度
if(index == strlen(digits)) {
//复制digits数组因为最后要多存储一个0所以数组长度要+1
char* tempString = (char*)malloc(sizeof(char) * strlen(digits) + 1);
int j;
for(j = 0; j < strlen(digits); j++) {
tempString[j] = path[j];
}
//char数组最后要以0结尾
tempString[strlen(digits)] = 0;
result[resultTop++] = tempString;
return ;
}
//将字符数字转换为真的数字
int digit = digits[index] - '0';
//找到letterMap中对应的字符串
char* letters = letterMap[digit];
int i;
for(i = 0; i < strlen(letters); i++) {
path[pathTop++] = letters[i];
//递归,处理下一层数字
backTracking(digits, index+1);
pathTop--;
}
}
char ** letterCombinations(char * digits, int* returnSize){
//初始化path和result
path = (char*)malloc(sizeof(char) * strlen(digits));
result = (char**)malloc(sizeof(char*) * 300);
*returnSize = 0;
//若digits数组中元素个数为0返回空集
if(strlen(digits) == 0)
return result;
pathTop = resultTop = 0;
backTracking(digits, 0);
*returnSize = resultTop;
return result;
}
```
-----------------------

View File

@ -376,6 +376,61 @@ class Solution:
Go
```go
func solveSudoku(board [][]byte) {
var backtracking func(board [][]byte) bool
backtracking=func(board [][]byte) bool{
for i:=0;i<9;i++{
for j:=0;j<9;j++{
//判断此位置是否适合填数字
if board[i][j]!='.'{
continue
}
//尝试填1-9
for k:='1';k<='9';k++{
if isvalid(i,j,byte(k),board)==true{//如果满足要求就填
board[i][j]=byte(k)
if backtracking(board)==true{
return true
}
board[i][j]='.'
}
}
return false
}
}
return true
}
backtracking(board)
}
//判断填入数字是否满足要求
func isvalid(row,col int,k byte,board [][]byte)bool{
for i:=0;i<9;i++{//行
if board[row][i]==k{
return false
}
}
for i:=0;i<9;i++{//列
if board[i][col]==k{
return false
}
}
//方格
startrow:=(row/3)*3
startcol:=(col/3)*3
for i:=startrow;i<startrow+3;i++{
for j:=startcol;j<startcol+3;j++{
if board[i][j]==k{
return false
}
}
}
return true
}
```
Javascript:
```Javascript
var solveSudoku = function(board) {

View File

@ -346,6 +346,60 @@ var combinationSum = function(candidates, target) {
};
```
C:
```c
int* path;
int pathTop;
int** ans;
int ansTop;
//记录每一个和等于target的path数组长度
int* length;
void backTracking(int target, int index, int* candidates, int candidatesSize, int sum) {
//若sum>=target就应该终止遍历
if(sum >= target) {
//若sum等于target将当前的组合放入ans数组中
if(sum == target) {
int* tempPath = (int*)malloc(sizeof(int) * pathTop);
int j;
for(j = 0; j < pathTop; j++) {
tempPath[j] = path[j];
}
ans[ansTop] = tempPath;
length[ansTop++] = pathTop;
}
return ;
}
int i;
for(i = index; i < candidatesSize; i++) {
//将当前数字大小加入sum
sum+=candidates[i];
path[pathTop++] = candidates[i];
backTracking(target, i, candidates, candidatesSize, sum);
sum-=candidates[i];
pathTop--;
}
}
int** combinationSum(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes){
//初始化变量
path = (int*)malloc(sizeof(int) * 50);
ans = (int**)malloc(sizeof(int*) * 200);
length = (int*)malloc(sizeof(int) * 200);
ansTop = pathTop = 0;
backTracking(target, 0, candidates, candidatesSize, 0);
//设置返回的数组大小
*returnSize = ansTop;
*returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);
int i;
for(i = 0; i < ansTop; i++) {
(*returnColumnSizes)[i] = length[i];
}
return ans;
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -392,7 +392,66 @@ var combinationSum2 = function(candidates, target) {
}
};
```
C:
```c
int* path;
int pathTop;
int** ans;
int ansTop;
//记录ans中每一个一维数组的大小
int* length;
int cmp(const void* a1, const void* a2) {
return *((int*)a1) - *((int*)a2);
}
void backTracking(int* candidates, int candidatesSize, int target, int sum, int startIndex) {
if(sum >= target) {
//若sum等于target复制当前path进入
if(sum == target) {
int* tempPath = (int*)malloc(sizeof(int) * pathTop);
int j;
for(j = 0; j < pathTop; j++) {
tempPath[j] = path[j];
}
length[ansTop] = pathTop;
ans[ansTop++] = tempPath;
}
return ;
}
int i;
for(i = startIndex; i < candidatesSize; i++) {
//对同一层树中使用过的元素跳过
if(i > startIndex && candidates[i] == candidates[i-1])
continue;
path[pathTop++] = candidates[i];
sum += candidates[i];
backTracking(candidates, candidatesSize, target, sum, i + 1);
//回溯
sum -= candidates[i];
pathTop--;
}
}
int** combinationSum2(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes){
path = (int*)malloc(sizeof(int) * 50);
ans = (int**)malloc(sizeof(int*) * 100);
length = (int*)malloc(sizeof(int) * 100);
pathTop = ansTop = 0;
//快速排序candidates让相同元素挨到一起
qsort(candidates, candidatesSize, sizeof(int), cmp);
backTracking(candidates, candidatesSize, target, 0, 0);
*returnSize = ansTop;
*returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);
int i;
for(i = 0; i < ansTop; i++) {
(*returnColumnSizes)[i] = length[i];
}
return ans;
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -134,6 +134,43 @@ public:
因为每次遍历列的时候还要向两边寻找最高的列所以时间复杂度为O(n^2)。
空间复杂度为O(1)。
一种更简便的双指针方法:
之前的双指针方法的原理是固定“底”的位置,往两边找比它高的“壁”,循环若干次求和。
我们逆向思维,把“壁”用两个初始位置在数组首末位置的指针表示,“壁”往中间推,同样可以让每个“底”都能找到最高的“壁”
本质上就是改变了运算方向,从而减少了重复运算
代码如下:
```C
int trap(int* height, int heightSize) {
int ans = 0;
int left = 0, right = heightSize - 1; //初始化两个指针到左右两边
int leftMax = 0, rightMax = 0; //这两个值用来记录左右的“壁”的最高值
while (left < right) { //两个指针重合就结束
leftMax = fmax(leftMax, height[left]);
rightMax = fmax(rightMax, height[right]);
if (leftMax < rightMax) {
ans += leftMax - height[left]; //这里考虑的是下标为left的“底”能装多少水
++left;//指针的移动次序是这个方法的关键
//这里左指针右移是因为左“墙”较矮,左边这一片实际情况下的盛水量是受制于这个矮的左“墙”的
//而较高的右边在实际情况下的限制条件可能不是当前的左“墙”,比如限制条件可能是右“墙”,就能装更高的水,
}
else {
ans += rightMax - height[right]; //同理考虑下标为right的元素
--right;
}
}
return ans;
}
```
时间复杂度 O(n)
空间复杂度 O(1)
## 动态规划解法
在上一节的双指针解法中,我们可以看到只要记录左边柱子的最高高度 和 右边柱子的最高高度,就可以计算当前位置的雨水面积,这就是通过列来计算。

View File

@ -469,6 +469,65 @@ class Solution {
}
```
C:
```c
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
//初始化返回的结果数组的大小
*returnSize = n;
*returnColumnSizes = (int*)malloc(sizeof(int) * n);
//初始化返回结果数组ans
int** ans = (int**)malloc(sizeof(int*) * n);
int i;
for(i = 0; i < n; i++) {
ans[i] = (int*)malloc(sizeof(int) * n);
(*returnColumnSizes)[i] = n;
}
//设置每次循环的起始位置
int startX = 0;
int startY = 0;
//设置二维数组的中间值若n为奇数。需要最后在中间填入数字
int mid = n / 2;
//循环圈数
int loop = n / 2;
//偏移数
int offset = 1;
//当前要添加的元素
int count = 1;
while(loop) {
int i = startX;
int j = startY;
//模拟上侧从左到右
for(; j < startY + n - offset; j++) {
ans[startX][j] = count++;
}
//模拟右侧从上到下
for(; i < startX + n - offset; i++) {
ans[i][j] = count++;
}
//模拟下侧从右到左
for(; j > startY; j--) {
ans[i][j] = count++;
}
//模拟左侧从下到上
for(; i > startX; i--) {
ans[i][j] = count++;
}
//偏移值每次加2
offset+=2;
//遍历起始位置每次+1
startX++;
startY++;
loop--;
}
//若n为奇数需要单独给矩阵中间赋值
if(n%2)
ans[mid][mid] = count;
return ans;
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -1173,7 +1173,7 @@ public:
if (root != NULL) que.push(root);
while (!que.empty()) {
int size = que.size();
vector<int> vec;
// vector<int> vec;
Node* nodePre;
Node* node;
for (int i = 0; i < size; i++) {
@ -1570,9 +1570,43 @@ class Solution:
return len(result)
```
Go
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func maxDepth(root *TreeNode) int {
ans:=0
if root==nil{
return 0
}
queue:=list.New()
queue.PushBack(root)
for queue.Len()>0{
length:=queue.Len()
for i:=0;i<length;i++{
node:=queue.Remove(queue.Front()).(*TreeNode)
if node.Left!=nil{
queue.PushBack(node.Left)
}
if node.Right!=nil{
queue.PushBack(node.Right)
}
}
ans++//记录深度,其他的是层序遍历的板子
}
return ans
}
```
JavaScript
# 111.二叉树的最小深度
@ -1674,6 +1708,46 @@ class Solution:
Go
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func minDepth(root *TreeNode) int {
ans:=0
if root==nil{
return 0
}
queue:=list.New()
queue.PushBack(root)
for queue.Len()>0{
length:=queue.Len()
for i:=0;i<length;i++{
node:=queue.Remove(queue.Front()).(*TreeNode)
if node.Left==nil&&node.Right==nil{//当前节点没有左右节点,则代表此层是最小层
return ans+1//返回当前层 ans代表是上一层
}
if node.Left!=nil{
queue.PushBack(node.Left)
}
if node.Right!=nil{
queue.PushBack(node.Right)
}
}
ans++//记录层数
}
return ans+1
}
```
JavaScript

View File

@ -214,6 +214,26 @@ class Solution {
}
}
```
```java
// 解法1
class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) return 0;
int length = prices.length;
// dp[i][0]代表第i天持有股票的最大收益
// dp[i][1]代表第i天不持有股票的最大收益
int[][] dp = new int[length][2];
int result = 0;
dp[0][0] = -prices[0];
dp[0][1] = 0;
for (int i = 1; i < length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], -prices[i]);
dp[i][1] = Math.max(dp[i - 1][0] + prices[i], dp[i - 1][1]);
}
return dp[length - 1][1];
}
}
```
``` java
class Solution { // 动态规划解法

View File

@ -202,6 +202,7 @@ Go
Javascript
```javascript
// 方法一动态规划dp 数组)
const maxProfit = (prices) => {
let dp = Array.from(Array(prices.length), () => Array(2).fill(0));
// dp[i][0] 表示第i天持有股票所得现金。
@ -222,6 +223,21 @@ const maxProfit = (prices) => {
return dp[prices.length -1][0];
};
// 方法二:动态规划(滚动数组)
const maxProfit = (prices) => {
// 滚动数组
// have: 第i天持有股票最大收益; notHave: 第i天不持有股票最大收益
let n = prices.length,
have = -prices[0],
notHave = 0;
for (let i = 1; i < n; i++) {
have = Math.max(have, notHave - prices[i]);
notHave = Math.max(notHave, have + prices[i]);
}
// 最终手里不持有股票才能保证收益最大化
return notHave;
}
```

View File

@ -281,6 +281,48 @@ func canCompleteCircuit(gas []int, cost []int) int {
```
Javascript:
暴力:
```js
var canCompleteCircuit = function(gas, cost) {
for(let i = 0; i < cost.length; i++) {
let rest = gas[i] - cost[i] //记录剩余油量
// 以i为起点行驶一圈index为下一个目的地
let index = (i + 1) % cost.length
while(rest > 0 && index !== i) {
rest += gas[index] - cost[index]
index = (index + 1) % cost.length
}
if(rest >= 0 && index === i) return i
}
return -1
};
```
解法一:
```js
var canCompleteCircuit = function(gas, cost) {
let curSum = 0
let min = Infinity
for(let i = 0; i < gas.length; i++) {
let rest = gas[i] - cost[i]
curSum += rest
if(curSum < min) {
min = curSum
}
}
if(curSum < 0) return -1 //1.总油量 小于 总消耗量
if(min >= 0) return 0 //2. 说明油箱里油没断过
//3. 从后向前,看哪个节点能这个负数填平,能把这个负数填平的节点就是出发节点
for(let i = gas.length -1; i >= 0; i--) {
let rest = gas[i] - cost[i]
min += rest
if(min >= 0) {
return i
}
}
return -1
}
```
解法二:
```Javascript
var canCompleteCircuit = function(gas, cost) {
const gasLen = gas.length

View File

@ -392,7 +392,63 @@ var combinationSum3 = function(k, n) {
};
```
C:
```c
int* path;
int pathTop;
int** ans;
int ansTop;
int getPathSum() {
int i;
int sum = 0;
for(i = 0; i < pathTop; i++) {
sum += path[i];
}
return sum;
}
void backtracking(int targetSum, int k, int sum, int startIndex) {
if(pathTop == k) {
if(sum == targetSum) {
int* tempPath = (int*)malloc(sizeof(int) * k);
int j;
for(j = 0; j < k; j++)
tempPath[j] = path[j];
ans[ansTop++] = tempPath;
}
// 如果path.size() == k 但sum != targetSum 直接返回
return;
}
int i;
//从startIndex开始遍历一直遍历到9
for (i = startIndex; i <= 9; i++) {
sum += i; // 处理
path[pathTop++] = i; // 处理
backtracking(targetSum, k, sum, i + 1); // 注意i+1调整startIndex
sum -= i; // 回溯
pathTop--;; // 回溯
}
}
int** combinationSum3(int k, int n, int* returnSize, int** returnColumnSizes){
//初始化辅助变量
path = (int*)malloc(sizeof(int) * k);
ans = (int**)malloc(sizeof(int*) * 20);
pathTop = ansTop = 0;
backtracking(n, k, 0, 1);
//设置返回的二维数组中元素个数为ansTop
*returnSize = ansTop;
//设置二维数组中每个元素个数的大小为k
*returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);
int i;
for(i = 0; i < ansTop; i++) {
(*returnColumnSizes)[i] = k;
}
return ans;
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -363,7 +363,9 @@ class Solution:
return root
```
### Go
### Go
递归版本的前序遍历
```Go
func invertTree(root *TreeNode) *TreeNode {
@ -381,6 +383,96 @@ func invertTree(root *TreeNode) *TreeNode {
}
```
递归版本的后序遍历
```go
func invertTree(root *TreeNode) *TreeNode {
if root==nil{
return root
}
invertTree(root.Left)//遍历左节点
invertTree(root.Right)//遍历右节点
root.Left,root.Right=root.Right,root.Left//交换
return root
}
```
迭代版本的前序遍历
```go
func invertTree(root *TreeNode) *TreeNode {
stack:=[]*TreeNode{}
node:=root
for node!=nil||len(stack)>0{
for node!=nil{
node.Left,node.Right=node.Right,node.Left//交换
stack=append(stack,node)
node=node.Left
}
node=stack[len(stack)-1]
stack=stack[:len(stack)-1]
node=node.Right
}
return root
}
```
迭代版本的后序遍历
```go
func invertTree(root *TreeNode) *TreeNode {
stack:=[]*TreeNode{}
node:=root
var prev *TreeNode
for node!=nil||len(stack)>0{
for node!=nil{
stack=append(stack,node)
node=node.Left
}
node=stack[len(stack)-1]
stack=stack[:len(stack)-1]
if node.Right==nil||node.Right==prev{
node.Left,node.Right=node.Right,node.Left//交换
prev=node
node=nil
}else {
stack=append(stack,node)
node=node.Right
}
}
return root
}
```
层序遍历
```go
func invertTree(root *TreeNode) *TreeNode {
if root==nil{
return root
}
queue:=list.New()
node:=root
queue.PushBack(node)
for queue.Len()>0{
length:=queue.Len()
for i:=0;i<length;i++{
e:=queue.Remove(queue.Front()).(*TreeNode)
e.Left,e.Right=e.Right,e.Left//交换
if e.Left!=nil{
queue.PushBack(e.Left)
}
if e.Right!=nil{
queue.PushBack(e.Right)
}
}
}
return root
}
```
### JavaScript
使用递归版本的前序遍历

View File

@ -256,6 +256,25 @@ class Solution {
}
```
Rust
```rust
impl Solution {
pub fn is_anagram(s: String, t: String) -> bool {
let mut record = vec![0; 26];
let baseChar = 'a';
for byte in s.bytes() {
record[byte as usize - baseChar as usize] += 1;
}
for byte in t.bytes() {
record[byte as usize - baseChar as usize] -= 1;
}
record.iter().filter(|x| **x != 0).count() == 0
}
}
```
## 相关题目
* 383.赎金信

View File

@ -408,25 +408,57 @@ class Solution {
Python
```Python
class Solution:
"""二叉树的所有路径 递归法"""
def binaryTreePaths(self, root: TreeNode) -> List[str]:
path=[]
res=[]
def backtrace(root, path):
if not root:return
path.append(root.val)
if (not root.left)and (not root.right):
res.append(path[:])
ways=[]
if root.left:ways.append(root.left)
if root.right:ways.append(root.right)
for way in ways:
backtrace(way,path)
path.pop()
backtrace(root,path)
return ["->".join(list(map(str,i))) for i in res]
path, result = '', []
self.traversal(root, path, result)
return result
def traversal(self, cur: TreeNode, path: List, result: List):
path += str(cur.val)
# 如果当前节点为叶子节点,添加路径到结果中
if not (cur.left or cur.right):
result.append(path)
return
if cur.left:
self.traversal(cur.left, path + '->', result)
if cur.right:
self.traversal(cur.right, path + '->', result)
```
```python
from collections import deque
class Solution:
"""二叉树的所有路径 迭代法"""
def binaryTreePaths(self, root: TreeNode) -> List[str]:
# 题目中节点数至少为1
stack, path_st, result = deque([root]), deque(), []
path_st.append(str(root.val))
while stack:
cur = stack.pop()
path = path_st.pop()
# 如果当前节点为叶子节点,添加路径到结果中
if not (cur.left or cur.right):
result.append(path)
if cur.right:
stack.append(cur.right)
path_st.append(path + '->' + str(cur.right.val))
if cur.left:
stack.append(cur.left)
path_st.append(path + '->' + str(cur.left.val))
return result
```
Go
```go
func binaryTreePaths(root *TreeNode) []string {

View File

@ -206,6 +206,7 @@ var reverseString = function(s) {
Swift:
```swift
// 双指针 - 元组
func reverseString(_ s: inout [Character]) {
var l = 0
var r = s.count - 1
@ -216,11 +217,18 @@ func reverseString(_ s: inout [Character]) {
r -= 1
}
}
// 双指针法 - 库函数
func reverseString(_ s: inout [Character]) {
var j = s.count - 1
for i in 0 ..< Int(Double(s.count) * 0.5) {
s.swapAt(i, j)
j -= 1
}
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)

View File

@ -238,6 +238,25 @@ class Solution {
}
```
Rust:
```rust
use std::collections::HashSet;
impl Solution {
pub fn intersection(nums1: Vec<i32>, nums2: Vec<i32>) -> Vec<i32> {
let mut resultSet: HashSet<i32> = HashSet::with_capacity(1000);
let nums1Set: HashSet<i32> = nums1.into_iter().collect();
for num in nums2.iter() {
if nums1Set.contains(num) {
resultSet.insert(*num);
}
}
let ret: Vec<i32> = resultSet.into_iter().collect();
ret
}
}
```
## 相关题目
* 350.两个数组的交集 II

View File

@ -315,6 +315,28 @@ func canConstruct(_ ransomNote: String, _ magazine: String) -> Bool {
}
```
Rust:
```rust
impl Solution {
pub fn can_construct(ransom_note: String, magazine: String) -> bool {
let baseChar = 'a';
let mut record = vec![0; 26];
for byte in magazine.bytes() {
record[byte as usize - baseChar as usize] += 1;
}
for byte in ransom_note.bytes() {
record[byte as usize - baseChar as usize] -= 1;
if record[byte as usize - baseChar as usize] < 0 {
return false;
}
}
return true;
}
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -227,6 +227,45 @@ class Solution:
```
Go
```
func canPartition(nums []int) bool {
/**
动态五部曲:
1.确定dp数组和下标含义
2.确定递推公式
3.dp数组初始化
4.dp遍历顺序
5.打印
**/
//确定和
var sum int
for _,v:=range nums{
sum+=v
}
if sum%2!=0{ //如果和为奇数,则不可能分成两个相等的数组
return false
}
sum/=2
//确定dp数组和下标含义
var dp [][]bool //dp[i][j] 表示: 前i个石头是否总和不大于J
//初始化数组
dp=make([][]bool,len(nums)+1)
for i,_:=range dp{
dp[i]=make([]bool,sum+1)
dp[i][0]=true
}
for i:=1;i<=len(nums);i++{
for j:=1;j<=sum;j++{//j是固定总量
if j>=nums[i-1]{//如果容量够用则可放入背包
dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i-1]]
}else{//如果容量不够用则不拿,维持前一个状态
dp[i][j]=dp[i-1][j]
}
}
}
return dp[len(nums)][sum]
}
```
javaScript:

View File

@ -274,6 +274,7 @@ func min(a,b int)int{
}
```
Javascript:
- 按右边界排序
```Javascript
var eraseOverlapIntervals = function(intervals) {
intervals.sort((a, b) => {
@ -285,7 +286,7 @@ var eraseOverlapIntervals = function(intervals) {
for(let i = 1; i < intervals.length; i++) {
let interval = intervals[i]
if(interval[0] >= right) {
if(interval[0] >= end) {
end = interval[1]
count += 1
}
@ -294,6 +295,24 @@ var eraseOverlapIntervals = function(intervals) {
return intervals.length - count
};
```
- 按左边界排序
```js
var eraseOverlapIntervals = function(intervals) {
// 按照左边界升序排列
intervals.sort((a, b) => a[0] - b[0])
let count = 1
let end = intervals[intervals.length - 1][0]
// 倒序遍历,对单个区间来说,左边界越大越好,因为给前面区间的空间越大
for(let i = intervals.length - 2; i >= 0; i--) {
if(intervals[i][1] <= end) {
count++
end = intervals[i][0]
}
}
// count 记录的是最大非重复区间的个数
return intervals.length - count
}
```
-----------------------

View File

@ -282,6 +282,31 @@ func fourSumCount(_ nums1: [Int], _ nums2: [Int], _ nums3: [Int], _ nums4: [Int]
}
```
Rust
```rust
use std::collections::HashMap;
impl Solution {
pub fn four_sum_count(nums1: Vec<i32>, nums2: Vec<i32>, nums3: Vec<i32>, nums4: Vec<i32>) -> i32 {
let mut umap:HashMap<i32, i32> = HashMap::new();
for num1 in &nums1 {
for num2 in &nums2 {
*umap.entry(num1 + num2).or_insert(0) += 1;
}
}
let mut count = 0;
for num3 in &nums3 {
for num4 in &nums4 {
let target:i32 = - (num3 + num4);
count += umap.get(&target).unwrap_or(&0);
}
}
count
}
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -84,6 +84,37 @@ public:
Java
```java
// 解法一
class Solution {
// 上下左右 4 个方向
int[] dirx = {-1, 1, 0, 0};
int[] diry = {0, 0, -1, 1};
public int islandPerimeter(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int res = 0; // 岛屿周长
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1) {
for (int k = 0; k < 4; k++) {
int x = i + dirx[k];
int y = j + diry[k];
// 当前位置是陆地并且从当前位置4个方向扩展的“新位置”是“水域”或“新位置“越界则会为周长贡献一条边
if (x < 0 || x >= m || y < 0 || y >= n || grid[x][y] == 0) {
res++;
continue;
}
}
}
}
}
return res;
}
}
```
Python
Go

View File

@ -248,6 +248,53 @@ func max(a,b int) int {
return b
}
```
> 传统背包,三维数组法
```golang
func findMaxForm(strs []string, m int, n int) int {
//dp的第一个index代表项目的多少第二个代表的是背包的容量
//所以本处项目的多少是lenstrs容量为m和n
dp:=make([][][]int,len(strs)+1)
for i:=0;i<=len(strs);i++{
//初始化背包容量
strDp:=make([][]int,m+1)
for j:=0;j<m+1;j++{
tmp:=make([]int,n+1)
strDp[j]=tmp
}
dp[i]=strDp
}
for k,value:=range strs{
//统计每个字符串0和1的个数
var zero,one int
for _,v:=range value{
if v=='0'{
zero++
}else{
one++
}
}
k+=1
//计算dp
for i:=0;i<=m;i++{
for j:=0;j<=n;j++{
//如果装不下
dp[k][i][j]=dp[k-1][i][j]
//如果装的下
if i>=zero&&j>=one{
dp[k][i][j]=getMax(dp[k-1][i][j],dp[k-1][i-zero][j-one]+1)
}
}
}
}
return dp[len(strs)][m][n]
}
func getMax(a,b int)int{
if a>b{
return a
}
return b
}
```
Javascript
```javascript

View File

@ -314,6 +314,47 @@ func findTargetSumWays(nums []int, target int) int {
return dp[bag]
}
```
> 更新版上一个跑不通了因为会存在bag 小于0的情况
```go
func findTargetSumWays(nums []int, target int) int {
//先转化为数学问题
//a-b=target
//a+b=sum
//a=(target+sum)/2
//求出sum
var sum int
for _,value:=range nums{
sum+=value
}
//如果sum<target或者 sum+target不是偶数因为a是int 或者两者之和小于0了
if sum<target||(sum+target)%2==1||(sum+target)<0{
return 0
}
//开始dp初始化
dp:=make([][]int,len(nums)+1)
for i:=0;i<=len(nums);i++{
tmp:=make([]int,(target+sum)/2+1)//背包容量
dp[i]=tmp
}
dp[0][0]=1//当背包容量为0且物品为0时填满背包就1种方法
for i:=0;i<len(nums)+1;i++{
if i==0{
continue
}
for j:=0;j<(target+sum)/2+1;j++{
if nums[i-1]<=j{//如果背包装的下
dp[i][j]=dp[i-1][j]+dp[i-1][j-nums[i-1]]
}else{
dp[i][j]=dp[i-1][j]
}
}
}
return dp[len(nums)][(target+sum)/2]
}
```
Javascript
```javascript
@ -321,7 +362,7 @@ const findTargetSumWays = (nums, target) => {
const sum = nums.reduce((a, b) => a+b);
if(target > sum) {
if(Math.abs(target) > sum) {
return 0;
}

View File

@ -238,4 +238,37 @@ class Solution:
return result
```
Go
```go
func nextGreaterElement(nums1 []int, nums2 []int) []int {
res := make([]int, len(nums1))
for i:= range res {
res[i] = -1
}
mp := map[int]int{}
for i,v := range nums1 {
mp[v] = i
}
// 单调栈
stack := []int{}
stack = append(stack,0)
for i:=1; i<len(nums2); i++ {
for len(stack) >0 && nums2[i] > nums2[stack[len(stack)-1]] {
top := stack[len(stack)-1]
if _, ok := mp[nums2[top]]; ok { // 看map里是否存在这个元素
index := mp[nums2[top]]; // 根据map找到nums2[top] 在 nums1中的下表
res[index] = nums2[i]
}
stack = stack[:len(stack)-1] // 出栈
}
stack = append(stack, i)
}
return res
}
```
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -9,7 +9,7 @@
# 513.找树左下角的值
[力扣题目链接]([https://leetcode-cn.com/problems/find-bottom-left-tree-value/](https://leetcode-cn.com/problems/find-bottom-left-tree-value/v))
[力扣题目链接](https://leetcode-cn.com/problems/find-bottom-left-tree-value/)
给定一个二叉树,在树的最后一行找到最左边的值。

View File

@ -258,16 +258,30 @@ class Solution {
## Python
```python
//递归法
class Solution:
"""最大二叉树 递归法"""
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
if not nums: return None //终止条件
root = TreeNode(max(nums)) //新建节点
p = nums.index(root.val) //找到最大值位置
if p > 0: //保证有左子树
root.left = self.constructMaximumBinaryTree(nums[:p]) //递归
if p < len(nums): //保证有右子树
root.right = self.constructMaximumBinaryTree(nums[p+1:]) //递归
return self.traversal(nums, 0, len(nums))
def traversal(self, nums: List[int], begin: int, end: int) -> TreeNode:
# 列表长度为0时返回空节点
if begin == end:
return None
# 找到最大的值和其对应的下标
max_index = begin
for i in range(begin, end):
if nums[i] > nums[max_index]:
max_index = i
# 构建当前节点
root = TreeNode(nums[max_index])
# 递归构建左右子树
root.left = self.traversal(nums, begin, max_index)
root.right = self.traversal(nums, max_index + 1, end)
return root
```

View File

@ -10,6 +10,9 @@
# 684.冗余连接
[力扣题目链接](https://leetcode-cn.com/problems/redundant-connection/)
树可以看成是一个连通且 无环 的 无向 图。
给定往一棵 n 个节点 (节点值 1n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edges edges[i] = [ai, bi] 表示图中在 ai 和 bi 之间存在一条边。
@ -140,16 +143,161 @@ public:
## Java
```java
class Solution {
private int n; // 节点数量3 到 1000
private int[] father;
public Solution() {
n = 1005;
father = new int[n];
// 并查集初始化
for (int i = 0; i < n; ++i) {
father[i] = i;
}
}
// 并查集里寻根的过程
private int find(int u) {
if(u == father[u]) {
return u;
}
father[u] = find(father[u]);
return father[u];
}
// 将v->u 这条边加入并查集
private void join(int u, int v) {
u = find(u);
v = find(v);
if (u == v) return ;
father[v] = u;
}
// 判断 u 和 v是否找到同一个根本题用不上
private Boolean same(int u, int v) {
u = find(u);
v = find(v);
return u == v;
}
public int[] findRedundantConnection(int[][] edges) {
for (int i = 0; i < edges.length; i++) {
if (same(edges[i][0], edges[i][1])) {
return edges[i];
} else {
join(edges[i][0], edges[i][1]);
}
}
return null;
}
}
```
## Python
```python
class Solution:
def __init__(self):
"""
初始化
"""
self.n = 1005
self.father = [i for i in range(self.n)]
def find(self, u):
"""
并查集里寻根的过程
"""
if u == self.father[u]:
return u
self.father[u] = self.find(self.father[u])
return self.father[u]
def join(self, u, v):
"""
将v->u 这条边加入并查集
"""
u = self.find(u)
v = self.find(v)
if u == v : return
self.father[v] = u
pass
def same(self, u, v ):
"""
判断 u 和 v是否找到同一个根本题用不上
"""
u = self.find(u)
v = self.find(v)
return u == v
def findRedundantConnection(self, edges: List[List[int]]) -> List[int]:
for i in range(len(edges)):
if self.same(edges[i][0], edges[i][1]) :
return edges[i]
else :
self.join(edges[i][0], edges[i][1])
return []
```
## Go
```go
// 全局变量
var (
n = 1005 // 节点数量3 到 1000
father = make([]int, 1005)
)
// 并查集初始化
func initialize() {
for i := 0; i < n; i++ {
father[i] = i
}
}
// 并查集里寻根的过程
func find(u int) int {
if u == father[u] {
return u
}
father[u] = find(father[u])
return father[u]
}
// 将v->u 这条边加入并查集
func join(u, v int) {
u = find(u)
v = find(v)
if u == v {
return
}
father[v] = u
}
// 判断 u 和 v是否找到同一个根本题用不上
func same(u, v int) bool {
u = find(u)
v = find(v)
return u == v
}
func findRedundantConnection(edges [][]int) []int {
initialize()
for i := 0; i < len(edges); i++ {
if same(edges[i][0], edges[i][1]) {
return edges[i]
} else {
join(edges[i][0], edges[i][1])
}
}
return []int{}
}
```
## JavaScript

View File

@ -39,7 +39,7 @@
**这说明题目中的图原本是是一棵树,只不过在不增加节点的情况下多加了一条边!**
还有**若有多个答案,返回最后出现在给定二维数组的答案。**这说明在两边都可以删除的情况下,要删顺序靠后的!
还有**若有多个答案,返回最后出现在给定二维数组的答案。**这说明在两边都可以删除的情况下,要删顺序靠后的!
那么有如下三种情况前两种情况是出现入度为2的点如图
@ -58,7 +58,7 @@
首先先计算节点的入度,代码如下:
```CPP
```cpp
int inDegree[N] = {0}; // 记录节点入度
n = edges.size(); // 边的数量
for (int i = 0; i < n; i++) {
@ -70,7 +70,7 @@ for (int i = 0; i < n; i++) {
代码如下:
```CPP
```cpp
vector<int> vec; // 记录入度为2的边如果有的话就两条边
// 找入度为2的节点所对应的边注意要倒叙因为优先返回最后出现在二维数组中的答案
for (int i = n - 1; i >= 0; i--) {
@ -112,7 +112,7 @@ vector<int> getRemoveEdge(const vector<vector<int>>& edges)
本题C++代码如下:(详细注释了)
```CPP
```cpp
class Solution {
private:
static const int N = 1010; // 如题二维数组大小的在3到1000范围内
@ -174,7 +174,7 @@ public:
inDegree[edges[i][1]]++; // 统计入度
}
vector<int> vec; // 记录入度为2的边如果有的话就两条边
// 找入度为2的节点所对应的边注意要倒,因为优先返回最后出现在二维数组中的答案
// 找入度为2的节点所对应的边注意要倒,因为优先返回最后出现在二维数组中的答案
for (int i = n - 1; i >= 0; i--) {
if (inDegree[edges[i][1]] == 2) {
vec.push_back(i);
@ -203,16 +203,313 @@ public:
## Java
```java
class Solution {
private static final int N = 1010; // 如题二维数组大小的在3到1000范围内
private int[] father;
public Solution() {
father = new int[N];
// 并查集初始化
for (int i = 0; i < N; ++i) {
father[i] = i;
}
}
// 并查集里寻根的过程
private int find(int u) {
if(u == father[u]) {
return u;
}
father[u] = find(father[u]);
return father[u];
}
// 将v->u 这条边加入并查集
private void join(int u, int v) {
u = find(u);
v = find(v);
if (u == v) return ;
father[v] = u;
}
// 判断 u 和 v是否找到同一个根本题用不上
private Boolean same(int u, int v) {
u = find(u);
v = find(v);
return u == v;
}
/**
* 初始化并查集
*/
private void initFather() {
// 并查集初始化
for (int i = 0; i < N; ++i) {
father[i] = i;
}
}
/**
* 在有向图里找到删除的那条边,使其变成树
* @param edges
* @return 要删除的边
*/
private int[] getRemoveEdge(int[][] edges) {
initFather();
for(int i = 0; i < edges.length; i++) {
if(same(edges[i][0], edges[i][1])) { // 构成有向环了,就是要删除的边
return edges[i];
}
join(edges[i][0], edges[i][1]);
}
return null;
}
/**
* 删一条边之后判断是不是树
* @param edges
* @param deleteEdge 要删除的边
* @return true: 是树, false 不是树
*/
private Boolean isTreeAfterRemoveEdge(int[][] edges, int deleteEdge)
{
initFather();
for(int i = 0; i < edges.length; i++)
{
if(i == deleteEdge) continue;
if(same(edges[i][0], edges[i][1])) { // 构成有向环了,一定不是树
return false;
}
join(edges[i][0], edges[i][1]);
}
return true;
}
public int[] findRedundantDirectedConnection(int[][] edges) {
int[] inDegree = new int[N];
for(int i = 0; i < edges.length; i++)
{
// 入度
inDegree[ edges[i][1] ] += 1;
}
// 找入度为2的节点所对应的边注意要倒序因为优先返回最后出现在二维数组中的答案
ArrayList<Integer> twoDegree = new ArrayList<Integer>();
for(int i = edges.length - 1; i >= 0; i--)
{
if(inDegree[edges[i][1]] == 2) {
twoDegree.add(i);
}
}
// 处理图中情况1 和 情况2
// 如果有入度为2的节点那么一定是两条边里删一个看删哪个可以构成树
if(!twoDegree.isEmpty())
{
if(isTreeAfterRemoveEdge(edges, twoDegree.get(0))) {
return edges[ twoDegree.get(0)];
}
return edges[ twoDegree.get(1)];
}
// 明确没有入度为2的情况那么一定有有向环找到构成环的边返回就可以了
return getRemoveEdge(edges);
}
}
```
## Python
```python
class Solution:
def __init__(self):
self.n = 1010
self.father = [i for i in range(self.n)]
def find(self, u: int):
"""
并查集里寻根的过程
"""
if u == self.father[u]:
return u
self.father[u] = self.find(self.father[u])
return self.father[u]
def join(self, u: int, v: int):
"""
将v->u 这条边加入并查集
"""
u = self.find(u)
v = self.find(v)
if u == v : return
self.father[v] = u
pass
def same(self, u: int, v: int ):
"""
判断 u 和 v是否找到同一个根本题用不上
"""
u = self.find(u)
v = self.find(v)
return u == v
def init_father(self):
self.father = [i for i in range(self.n)]
pass
def getRemoveEdge(self, edges: List[List[int]]) -> List[int]:
"""
在有向图里找到删除的那条边,使其变成树
"""
self.init_father()
for i in range(len(edges)):
if self.same(edges[i][0], edges[i][1]): # 构成有向环了,就是要删除的边
return edges[i]
self.join(edges[i][0], edges[i][1]);
return []
def isTreeAfterRemoveEdge(self, edges: List[List[int]], deleteEdge: int) -> bool:
"""
删一条边之后判断是不是树
"""
self.init_father()
for i in range(len(edges)):
if i == deleteEdge: continue
if self.same(edges[i][0], edges[i][1]): # 构成有向环了,一定不是树
return False
self.join(edges[i][0], edges[i][1]);
return True
def findRedundantDirectedConnection(self, edges: List[List[int]]) -> List[int]:
inDegree = [0 for i in range(self.n)]
for i in range(len(edges)):
inDegree[ edges[i][1] ] += 1
# 找入度为2的节点所对应的边注意要倒序因为优先返回最后出现在二维数组中的答案
towDegree = []
for i in range(len(edges))[::-1]:
if inDegree[edges[i][1]] == 2 :
towDegree.append(i)
# 处理图中情况1 和 情况2
# 如果有入度为2的节点那么一定是两条边里删一个看删哪个可以构成树
if len(towDegree) > 0:
if(self.isTreeAfterRemoveEdge(edges, towDegree[0])) :
return edges[towDegree[0]]
return edges[towDegree[1]]
# 明确没有入度为2的情况那么一定有有向环找到构成环的边返回就可以了
return self.getRemoveEdge(edges)
```
## Go
```go
// 全局变量
var (
n = 1010// 节点数量3 到 1000
father = make([]int, n)
)
// 并查集初始化
func initialize() {
for i := 0; i < n; i++ {
father[i] = i
}
}
// 并查集里寻根的过程
func find(u int) int {
if u == father[u] {
return u
}
father[u] = find(father[u])
return father[u]
}
// 将v->u 这条边加入并查集
func join(u, v int) {
u = find(u)
v = find(v)
if u == v {
return
}
father[v] = u
}
// 判断 u 和 v是否找到同一个根本题用不上
func same(u, v int) bool {
u = find(u)
v = find(v)
return u == v
}
// getRemoveEdge 在有向图里找到删除的那条边,使其变成树
func getRemoveEdge(edges [][]int) []int {
initialize()
for i := 0; i < len(edges); i++ { // 遍历所有的边
if same(edges[i][0], edges[i][1]) { // 构成有向环了,就是要删除的边
return edges[i]
}
join(edges[i][0], edges[i][1])
}
return []int{}
}
// isTreeAfterRemoveEdge 删一条边之后判断是不是树
func isTreeAfterRemoveEdge(edges [][]int, deleteEdge int) bool {
initialize()
for i := 0; i < len(edges); i++ {
if i == deleteEdge {
continue
}
if same(edges[i][0], edges[i][1]) { // 构成有向环了,一定不是树
return false
}
join(edges[i][0], edges[i][1])
}
return true
}
func findRedundantDirectedConnection(edges [][]int) []int {
inDegree := make([]int, len(father))
for i := 0; i < len(edges); i++ {
// 统计入度
inDegree[edges[i][1]] += 1
}
// 记录入度为2的边如果有的话就两条边
// 找入度为2的节点所对应的边注意要倒序因为优先返回最后出现在二维数组中的答案
twoDegree := make([]int, 0)
for i := len(edges) - 1; i >= 0; i-- {
if inDegree[edges[i][1]] == 2 {
twoDegree = append(twoDegree, i)
}
}
// 处理图中情况1 和 情况2
// 如果有入度为2的节点那么一定是两条边里删一个看删哪个可以构成树
if len(twoDegree) > 0 {
if isTreeAfterRemoveEdge(edges, twoDegree[0]) {
return edges[twoDegree[0]]
}
return edges[twoDegree[1]]
}
// 处理图中情况3
// 明确没有入度为2的情况那么一定有有向环找到构成环的边返回就可以了
return getRemoveEdge(edges)
}
```
## JavaScript

View File

@ -9,6 +9,8 @@
# 724.寻找数组的中心下标
[力扣题目链接](https://leetcode-cn.com/problems/find-pivot-index/)
给你一个整数数组 nums ,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
@ -87,15 +89,15 @@ class Solution {
}
```
## Python
## Python3
```python3
```python
class Solution:
def pivotIndex(self, nums: List[int]) -> int:
numSum = sum(nums) #数组总和
leftSum = 0
for i in range(len(nums)):
if numSum - leftSum -nums[i] == leftSum: #左右和相等
if numSum - leftSum -nums[i] == leftSum: #左右和相等
return i
leftSum += nums[i]
return -1
@ -104,6 +106,24 @@ class Solution:
## Go
```go
func pivotIndex(nums []int) int {
sum := 0
for _, v := range nums {
sum += v;
}
leftSum := 0 // 中心索引左半和
rightSum := 0 // 中心索引右半和
for i := 0; i < len(nums); i++ {
leftSum += nums[i]
rightSum = sum - leftSum + nums[i]
if leftSum == rightSum{
return i
}
}
return -1
}
```
## JavaScript

View File

@ -347,24 +347,57 @@ 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 minCameraCover(self, root: TreeNode) -> int:
# Greedy Algo:
# 从下往上安装摄像头跳过leaves这样安装数量最少局部最优 -> 全局最优
# 先给leaves的父节点安装然后每隔两层节点安装一个摄像头直到Head
# 0: 该节点未覆盖
# 1: 该节点有摄像头
# 2: 该节点有覆盖
result = 0
def traversal(cur):
# 从下往上遍历:后序(左右中)
def traversal(curr: TreeNode) -> int:
nonlocal result
if not cur:
return 2
left = traversal(cur.left)
right = traversal(cur.right)
if left == 2 and right == 2:
if not curr: return 2
left = traversal(curr.left)
right = traversal(curr.right)
# Case 1:
# 左右节点都有覆盖
if left == 2 and right == 2:
return 0
elif left == 0 or right == 0:
# Case 2:
# left == 0 && right == 0 左右节点无覆盖
# left == 1 && right == 0 左节点有摄像头,右节点无覆盖
# left == 0 && right == 1 左节点有无覆盖,右节点摄像头
# left == 0 && right == 2 左节点无覆盖,右节点覆盖
# left == 2 && right == 0 左节点覆盖,右节点无覆盖
elif left == 0 or right == 0:
result += 1
return 1
# Case 3:
# left == 1 && right == 2 左节点有摄像头,右节点有覆盖
# left == 2 && right == 1 左节点有覆盖,右节点有摄像头
# left == 1 && right == 1 左右节点都有摄像头
elif left == 1 or right == 1:
return 2
else: return -1
if traversal(root) == 0: result += 1
# 其他情况前段代码均已覆盖
if traversal(root) == 0:
result += 1
return result
```
Go

View File

@ -219,7 +219,28 @@ func max(a, b int) int {
}
```
JavaScript版本
```javascript
/**
* @param {number[]} stones
* @return {number}
*/
var lastStoneWeightII = function (stones) {
let sum = stones.reduce((s, n) => s + n);
let dpLen = Math.floor(sum / 2);
let dp = new Array(dpLen + 1).fill(0);
for (let i = 0; i < stones.length; ++i) {
for (let j = dpLen; j >= stones[i]; --j) {
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
return sum - dp[dpLen] - dp[dpLen];
};
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -167,7 +167,33 @@ else {
Java
```java
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][] dp = new int[m+1][n+1];
for(int i = 1; i <= m; i++){
dp[i][0] = i;
}
for(int i = 1; i <= n; i++){
dp[0][i] = i;
}
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
int left = dp[i][j-1]+1;
int mid = dp[i-1][j-1];
int right = dp[i-1][j]+1;
if(word1.charAt(i-1) != word2.charAt(j-1)){
mid ++;
}
dp[i][j] = Math.min(left,Math.min(mid,right));
}
}
return dp[m][n];
}
}
```
Python

View File

@ -34,7 +34,7 @@ leetcode上没有纯01背包的问题都是01背包应用方面的题目
## 01 背包
有N件物品和一个最多能重量为W 的背包。第i件物品的重量是weight[i]得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。
有N件物品和一个最多能重量为W 的背包。第i件物品的重量是weight[i]得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。
![动态规划-背包问题](https://img-blog.csdnimg.cn/20210117175428387.jpg)