知识点
拓扑排序 或者 动态规划
结果
拓扑排序
动态规划
代码
拓扑排序
//就是返回拓扑排序的层数吧
//拓扑信息是大于关系吧
class Solution {
public:
int longestIncreasingPath(vector<vector<int>>& matrix) {
//得到矩阵的长宽,总大小
int h = matrix.size();
if(h == 0){
return 0;
}
int w = matrix[0].size();
int max = h * w;
//邻接表,表示before < after,并且after在before的四个方向,数组下标从0开始
vector<vector<int>> adj(max+10);
//入度数组
vector<int> inDegree(max+10,0);
//将矩阵数组展开进行存储
vector<int> arr;
for(int i=0;i<h;i++){
for(int j=0;j<w;j++){
arr.push_back(matrix[i][j]);
}
}
//上下左右
int up;
int down;
int left;
int right;
for(int i=0;i<max;i++){
up = i-w;
down = i+w;
left = i-1;
right = i+1;
if(up>=0 && arr[up] > arr[i]){
adj[i].push_back(up);
inDegree[up]++;
}
if(down<max && arr[down] > arr[i]){
adj[i].push_back(down);
inDegree[down]++;
}
if(i%w !=0 && arr[left] > arr[i] ){
adj[i].push_back(left);
inDegree[left]++;
}
if(right%w != 0 && arr[right] > arr[i]){
adj[i].push_back(right);
inDegree[right]++;
}
}
//下面进行拓扑排序
int length = topoSort(adj,inDegree,max);
return length;
}
int topoSort(vector<vector<int>>& adj,vector<int>& inDegree,int max){
queue<int> q;
for(int i=0;i<inDegree.size();i++){
if(inDegree[i] == 0){
q.push(i);
}
}
int length = 0;
while(!q.empty()){
length++;
int s = q.size();
for(int i=0;i<s;i++){
int before = q.front();
q.pop();
for(int i=0;i<adj[before].size();i++){
int after = adj[before][i];
inDegree[after]--;
if(inDegree[after] == 0){
q.push(after);
}
}
}
}
return length;
}
};
动态规划
//使用DFS+DP来解题
//DP的作用是记忆化搜索的作用
//这里面没有指定数组的大小,所以我们的dp数组使用vector
#include <bits/stdc++.h>
using namespace std;
class Solution {
private:
//长度
int h;
//宽度
int w;
//动态dp数组
vector<vector<int>> dp;
//相对方位数组,储存四个方向,上下左右
int dr[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
public:
int longestIncreasingPath(vector<vector<int>>& matrix) {
//长度
h = matrix.size();
//特判matrix为空
if(h == 0){
return 0;
}
//宽度
w = matrix[0].size();
//为dp数组赋值大小和值,所有的值最原始都是0
dp.assign(h,vector<int>(w,0));
//最大长度
int maxLen = 0;
for(int i=0;i<h;i++){
for(int j=0;j<w;j++){
maxLen = max(maxLen,DFS(matrix,i,j));
}
}
return maxLen;
}
int DFS(vector<vector<int>>& matrix,int x,int y){
//记忆化搜索价值所在:不为零,说明一定是已经进行了DFS的,那它的值绝对确定了
if(dp[x][y] != 0){
return dp[x][y];
}
//否则进行计算
//前后左右四个方位的dp,取max那种
//dp初始化1
dp[x][y] = 1;
for(int k=0;k<4;k++){
//n表示neighbor!
int nx = x+dr[k][0];
int ny = y+dr[k][1];
//不超出边界,而且邻居还小于自己,进行DFS继续搜索
if(nx>=0 && nx < h && ny >=0 && ny < w && matrix[nx][ny] <matrix[x][y]){
//进行记忆化存储!!!
dp[x][y] = max(dp[x][y],1+DFS(matrix,nx,ny));
}
}
return dp[x][y];
}
};
反思
拓扑排序
- 要不是看见这道题目出现在拓扑排序里面,我可能根本想不到要用拓扑排序😓,我之前一直以为拓扑排序都是判断DAG,这次长见识了,我应该会首选动态规划的;
- LeetCode居然不能debug,肉眼debug太难了!!!
- 注意拓扑排序循环体与平常的写法不一样,这里是一次性把同一层的都遍历一个遍,这样是为了方便记录层数
layer
,我之前没想到,结果用了一个结构体存储层数,太笨了; - 要理解拓扑排序的那张分层的结构图,感觉那个就是拓扑排序的思想,要用拓扑排序,就看可不可以套用那张分层结构图,套得上就可以用拓扑排序!
- 要特判
matrx
为空的情况,难顶。
动态规划
- 对于DFS+动态规划(即记忆化搜索,真的好常见的考法),DFS的递归边界一般就是
dp[i][j]
已经得到,直接return dp[i][j]
。DFS(i,j)
的含义更像是返回dp[i][j],如果没有则给dfs计算dp[i][j],反正我要返回dp[i][j]
,在这其中用到了动态规划的思想,将大问题分解成规模小一点的问题。 - 学会了
vector.assign()
,开心~~~ - 对于前后左右,我们一般还是用相对位置加减,这样代码更加清晰!