mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-07 07:35:35 +08:00
Merge branch 'master' into master
This commit is contained in:
@ -39,7 +39,7 @@
|
||||
|
||||
分为如下几步:
|
||||
|
||||
* 首先这里我推荐大家使用虚拟头结点,这样方面处理删除实际头结点的逻辑,如果虚拟头结点不清楚,可以看这篇: [链表:听说用虚拟头节点会方便很多?](https://programmercarl.com/0203.移除链表元素.html)
|
||||
* 首先这里我推荐大家使用虚拟头结点,这样方便处理删除实际头结点的逻辑,如果虚拟头结点不清楚,可以看这篇: [链表:听说用虚拟头节点会方便很多?](https://programmercarl.com/0203.移除链表元素.html)
|
||||
|
||||
* 定义fast指针和slow指针,初始值为虚拟头结点,如图:
|
||||
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
|
||||
**双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。**
|
||||
|
||||
后序都会一一介绍到,本题代码如下:
|
||||
后续都会一一介绍到,本题代码如下:
|
||||
|
||||
```CPP
|
||||
// 时间复杂度:O(n)
|
||||
|
@ -564,6 +564,57 @@ int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
|
||||
return ans;
|
||||
}
|
||||
```
|
||||
Scala:
|
||||
```scala
|
||||
object Solution {
|
||||
def generateMatrix(n: Int): Array[Array[Int]] = {
|
||||
var res = Array.ofDim[Int](n, n) // 定义一个n*n的二维矩阵
|
||||
var num = 1 // 标志当前到了哪个数字
|
||||
var i = 0 // 横坐标
|
||||
var j = 0 // 竖坐标
|
||||
|
||||
while (num <= n * n) {
|
||||
// 向右:当j不越界,并且下一个要填的数字是空白时
|
||||
while (j < n && res(i)(j) == 0) {
|
||||
res(i)(j) = num // 当前坐标等于num
|
||||
num += 1 // num++
|
||||
j += 1 // 竖坐标+1
|
||||
}
|
||||
i += 1 // 下移一行
|
||||
j -= 1 // 左移一列
|
||||
|
||||
// 剩下的都同上
|
||||
|
||||
// 向下
|
||||
while (i < n && res(i)(j) == 0) {
|
||||
res(i)(j) = num
|
||||
num += 1
|
||||
i += 1
|
||||
}
|
||||
i -= 1
|
||||
j -= 1
|
||||
|
||||
// 向左
|
||||
while (j >= 0 && res(i)(j) == 0) {
|
||||
res(i)(j) = num
|
||||
num += 1
|
||||
j -= 1
|
||||
}
|
||||
i -= 1
|
||||
j += 1
|
||||
|
||||
// 向上
|
||||
while (i >= 0 && res(i)(j) == 0) {
|
||||
res(i)(j) = num
|
||||
num += 1
|
||||
i -= 1
|
||||
}
|
||||
i += 1
|
||||
j += 1
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -199,6 +199,28 @@ var climbStairs = function(n) {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function climbStairs(n: number): number {
|
||||
const m: number = 2; // 本题m为2
|
||||
const dp: number[] = new Array(n + 1).fill(0);
|
||||
dp[0] = 1;
|
||||
// 遍历背包
|
||||
for (let i = 1; i <= n; i++) {
|
||||
// 遍历物品
|
||||
for (let j = 1; j <= m; j++) {
|
||||
if (j <= i) {
|
||||
dp[i] += dp[i - j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[n];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -82,6 +82,26 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
```CPP
|
||||
# 递归法
|
||||
class Solution {
|
||||
public:
|
||||
void order(TreeNode* cur, vector<vector<int>>& result, int depth)
|
||||
{
|
||||
if (cur == nullptr) return;
|
||||
if (result.size() == depth) result.push_back(vector<int>());
|
||||
result[depth].push_back(cur->val);
|
||||
order(cur->left, result, depth + 1);
|
||||
order(cur->right, result, depth + 1);
|
||||
}
|
||||
vector<vector<int>> levelOrder(TreeNode* root) {
|
||||
vector<vector<int>> result;
|
||||
int depth = 0;
|
||||
order(root, result, depth);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
python3代码:
|
||||
|
||||
|
@ -377,22 +377,22 @@ class solution {
|
||||
|
||||
```java
|
||||
class solution {
|
||||
public list<list<integer>> pathsum(treenode root, int targetsum) {
|
||||
list<list<integer>> res = new arraylist<>();
|
||||
public List<List<Integer>> pathsum(TreeNode root, int targetsum) {
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
if (root == null) return res; // 非空判断
|
||||
|
||||
list<integer> path = new linkedlist<>();
|
||||
|
||||
List<Integer> path = new LinkedList<>();
|
||||
preorderdfs(root, targetsum, res, path);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void preorderdfs(treenode root, int targetsum, list<list<integer>> res, list<integer> path) {
|
||||
public void preorderdfs(TreeNode root, int targetsum, List<List<Integer>> res, List<Integer> path) {
|
||||
path.add(root.val);
|
||||
// 遇到了叶子节点
|
||||
if (root.left == null && root.right == null) {
|
||||
// 找到了和为 targetsum 的路径
|
||||
if (targetsum - root.val == 0) {
|
||||
res.add(new arraylist<>(path));
|
||||
res.add(new ArrayList<>(path));
|
||||
}
|
||||
return; // 如果和不为 targetsum,返回
|
||||
}
|
||||
@ -1006,6 +1006,126 @@ func traversal(_ cur: TreeNode?, count: Int) {
|
||||
}
|
||||
```
|
||||
|
||||
## C
|
||||
> 0112.路径总和
|
||||
递归法:
|
||||
```c
|
||||
bool hasPathSum(struct TreeNode* root, int targetSum){
|
||||
// 递归结束条件:若当前节点不存在,返回false
|
||||
if(!root)
|
||||
return false;
|
||||
// 若当前节点为叶子节点,且targetSum-root的值为0。(当前路径上的节点值的和满足条件)返回true
|
||||
if(!root->right && !root->left && targetSum == root->val)
|
||||
return true;
|
||||
|
||||
// 查看左子树和右子树的所有节点是否满足条件
|
||||
return hasPathSum(root->right, targetSum - root->val) || hasPathSum(root->left, targetSum - root->val);
|
||||
}
|
||||
```
|
||||
|
||||
迭代法:
|
||||
```c
|
||||
// 存储一个节点以及当前的和
|
||||
struct Pair {
|
||||
struct TreeNode* node;
|
||||
int sum;
|
||||
};
|
||||
|
||||
bool hasPathSum(struct TreeNode* root, int targetSum){
|
||||
struct Pair stack[1000];
|
||||
int stackTop = 0;
|
||||
|
||||
// 若root存在,则将节点和值封装成一个pair入栈
|
||||
if(root) {
|
||||
struct Pair newPair = {root, root->val};
|
||||
stack[stackTop++] = newPair;
|
||||
}
|
||||
|
||||
// 当栈不为空时
|
||||
while(stackTop) {
|
||||
// 出栈栈顶元素
|
||||
struct Pair topPair = stack[--stackTop];
|
||||
// 若栈顶元素为叶子节点,且和为targetSum时,返回true
|
||||
if(!topPair.node->left && !topPair.node->right && topPair.sum == targetSum)
|
||||
return true;
|
||||
|
||||
// 若当前栈顶节点有左右孩子,计算和并入栈
|
||||
if(topPair.node->left) {
|
||||
struct Pair newPair = {topPair.node->left, topPair.sum + topPair.node->left->val};
|
||||
stack[stackTop++] = newPair;
|
||||
}
|
||||
if(topPair.node->right) {
|
||||
struct Pair newPair = {topPair.node->right, topPair.sum + topPair.node->right->val};
|
||||
stack[stackTop++] = newPair;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
```
|
||||
> 0113.路径总和 II
|
||||
```c
|
||||
int** ret;
|
||||
int* path;
|
||||
int* colSize;
|
||||
int retTop;
|
||||
int pathTop;
|
||||
|
||||
void traversal(const struct TreeNode* const node, int count) {
|
||||
// 若当前节点为叶子节点
|
||||
if(!node->right && !node->left) {
|
||||
// 若当前path上的节点值总和等于targetSum。
|
||||
if(count == 0) {
|
||||
// 复制当前path
|
||||
int *curPath = (int*)malloc(sizeof(int) * pathTop);
|
||||
memcpy(curPath, path, sizeof(int) * pathTop);
|
||||
// 记录当前path的长度为pathTop
|
||||
colSize[retTop] = pathTop;
|
||||
// 将当前path加入到ret数组中
|
||||
ret[retTop++] = curPath;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 若节点有左/右孩子
|
||||
if(node->left) {
|
||||
// 将左孩子的值加入path中
|
||||
path[pathTop++] = node->left->val;
|
||||
traversal(node->left, count - node->left->val);
|
||||
// 回溯
|
||||
pathTop--;
|
||||
}
|
||||
if(node->right) {
|
||||
// 将右孩子的值加入path中
|
||||
path[pathTop++] = node->right->val;
|
||||
traversal(node->right, count - node->right->val);
|
||||
// 回溯
|
||||
--pathTop;
|
||||
}
|
||||
}
|
||||
|
||||
int** pathSum(struct TreeNode* root, int targetSum, int* returnSize, int** returnColumnSizes){
|
||||
// 初始化数组
|
||||
ret = (int**)malloc(sizeof(int*) * 1000);
|
||||
path = (int*)malloc(sizeof(int*) * 1000);
|
||||
colSize = (int*)malloc(sizeof(int) * 1000);
|
||||
retTop = pathTop = 0;
|
||||
*returnSize = 0;
|
||||
|
||||
// 若根节点不存在,返回空的ret
|
||||
if(!root)
|
||||
return ret;
|
||||
// 将根节点加入到path中
|
||||
path[pathTop++] = root->val;
|
||||
traversal(root, targetSum - root->val);
|
||||
|
||||
// 设置返回ret数组大小,以及其中每个一维数组元素的长度
|
||||
*returnSize = retTop;
|
||||
*returnColumnSizes = colSize;
|
||||
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -345,6 +345,48 @@ const wordBreak = (s, wordDict) => {
|
||||
}
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
> 动态规划
|
||||
|
||||
```typescript
|
||||
function wordBreak(s: string, wordDict: string[]): boolean {
|
||||
const dp: boolean[] = new Array(s.length + 1).fill(false);
|
||||
dp[0] = true;
|
||||
for (let i = 1; i <= s.length; i++) {
|
||||
for (let j = 0; j < i; j++) {
|
||||
const tempStr: string = s.slice(j, i);
|
||||
if (wordDict.includes(tempStr) && dp[j] === true) {
|
||||
dp[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[s.length];
|
||||
};
|
||||
```
|
||||
|
||||
> 记忆化回溯
|
||||
|
||||
```typescript
|
||||
function wordBreak(s: string, wordDict: string[]): boolean {
|
||||
// 只需要记忆结果为false的情况
|
||||
const memory: boolean[] = [];
|
||||
return backTracking(s, wordDict, 0, memory);
|
||||
function backTracking(s: string, wordDict: string[], startIndex: number, memory: boolean[]): boolean {
|
||||
if (startIndex >= s.length) return true;
|
||||
if (memory[startIndex] === false) return false;
|
||||
for (let i = startIndex + 1, length = s.length; i <= length; i++) {
|
||||
const str: string = s.slice(startIndex, i);
|
||||
if (wordDict.includes(str) && backTracking(s, wordDict, i, memory))
|
||||
return true;
|
||||
}
|
||||
memory[startIndex] = false;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -189,6 +189,29 @@ const rob = nums => {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function rob(nums: number[]): number {
|
||||
/**
|
||||
dp[i]: 前i个房屋能偷到的最大金额
|
||||
dp[0]: nums[0];
|
||||
dp[1]: max(nums[0], nums[1]);
|
||||
...
|
||||
dp[i]: max(dp[i-1], dp[i-2]+nums[i]);
|
||||
*/
|
||||
const length: number = nums.length;
|
||||
if (length === 1) return nums[0];
|
||||
const dp: number[] = [];
|
||||
dp[0] = nums[0];
|
||||
dp[1] = Math.max(nums[0], nums[1]);
|
||||
for (let i = 2; i < length; i++) {
|
||||
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
|
||||
}
|
||||
return dp[length - 1];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -478,6 +478,36 @@ impl Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Scala:
|
||||
```scala
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* class ListNode(_x: Int = 0, _next: ListNode = null) {
|
||||
* var next: ListNode = _next
|
||||
* var x: Int = _x
|
||||
* }
|
||||
*/
|
||||
object Solution {
|
||||
def removeElements(head: ListNode, `val`: Int): ListNode = {
|
||||
if (head == null) return head
|
||||
var dummy = new ListNode(-1, head) // 定义虚拟头节点
|
||||
var cur = head // cur 表示当前节点
|
||||
var pre = dummy // pre 表示cur前一个节点
|
||||
while (cur != null) {
|
||||
if (cur.x == `val`) {
|
||||
// 相等,就删除那么cur的前一个节点pre执行cur的下一个
|
||||
pre.next = cur.next
|
||||
} else {
|
||||
// 不相等,pre就等于当前cur节点
|
||||
pre = cur
|
||||
}
|
||||
// 向下迭代
|
||||
cur = cur.next
|
||||
}
|
||||
// 最终返回dummy的下一个,就是链表的头
|
||||
dummy.next
|
||||
}
|
||||
}
|
||||
```
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -400,6 +400,54 @@ class Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
Scala:
|
||||
|
||||
滑动窗口:
|
||||
```scala
|
||||
object Solution {
|
||||
def minSubArrayLen(target: Int, nums: Array[Int]): Int = {
|
||||
var result = Int.MaxValue // 返回结果,默认最大值
|
||||
var left = 0 // 慢指针,当sum>=target,向右移动
|
||||
var sum = 0 // 窗口值的总和
|
||||
for (right <- 0 until nums.length) {
|
||||
sum += nums(right)
|
||||
while (sum >= target) {
|
||||
result = math.min(result, right - left + 1) // 产生新结果
|
||||
sum -= nums(left) // 左指针移动,窗口总和减去左指针的值
|
||||
left += 1 // 左指针向右移动
|
||||
}
|
||||
}
|
||||
// 相当于三元运算符,return关键字可以省略
|
||||
if (result == Int.MaxValue) 0 else result
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
暴力解法:
|
||||
```scala
|
||||
object Solution {
|
||||
def minSubArrayLen(target: Int, nums: Array[Int]): Int = {
|
||||
import scala.util.control.Breaks
|
||||
var res = Int.MaxValue
|
||||
var subLength = 0
|
||||
for (i <- 0 until nums.length) {
|
||||
var sum = 0
|
||||
Breaks.breakable(
|
||||
for (j <- i until nums.length) {
|
||||
sum += nums(j)
|
||||
if (sum >= target) {
|
||||
subLength = j - i + 1
|
||||
res = math.min(subLength, res)
|
||||
Breaks.break()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
// 相当于三元运算符
|
||||
if (res == Int.MaxValue) 0 else res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -165,7 +165,30 @@ const robRange = (nums, start, end) => {
|
||||
return dp[end]
|
||||
}
|
||||
```
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function rob(nums: number[]): number {
|
||||
const length: number = nums.length;
|
||||
if (length === 0) return 0;
|
||||
if (length === 1) return nums[0];
|
||||
return Math.max(robRange(nums, 0, length - 2),
|
||||
robRange(nums, 1, length - 1));
|
||||
};
|
||||
function robRange(nums: number[], start: number, end: number): number {
|
||||
if (start === end) return nums[start];
|
||||
const dp: number[] = [];
|
||||
dp[start] = nums[start];
|
||||
dp[start + 1] = Math.max(nums[start], nums[start + 1]);
|
||||
for (let i = start + 2; i <= end; i++) {
|
||||
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
|
||||
}
|
||||
return dp[end];
|
||||
}
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
```go
|
||||
// 打家劫舍Ⅱ 动态规划
|
||||
// 时间复杂度O(n) 空间复杂度O(n)
|
||||
|
@ -355,5 +355,24 @@ var numSquares2 = function(n) {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function numSquares(n: number): number {
|
||||
const goodsNum: number = Math.floor(Math.sqrt(n));
|
||||
const dp: number[] = new Array(n + 1).fill(Infinity);
|
||||
dp[0] = 0;
|
||||
for (let i = 1; i <= goodsNum; i++) {
|
||||
const tempVal: number = i * i;
|
||||
for (let j = tempVal; j <= n; j++) {
|
||||
dp[j] = Math.min(dp[j], dp[j - tempVal] + 1);
|
||||
}
|
||||
}
|
||||
return dp[n];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -340,7 +340,21 @@ const coinChange = (coins, amount) => {
|
||||
}
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function coinChange(coins: number[], amount: number): number {
|
||||
const dp: number[] = new Array(amount + 1).fill(Infinity);
|
||||
dp[0] = 0;
|
||||
for (let i = 0; i < coins.length; i++) {
|
||||
for (let j = coins[i]; j <= amount; j++) {
|
||||
if (dp[j - coins[i]] === Infinity) continue;
|
||||
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
|
||||
}
|
||||
}
|
||||
return dp[amount] === Infinity ? -1 : dp[amount];
|
||||
};
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -221,7 +221,27 @@ const combinationSum4 = (nums, target) => {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function combinationSum4(nums: number[], target: number): number {
|
||||
const dp: number[] = new Array(target + 1).fill(0);
|
||||
dp[0] = 1;
|
||||
// 遍历背包
|
||||
for (let i = 1; i <= target; i++) {
|
||||
// 遍历物品
|
||||
for (let j = 0, length = nums.length; j < length; j++) {
|
||||
if (i >= nums[j]) {
|
||||
dp[i] += dp[i - nums[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[target];
|
||||
};
|
||||
```
|
||||
|
||||
Rust
|
||||
|
||||
```Rust
|
||||
impl Solution {
|
||||
pub fn combination_sum4(nums: Vec<i32>, target: i32) -> i32 {
|
||||
|
@ -416,6 +416,108 @@ var canPartition = function(nums) {
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
C:
|
||||
二维dp:
|
||||
```c
|
||||
/**
|
||||
1. dp数组含义:dp[i][j]为背包重量为j时,从[0-i]元素和最大值
|
||||
2. 递推公式:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i])
|
||||
3. 初始化:dp[i][0]初始化为0。因为背包重量为0时,不可能放入元素。dp[0][j] = nums[0],当j >= nums[0] && j < target时
|
||||
4. 遍历顺序:先遍历物品,再遍历背包
|
||||
*/
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
int getSum(int* nums, int numsSize) {
|
||||
int sum = 0;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < numsSize; ++i) {
|
||||
sum += nums[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
bool canPartition(int* nums, int numsSize){
|
||||
// 求出元素总和
|
||||
int sum = getSum(nums, numsSize);
|
||||
// 若元素总和为奇数,则不可能得到两个和相等的子数组
|
||||
if(sum % 2)
|
||||
return false;
|
||||
|
||||
// 若子数组的和等于target,则nums可以被分割
|
||||
int target = sum / 2;
|
||||
// 初始化dp数组
|
||||
int dp[numsSize][target + 1];
|
||||
// dp[j][0]都应被设置为0。因为当背包重量为0时,不可放入元素
|
||||
memset(dp, 0, sizeof(int) * numsSize * (target + 1));
|
||||
|
||||
int i, j;
|
||||
// 当背包重量j大于nums[0]时,可以在dp[0][j]中放入元素nums[0]
|
||||
for(j = nums[0]; j <= target; ++j) {
|
||||
dp[0][j] = nums[0];
|
||||
}
|
||||
|
||||
for(i = 1; i < numsSize; ++i) {
|
||||
for(j = 1; j <= target; ++j) {
|
||||
// 若当前背包重量j小于nums[i],则其值等于只考虑0到i-1物品时的值
|
||||
if(j < nums[i])
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
// 否则,背包重量等于在背包中放入num[i]/不放入nums[i]的较大值
|
||||
else
|
||||
dp[i][j] = MAX(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
|
||||
}
|
||||
}
|
||||
// 判断背包重量为target,且考虑到所有物品时,放入的元素和是否等于target
|
||||
return dp[numsSize - 1][target] == target;
|
||||
}
|
||||
```
|
||||
滚动数组:
|
||||
```c
|
||||
/**
|
||||
1. dp数组含义:dp[j]为背包重量为j时,其中可放入元素的最大值
|
||||
2. 递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
|
||||
3. 初始化:均初始化为0即可
|
||||
4. 遍历顺序:先遍历物品,再后序遍历背包
|
||||
*/
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
int getSum(int* nums, int numsSize) {
|
||||
int sum = 0;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < numsSize; ++i) {
|
||||
sum += nums[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
bool canPartition(int* nums, int numsSize){
|
||||
// 求出元素总和
|
||||
int sum = getSum(nums, numsSize);
|
||||
// 若元素总和为奇数,则不可能得到两个和相等的子数组
|
||||
if(sum % 2)
|
||||
return false;
|
||||
// 背包容量
|
||||
int target = sum / 2;
|
||||
|
||||
// 初始化dp数组,元素均为0
|
||||
int dp[target + 1];
|
||||
memset(dp, 0, sizeof(int) * (target + 1));
|
||||
|
||||
int i, j;
|
||||
// 先遍历物品,后遍历背包
|
||||
for(i = 0; i < numsSize; ++i) {
|
||||
for(j = target; j >= nums[i]; --j) {
|
||||
dp[j] = MAX(dp[j], dp[j - nums[i]] + nums[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 查看背包容量为target时,元素总和是否等于target
|
||||
return dp[target] == target;
|
||||
}
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
> 一维数组,简洁
|
||||
|
@ -279,7 +279,7 @@ class Solution:
|
||||
root.right = self.insertIntoBST(root.right, val)
|
||||
|
||||
# 返回更新后的以当前root为根节点的新树
|
||||
return roo
|
||||
return root
|
||||
```
|
||||
|
||||
**递归法** - 无返回值
|
||||
|
@ -382,5 +382,42 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
Scala:
|
||||
|
||||
双指针:
|
||||
```scala
|
||||
object Solution {
|
||||
def sortedSquares(nums: Array[Int]): Array[Int] = {
|
||||
val res: Array[Int] = new Array[Int](nums.length)
|
||||
var top = nums.length - 1
|
||||
var i = 0
|
||||
var j = nums.length - 1
|
||||
while (i <= j) {
|
||||
if (nums(i) * nums(i) <= nums(j) * nums(j)) {
|
||||
// 当左侧平方小于等于右侧,res数组顶部放右侧的平方,并且top下移,j左移
|
||||
res(top) = nums(j) * nums(j)
|
||||
top -= 1
|
||||
j -= 1
|
||||
} else {
|
||||
// 当左侧平方大于右侧,res数组顶部放左侧的平方,并且top下移,i右移
|
||||
res(top) = nums(i) * nums(i)
|
||||
top -= 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
骚操作(暴力思路):
|
||||
```scala
|
||||
object Solution {
|
||||
def sortedSquares(nums: Array[Int]): Array[Int] = {
|
||||
nums.map(x=>{x*x}).sortWith(_ < _)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -209,6 +209,22 @@ var largestSumAfterKNegations = function(nums, k) {
|
||||
return a + b
|
||||
})
|
||||
};
|
||||
|
||||
// 版本二 (优化: 一次遍历)
|
||||
var largestSumAfterKNegations = function(nums, k) {
|
||||
nums.sort((a, b) => Math.abs(b) - Math.abs(a)); // 排序
|
||||
let sum = 0;
|
||||
for(let i = 0; i < nums.length; i++) {
|
||||
if(nums[i] < 0 && k-- > 0) { // 负数取反(k 数量足够时)
|
||||
nums[i] = -nums[i];
|
||||
}
|
||||
sum += nums[i]; // 求和
|
||||
}
|
||||
if(k % 2 > 0) { // k 有多余的(k若消耗完则应为 -1)
|
||||
sum -= 2 * nums[nums.length - 1]; // 减去两倍的最小值(因为之前加过一次)
|
||||
}
|
||||
return sum;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
@ -432,6 +432,54 @@ function test () {
|
||||
test();
|
||||
```
|
||||
|
||||
|
||||
### C
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define ARR_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
|
||||
#define BAG_WEIGHT 4
|
||||
|
||||
void backPack(int* weights, int weightSize, int* costs, int costSize, int bagWeight) {
|
||||
// 开辟dp数组
|
||||
int dp[weightSize][bagWeight + 1];
|
||||
memset(dp, 0, sizeof(int) * weightSize * (bagWeight + 1));
|
||||
|
||||
int i, j;
|
||||
// 当背包容量大于物品0的重量时,将物品0放入到背包中
|
||||
for(j = weights[0]; j <= bagWeight; ++j) {
|
||||
dp[0][j] = costs[0];
|
||||
}
|
||||
|
||||
// 先遍历物品,再遍历重量
|
||||
for(j = 1; j <= bagWeight; ++j) {
|
||||
for(i = 1; i < weightSize; ++i) {
|
||||
// 如果当前背包容量小于物品重量
|
||||
if(j < weights[i])
|
||||
// 背包物品的价值等于背包不放置当前物品时的价值
|
||||
dp[i][j] = dp[i-1][j];
|
||||
// 若背包当前重量可以放置物品
|
||||
else
|
||||
// 背包的价值等于放置该物品或不放置该物品的最大值
|
||||
dp[i][j] = MAX(dp[i - 1][j], dp[i - 1][j - weights[i]] + costs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
printf("%d\n", dp[weightSize - 1][bagWeight]);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int weights[] = {1, 3, 4};
|
||||
int costs[] = {15, 20, 30};
|
||||
backPack(weights, ARR_SIZE(weights), costs, ARR_SIZE(costs), BAG_WEIGHT);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### TypeScript
|
||||
|
||||
```typescript
|
||||
|
@ -137,6 +137,8 @@ dp[1] = dp[1 - weight[0]] + value[0] = 15
|
||||
|
||||
因为一维dp的写法,背包容量一定是要倒序遍历(原因上面已经讲了),如果遍历背包容量放在上一层,那么每个dp[j]就只会放入一个物品,即:背包里只放入了一个物品。
|
||||
|
||||
倒序遍历的原因是,本质上还是一个对二维数组的遍历,并且右下角的值依赖上一层左上角的值,因此需要保证左边的值仍然是上一层的,从右向左覆盖。
|
||||
|
||||
(这里如果读不懂,就在回想一下dp[j]的定义,或者就把两个for循环顺序颠倒一下试试!)
|
||||
|
||||
**所以一维dp数组的背包在遍历顺序上和二维其实是有很大差异的!**,这一点大家一定要注意。
|
||||
@ -315,6 +317,40 @@ function test () {
|
||||
test();
|
||||
```
|
||||
|
||||
### C
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define ARR_SIZE(arr) ((sizeof((arr))) / sizeof((arr)[0]))
|
||||
#define BAG_WEIGHT 4
|
||||
|
||||
void test_back_pack(int* weights, int weightSize, int* values, int valueSize, int bagWeight) {
|
||||
int dp[bagWeight + 1];
|
||||
memset(dp, 0, sizeof(int) * (bagWeight + 1));
|
||||
|
||||
int i, j;
|
||||
// 先遍历物品
|
||||
for(i = 0; i < weightSize; ++i) {
|
||||
// 后遍历重量。从后向前遍历
|
||||
for(j = bagWeight; j >= weights[i]; --j) {
|
||||
dp[j] = MAX(dp[j], dp[j - weights[i]] + values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 打印最优结果
|
||||
printf("%d\n", dp[bagWeight]);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int weights[] = {1, 3, 4};
|
||||
int values[] = {15, 20, 30};
|
||||
test_back_pack(weights, ARR_SIZE(weights), values, ARR_SIZE(values), BAG_WEIGHT);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
```typescript
|
||||
|
@ -334,6 +334,64 @@ func Test_multiplePack(t *testing.T) {
|
||||
PASS
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
> 版本一(改变数据源):
|
||||
|
||||
```typescript
|
||||
function testMultiPack() {
|
||||
const bagSize: number = 10;
|
||||
const weightArr: number[] = [1, 3, 4],
|
||||
valueArr: number[] = [15, 20, 30],
|
||||
amountArr: number[] = [2, 3, 2];
|
||||
for (let i = 0, length = amountArr.length; i < length; i++) {
|
||||
while (amountArr[i] > 1) {
|
||||
weightArr.push(weightArr[i]);
|
||||
valueArr.push(valueArr[i]);
|
||||
amountArr[i]--;
|
||||
}
|
||||
}
|
||||
const goodsNum: number = weightArr.length;
|
||||
const dp: number[] = new Array(bagSize + 1).fill(0);
|
||||
// 遍历物品
|
||||
for (let i = 0; i < goodsNum; i++) {
|
||||
// 遍历背包容量
|
||||
for (let j = bagSize; j >= weightArr[i]; j--) {
|
||||
dp[j] = Math.max(dp[j], dp[j - weightArr[i]] + valueArr[i]);
|
||||
}
|
||||
}
|
||||
console.log(dp);
|
||||
}
|
||||
testMultiPack();
|
||||
```
|
||||
|
||||
> 版本二(改变遍历方式):
|
||||
|
||||
```typescript
|
||||
function testMultiPack() {
|
||||
const bagSize: number = 10;
|
||||
const weightArr: number[] = [1, 3, 4],
|
||||
valueArr: number[] = [15, 20, 30],
|
||||
amountArr: number[] = [2, 3, 2];
|
||||
const goodsNum: number = weightArr.length;
|
||||
const dp: number[] = new Array(bagSize + 1).fill(0);
|
||||
// 遍历物品
|
||||
for (let i = 0; i < goodsNum; i++) {
|
||||
// 遍历物品个数
|
||||
for (let j = 0; j < amountArr[i]; j++) {
|
||||
// 遍历背包容量
|
||||
for (let k = bagSize; k >= weightArr[i]; k--) {
|
||||
dp[k] = Math.max(dp[k], dp[k - weightArr[i]] + valueArr[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(dp);
|
||||
}
|
||||
testMultiPack();
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -210,6 +210,13 @@ type ListNode struct {
|
||||
}
|
||||
```
|
||||
|
||||
Scala:
|
||||
```scala
|
||||
class ListNode(_x: Int = 0, _next: ListNode = null) {
|
||||
var next: ListNode = _next
|
||||
var x: Int = _x
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
|
Reference in New Issue
Block a user