这个题目,用搜索做是很正常的想法 ,于是我就这样交代码了;
由于题给测试数据不大,200ms还是过了。
时间复杂度: O ( n 4 ) O(n^4) O(n4)
const int dx[] = {
-1,0,1,0};
const int dy[] = {
0,1,0,-1};
class Solution {
public:
int n,t;
bool vis[51][51];
int swimInWater(vector<vector<int>>& grid) {
n=grid.size();
for(t=0;t<n*n;t++){
if(grid[0][0]<=t){
memset(vis,0,sizeof(vis)); //每次dfs,都要刷新一下
if(dfs(0,0,grid)){
return t;
}
}
}
return n*n-1;
}
bool dfs(int x,int y,vector<vector<int>>& grid){
// cout<
if(x==n-1 && y==n-1){
return true;
}
vis[x][y] = 1;
for(int k=0;k<4;k++){
int nx = x + dx[k];
int ny = y + dy[k];
if(nx>=0&&ny>=0&&nx<n&&ny<n && grid[nx][ny]<=t && !vis[nx][ny]){
if(dfs(nx,ny,grid)){
return true;
}
// vis[nx,ny] = 0;这个地方不需要也不能还原现场,否则会冗余搜索。
}
}
return false;
}
};
然后是怎么想到二分的呢?dfs()
是一个关于时间t的函数,返回true 或false,相当于是在[1,n*n-1]这个区间猜一个数,刚好处于一个临界点(超过这个临界点都是true,不到临界点都是false)。
这不就是一个二分应用里面的一个猜大小数字的小游戏吗?
d f s ( t ) = { 0 1 , t ∈ [ 1 , n 2 − 1 ] dfs(t)=\begin{cases} 0\\ 1 \end{cases} ,t\in [1,n^2-1] dfs(t)={ 01,t∈[1,n2−1]
时间复杂度 O ( l o g ( n 2 ) ∗ n 2 ) = O ( l o g ( n ) n 2 ) O(log(n^2)*n^2)=O(log(n)n^2) O(log(n2)∗n2)=O(log(n)n2)
const int dx[] = {
-1,0,1,0};
const int dy[] = {
0,1,0,-1};
class Solution {
public:
int n;
bool vis[51][51];
int swimInWater(vector<vector<int>>& grid) {
n=grid.size();
int l = grid[0][0], r = n*n-1,mid;
while(l<r){
int mid = (l+r)/2;
memset(vis,0,sizeof(vis));
if(dfs(0,0,mid,grid)){
r = mid;
}else{
l = mid +1;
}
}
return l;
}
bool dfs(int x,int y,int t,vector<vector<int>>& grid){
if(x==n-1 && y==n-1){
return true;
}
vis[x][y] = 1;
for(int k=0;k<4;k++){
int nx = x + dx[k];
int ny = y + dy[k];
if(nx>=0&&ny>=0&&nx<n&&ny<n && grid[nx][ny]<=t && !vis[nx][ny]){
if(dfs(nx,ny,t,grid)){
return true;
}
// vis[nx][ny] = 0;
}
}
return false;
}
};
这里,我也用并查集做了一下,原理是一样的。
const int dx[] = {
-1,0,1,0};
const int dy[] = {
0,1,0,-1};
struct UFS{
int f[50*50+10];
UFS(){
for(int i=0;i<50*50+10;i++){
f[i]=i;
}
}
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
void merge(int x,int y){
f[find(x)] = find(y);
}
};
class Solution {
public:
int swimInWater(vector<vector<int>>& grid) {
int n = grid.size(),t;
int l= grid[0][0],r=n*n-1;
while(l<r){
int mid = (l+r)/2;
UFS ufs;
for(int x=0;x<n;x++){
for(int y=0;y<n;y++){
if(grid[x][y]>mid){
continue;
}
for(int k=0;k<4;k++){
int nx = x + dx[k];
int ny = y + dy[k];
if(nx>=0 && ny>=0 && nx<n && ny<n && grid[nx][ny]<=mid){
ufs.merge(x*50+y,nx*50+ny);
}
}
}
}
if(ufs.find(0)==ufs.find((n-1)*50+(n-1))){
r = mid;
}else{
l = mid+1;
}
}
return l;
}
};
这题还有用优先队列做的,暂时先搁着吧。
以后再补。