知识储备了解:
1.图的遍历
从图的某个顶点出发访问遍图中所有定点,且每个顶点仅被访问一次
深度优先搜索 DFS
访问指定的起始顶点;
若当前访问的顶点的邻接顶点有未被访问的,则任选一个访问之;反之,退回到最近访问过的顶点;直到与起始顶点想通的全部顶点都访问完毕
若此时图中尚有顶点未被访问,则再选其中一个顶点作为起始顶点并访问之,转2;反之,遍历结束
遍历图的过程实质上是对每个顶点查找其邻接点的过程,所耗费的时间取决于所采用的存储结构。
广度优先搜索 BFS
从图的某一结点出发,首先依次访问该结点的所有邻接顶点 Vi1, Vi2, …, Vin 再按这些顶点被访问的先后次序依次访问与它们相邻接的所有未被访问的顶点,重复此过程,直至所有顶点均被访问为止。
依靠队列和一维数组来实现
DP(动态规划算法)的基本思想:
将待求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,让以后再次遇到时直接引用答案,不必重新求解。动态规划算法将问题的解决方案视为一系列决策的结果,与贪婪算法不同的是,在贪婪算法中,每采用一次贪婪准则,便做出一个不可撤回的决策;而在动态规划算法中,还要考察每个最优决策序列中是否包含一个最优决策子序列,即问题是否具有最优子结构性质。
题目1:
给定一个整数矩阵,找出最长递增路径的长度。
对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外(即不允许环绕)。
示例 1:
输入: nums =
[
[9,9,4],
[6,6,8],
[2,1,1]
]
输出: 4
解释: 最长递增路径为 [1, 2, 6, 9]。
示例 2:
输入: nums =
[
[3,4,5],
[3,2,6],
[2,2,1]
]
输出: 4
解释: 最长递增路径是 [3, 4, 5, 6]。注意不允许在对角线方向上移动。
class Solution {
public:
int dfs(vector<vector<int>> &matrix, vector<vector<int>> &memo, int x, int y){
if(memo[x][y]!=-1) return memo[x][y];
int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};
int ans = 1;
for(int i=0; i<4; i++){
for(int j=0; j<4; j++){
int tx = x+dx[i], ty = y+dy[i];
if(tx<memo.size() && tx>=0 && ty>=0 && ty<memo[0].size() && matrix[x][y]>matrix[tx][ty]){
ans = max(ans, 1+dfs(matrix, memo, tx, ty));
}
}
}
return memo[x][y]=ans;
}
int longestIncreasingPath(vector<vector<int>>& matrix) {
// 方法一:给定初始节点,dfs搜索
int m = matrix.size(); if(m==0) return 0;
int n = matrix[0].size(); if(n==0) return 0;
vector<vector<int>> memo(m, vector<int>(n, -1));
int ans = 1;
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
ans = max(ans, dfs(matrix, memo, i, j));
}
}
return ans;
}
};
dp[i][j][k]表示matrix[i][j]结尾且数组长度不超过k时的最长递增路径长度
利用滚动数组为dp[i][j][2]
int longestIncreasingPath(vector<vector<int>>& matrix) {
// 方法二:动态规划 复杂度O(m*n*max_path_len), 与Floyd算法类似
// ** 复杂度可以进一步改进为原来的一半,ans为最后dp的最大值
int m = matrix.size(); if(m==0) return 0;
int n = matrix[0].size(); if(n==0) return 0;
vector<vector<vector<int>>> dp(m, vector<vector<int>>(n, vector<int>{1,1}));
int cur = 0;
int ans = 1;
while(1){
bool is_change = false;
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
// 给定matrix[i][j], 选择其前面最近邻的节点使得dp[i][j]最大
int old = dp[i][j][cur];
if(i-1>=0 && matrix[i][j]>matrix[i-1][j] && 1+dp[i-1][j][cur]>dp[i][j][1-cur]) dp[i][j][1-cur] = 1+dp[i-1][j][cur];
if(i+1<m && matrix[i][j]>matrix[i+1][j] && 1+dp[i+1][j][cur]>dp[i][j][1-cur]) dp[i][j][1-cur] = 1+dp[i+1][j][cur];
if(j-1>=0 && matrix[i][j]>matrix[i][j-1] && 1+dp[i][j-1][cur]>dp[i][j][1-cur]) dp[i][j][1-cur] = 1+dp[i][j-1][cur];
if(j+1<n && matrix[i][j]>matrix[i][j+1] && 1+dp[i][j+1][cur]>dp[i][j][1-cur]) dp[i][j][1-cur] = 1+dp[i][j+1][cur];
if(old!=dp[i][j][1-cur]) is_change = true;
}
}
if(is_change){
ans++;
cur = 1-cur;
}else{
return ans;
}
}
return ans;
}