& nums) {
memset(dp, 0, sizeof dp);
dp[0][0] = dp[0][1] = 1;
-
- for (int i = 1; i < nums.size(); ++i)
- {
+ for (int i = 1; i < nums.size(); ++i) {
dp[i][0] = dp[i][1] = 1;
-
- for (int j = 0; j < i; ++j)
- {
+ for (int j = 0; j < i; ++j) {
if (nums[j] > nums[i]) dp[i][1] = max(dp[i][1], dp[j][0] + 1);
}
-
- for (int j = 0; j < i; ++j)
- {
+ for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) dp[i][0] = max(dp[i][0], dp[j][1] + 1);
}
}
@@ -153,17 +238,6 @@ public:
空间复杂度:O(n)
-## 总结
-
-**贪心的题目说简单有的时候就是常识,说难就难在都不知道该怎么用贪心**。
-
-本题大家如果要去模拟删除元素达到最长摆动子序列的过程,那指定绕里面去了,一时半会拔不出来。
-
-而这道题目有什么技巧说一下子能想到贪心么?
-
-其实也没有,类似的题目做过了就会想到。
-
-此时大家就应该了解了:保持区间波动,只需要把单调区间上的元素移除就可以了。
diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md
index 6c8c28ec..eec4183d 100644
--- a/problems/0494.目标和.md
+++ b/problems/0494.目标和.md
@@ -270,6 +270,8 @@ class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for (int i = 0; i < nums.length; i++) sum += nums[i];
+ //如果target过大 sum将无法满足
+ if ( target < 0 && sum < -target) return 0;
if ((target + sum) % 2 != 0) return 0;
int size = (target + sum) / 2;
if(size < 0) size = -size;
diff --git a/problems/0518.零钱兑换II.md b/problems/0518.零钱兑换II.md
index 2fc807cd..f6a8044c 100644
--- a/problems/0518.零钱兑换II.md
+++ b/problems/0518.零钱兑换II.md
@@ -95,6 +95,8 @@ dp[j] 就是所有的dp[j - coins[i]](考虑coins[i]的情况)相加。
下标非0的dp[j]初始化为0,这样累计加dp[j - coins[i]]的时候才不会影响真正的dp[j]
+dp[0]=1还说明了一种情况:如果正好选了coins[i]后,也就是j-coins[i] == 0的情况表示这个硬币刚好能选,此时dp[0]为1表示只选coins[i]存在这样的一种选法。
+
4. 确定遍历顺序
本题中我们是外层for循环遍历物品(钱币),内层for遍历背包(金钱总额),还是外层for遍历背包(金钱总额),内层for循环遍历物品(钱币)呢?
@@ -316,3 +318,4 @@ object Solution {
+
diff --git a/problems/0827.最大人工岛.md b/problems/0827.最大人工岛.md
index fb0c797e..05d82f7e 100644
--- a/problems/0827.最大人工岛.md
+++ b/problems/0827.最大人工岛.md
@@ -3,8 +3,11 @@
参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+
# 827. 最大人工岛
+[力扣链接](https://leetcode.cn/problems/making-a-large-island/)
+
给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。
返回执行此操作后,grid 中最大的岛屿面积是多少?
@@ -30,7 +33,9 @@
本题的一个暴力想法,应该是遍历地图尝试 将每一个 0 改成1,然后去搜索地图中的最大的岛屿面积。
-计算地图的最大面积:遍历地图 + 深搜岛屿,时间复杂度为 n * n
+计算地图的最大面积:遍历地图 + 深搜岛屿,时间复杂度为 n * n。
+
+(其实使用深搜还是广搜都是可以的,其目的就是遍历岛屿做一个标记,相当于染色,那么使用哪个遍历方式都行,以下我用深搜来讲解)
每改变一个0的方格,都需要重新计算一个地图的最大面积,所以 整体时间复杂度为:n^4。
@@ -41,7 +46,7 @@
其实每次深搜遍历计算最大岛屿面积,我们都做了很多重复的工作。
-只要把深搜就可以并每个岛屿的面积记录下来就好。
+只要用一次深搜把每个岛屿的面积记录下来就好。
第一步:一次遍历地图,得出各个岛屿的面积,并做编号记录。可以使用map记录,key为岛屿编号,value为岛屿面积
第二步:在遍历地图,遍历0的方格(因为要将0变成1),并统计该1(由0变成的1)周边岛屿面积,将其相邻面积相加在一起,遍历所有 0 之后,就可以得出 选一个0变成1 之后的最大面积。
@@ -74,7 +79,7 @@ void dfs(vector>& grid, vector>& visited, int x, int y,
int largestIsland(vector>& grid) {
int n = grid.size(), m = grid[0].size();
- vector> visited = vector>(n, vector(m, false));
+ vector> visited = vector>(n, vector(m, false)); // 标记访问过的点
unordered_map gridNum;
int mark = 2; // 记录每个岛屿的编号
bool isAllGrid = true; // 标记是否整个地图都是陆地
@@ -92,9 +97,10 @@ int largestIsland(vector>& grid) {
}
```
+
这个过程时间复杂度 n * n 。可能有录友想:分明是两个for循环下面套这一个dfs,时间复杂度怎么回事 n * n呢?
-其实大家可以自己看代码的时候,**n * n这个方格地图中,每个节点我们就遍历一次,并不会重复遍历**。
+其实大家可以仔细看一下代码,**n * n这个方格地图中,每个节点我们就遍历一次,并不会重复遍历**。
第二步过程如图所示:
@@ -106,6 +112,47 @@ int largestIsland(vector>& grid) {
所以整个解法的时间复杂度,为 n * n + n * n 也就是 n^2。
+当然这里还有一个优化的点,就是 可以不用 visited数组,因为有mark来标记,所以遍历过的grid[i][j]是不等于1的。
+
+代码如下:
+
+```CPP
+ int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
+ void dfs(vector>& grid, int x, int y, int mark) {
+ if (grid[x][y] != 1 || grid[x][y] == 0) return; // 终止条件:访问过的节点 或者 遇到海水
+ grid[x][y] = mark; // 给陆地标记新标签
+ count++;
+ for (int i = 0; i < 4; i++) {
+ int nextx = x + dir[i][0];
+ int nexty = y + dir[i][1];
+ if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 越界了,直接跳过
+ dfs(grid, nextx, nexty, mark);
+ }
+ }
+
+public:
+ int largestIsland(vector>& grid) {
+ int n = grid.size(), m = grid[0].size();
+ unordered_map gridNum;
+ int mark = 2; // 记录每个岛屿的编号
+ bool isAllGrid = true; // 标记是否整个地图都是陆地
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < m; j++) {
+ if (grid[i][j] == 0) isAllGrid = false;
+ if (grid[i][j] == 1) {
+ count = 0;
+ dfs(grid, i, j, mark); // 将与其链接的陆地都标记上 true
+ gridNum[mark] = count; // 记录每一个岛屿的面积
+ mark++; // 记录下一个岛屿编号
+ }
+ }
+ }
+ }
+}
+```
+
+不过为了让各个变量各司其事,代码清晰一些,完整代码还是使用visited数组来标记。
+
最后,整体代码如下:
```CPP
@@ -129,7 +176,7 @@ private:
public:
int largestIsland(vector>& grid) {
int n = grid.size(), m = grid[0].size();
- vector> visited = vector>(n, vector(m, false));
+ vector> visited = vector>(n, vector(m, false)); // 标记访问过的点
unordered_map gridNum;
int mark = 2; // 记录每个岛屿的编号
bool isAllGrid = true; // 标记是否整个地图都是陆地
@@ -171,6 +218,7 @@ public:
}
};
```
+
diff --git a/problems/1020.飞地的数量.md b/problems/1020.飞地的数量.md
index 8b54d7f1..b7cba7a6 100644
--- a/problems/1020.飞地的数量.md
+++ b/problems/1020.飞地的数量.md
@@ -6,6 +6,8 @@
# 1020. 飞地的数量
+[力扣链接](https://leetcode.cn/problems/number-of-enclaves/description/)
+
给你一个大小为 m x n 的二进制矩阵 grid ,其中 0 表示一个海洋单元格、1 表示一个陆地单元格。
一次 移动 是指从一个陆地单元格走到另一个相邻(上、下、左、右)的陆地单元格或跨过 grid 的边界。
@@ -26,7 +28,7 @@
## 思路
-本题使用dfs,bfs,并查集都是可以的。 本题和 417. 太平洋大西洋水流问题 很像。
+本题使用dfs,bfs,并查集都是可以的。
本题要求找到不靠边的陆地面积,那么我们只要从周边找到陆地然后 通过 dfs或者bfs 将周边靠陆地且相邻的陆地都变成海洋,然后再去重新遍历地图的时候,统计此时还剩下的陆地就可以了。