Leetcode(剑指offer专项训练)——DP专项(7)
矩阵中的距离
题目:
给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。
两个相邻元素间的距离为 1 。
链接
TLS思路题解
暴力DFS的结果是超时😢,就是找每个位置的距离它最近的零点的位置
class Solution {
public:
vector<vector<int>>ans;
vector<vector<bool>>vis;
int m,n;
int inf=99999;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
void dfs(int rx,int ry,int x,int y,vector<vector<int>>& mat){
vis[x][y]=true;
if(ans[x][y]!=inf){
ans[rx][ry]=min(ans[x][y]+abs(rx-x)+abs(ry-y),ans[rx][ry]);
return;
}
if(mat[x][y]==0){
ans[rx][ry]=min(abs(rx-x)+abs(ry-y),ans[rx][ry]);
return;
}else{
int nx,ny;
for(int i=0;i<4;i++){
nx=x+dx[i];
ny=y+dy[i];
if(nx>=0&&nx<m&&ny>=0&&ny<n&&!vis[nx][ny]){
// cout<<nx<<" : "<<ny<<"|"<<m<<":"<<n<<endl;
dfs(rx,ry,nx,ny,mat);
}
}
}
}
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
//输出每一个元素最近的0的距离
m=mat.size();
n=mat[0].size();
ans=vector<vector<int>>(m,vector<int>(n,inf));
vis=vector<vector<bool>>(m,vector<bool>(n,false));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
dfs(i,j,i,j,mat);
vis.clear();
vis=vector<vector<bool>>(m,vector<bool>(n,false));
}
}
return ans;
}
};
题解
BFS
思路:将地图中所有0
看作第一层,第二层为紧邻0
的那一份1
,第三层为紧邻第一层1
的1
……以此类推
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
//输出每一个元素最近的0的距离
int m=mat.size();
int n=mat[0].size();
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int nx,ny;
int inf=99999;
vector<vector<int>>ans(m,vector<int>(n));
vector<vector<bool>>vis(m,vector<bool>(n,false));
queue<pair<int,int>>q;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(mat[i][j]==0){
vis[i][j]=true;
ans[i][j]=0;
q.emplace(i,j);
}
}
}
while(!q.empty()){
auto[x,y]=q.front();
q.pop();
for(int i=0;i<4;i++){
nx=x+dx[i];
ny=y+dy[i];
if(nx>=0&&nx<m&&ny>=0&&ny<n&&!vis[nx][ny]){
q.emplace(nx,ny);
ans[nx][ny]=ans[x][y]+1;
// printf("%d %d, %d %d,[%d,%d]\n",nx,ny,i,j,m,n);
vis[nx][ny]=true;
}
}
}
return ans;
}
};
DP
思路:其实每次移动都有四种方位选择(1,1)(-1,1)(1,-1)(-1,-1),我们可以得到其中某个方向的状态转移方程:
然后需要对四个方向依次做一遍这种操作即可
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
//输出每一个元素最近的0的距离
int m=mat.size();
int n=mat[0].size();
int inf=99999;
vector<vector<int>>ans(m,vector<int>(n,inf));
//初始化
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(mat[i][j]==0){
ans[i][j]=0;
}
}
}
//右-下
for(int i=m-1;i>=0;i--){
for(int j=n-1;j>=0;j--){
if(j+1<n){
ans[i][j]=min(ans[i][j+1]+1,ans[i][j]);
}
if(i+1<m){
ans[i][j]=min(ans[i+1][j]+1,ans[i][j]);
}
}
}
//右 上:可以不需要
for(int i=m-1;i>=0;i--){
for(int j=0;j<n;j++){
if(j-1>=0){
ans[i][j]=min(ans[i][j-1]+1,ans[i][j]);
}
if(i+1<m){
ans[i][j]=min(ans[i+1][j]+1,ans[i][j]);
}
}
}
//左-上
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(j-1>=0){
ans[i][j]=min(ans[i][j-1]+1,ans[i][j]);
}
if(i-1>=0){
ans[i][j]=min(ans[i-1][j]+1,ans[i][j]);
}
}
}
//左-下:可以不需要
for(int i=0;i<m;i++){
for(int j=n-1;j>=0;j--){
if(j+1<n){
ans[i][j]=min(ans[i][j+1]+1,ans[i][j]);
}
if(i-1>=0){
ans[i][j]=min(ans[i-1][j]+1,ans[i][j]);
}
}
}
return ans;
}
};
按照官方说法,常数优化后,其实只需要保留左上和右下两种遍历即可
单词演变
题目:
在字典(单词列表) wordList 中,从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:
序列中第一个单词是 beginWord 。
序列中最后一个单词是 endWord 。
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典 wordList 中的单词。
给定两个长度相同但内容不同的单词 beginWord 和 endWord 和一个字典 wordList ,找到从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0。
链接
BFS
思路:求最短的演变单词数量,本质上是在求最短路径,容易想到dfs,把原始wordList转成链表,可以有效的缩短BFS的遍历时间(具体体现为一个word路过后,可以从链表中摘除);
构造Node结构体,存储每一次遍历到的位置(str)以及单词个数(path),每次继续探索只能改变一个字母,所以需要遍历没有走过的单词链表,找到和当前str字符相差为1的下一个单词位置
完整代码如下:
class Solution {
public:
int m,n;
bool near_diff(string &a,string &b){
int cnt=0;
for(int i=0;i<n;i++){
if(a[i]!=b[i]){
cnt++;
if(cnt>1){
return false;
}
}
}
if(cnt==1){
return true;
}
return false;
}
struct Node{
string str="";
Node*next=NULL;
int path=1;
};
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
m=wordList.size();
n=beginWord.size();
//构建链表
Node*head,*p,*pre;
head=new Node;
pre=head;
bool flag=false;
for(int i=0;i<m;i++){
p=new Node;
p->str=wordList[i];
pre->next=p;
pre=p;
if(wordList[i]==endWord){
flag=true;
}
}
if(!flag){
return 0;
}
//计算最短路径
queue<Node*>q;
Node*temp=new Node;
temp->str=beginWord;
q.emplace(temp);
while(!q.empty()){
temp=q.front();
q.pop();
//找新的方向
p=head->next;
pre=head;
while(p){
if(near_diff(temp->str, p->str)){
p->path=temp->path+1;
//cout<<"temp="<<temp->str<<" p="<<p->str<<" len="<<p->path<<endl;
if(p->str==endWord){
return p->path;
}
//hot-dot-dog-cog
q.emplace(p);
//删除节点
pre->next=p->next;
// Node *t=p;
p=p->next;
// delete(t);
continue;
}
pre=p;
p=p->next;
}
}
//["hot","dot","dog","lot","log","cog"]
//hot->lot->log->log
return 0;
}
};
本文来自博客园,作者:理想国的糕,转载请注明原文链接:https://www.cnblogs.com/SaltyCheese/p/17289933.html嗷~