算法
(BFS) $O(nm)$
这是一个典型的宽度优先搜索问题,我们从 (0, 0) 点开始,每次朝上下左右四个方向扩展新的节点即可。
扩展时需要注意新的节点需要满足如下条件:
- 之前没有遍历过,这个可以用个
bool
数组来判断; - 没有走出边界;
- 横纵坐标的各位数字之和小于 $k$;
最后答案就是所有遍历过的合法的节点个数。
时间复杂度
每个节点最多只会入队一次,所以时间复杂度不会超过方格中的节点个数。
最坏情况下会遍历方格中的所有点,所以时间复杂度就是 $O(nm)$。
C++ 代码
class Solution {
public:
int get_sum(pair<int, int> p) {
int s = 0;
while (p.first) {
s += p.first % 10;
p.first /= 10;
}
while (p.second) {
s += p.second % 10;
p.second /= 10;
}
return s;
}
int movingCount(int threshold, int rows, int cols)
{
if (!rows || !cols) return 0;
queue<pair<int,int>> q;
vector<vector<bool>> st(rows, vector<bool>(cols, false));
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int res = 0;
q.push({0, 0});
while (q.size()) {
auto t = q.front();
q.pop();
if (st[t.first][t.second] || get_sum(t) > threshold) continue;
res ++ ;
st[t.first][t.second] = true;
for (int i = 0; i < 4; i ++ ) {
int x = t.first + dx[i], y = t.second + dy[i];
if (x >= 0 && x < rows && y >= 0 && y < cols) q.push({x, y});
}
}
return res;
}
};
加了标注,最后class{}外少一个;
为什么不使用数组模拟呢,不是更快吗
边界的时候很难code的
直接按题意写
为什么这种两层for循环枚举所有的点,当数据大了之后就不对了呢?不是时间复杂度的问题
求大佬解答
### 算法1
##### (暴力枚举) $O(n^2)$
class Solution {
public:
int movingCount(int threshold, int rows, int cols)
{ int ans=0;
for(int i=0;i[HTML_REMOVED]=10&&j<10){
sum=sum+j+i%10+i/10;
if(sum<=threshold){
ans;
}
}
if(j>=10&&i<10){
sum=sum+i+j%10+j/10;
if(sum<=threshold){
ans;
}
}
if(i>=10&&j>=10){
sum=sum+j%10+j/10+i%10+i/10;
if(sum<=threshold){
ans++;
}
}
}
}
return ans;
}
};
因为机械人只能一步一步走 枚举所有点会把跳跃的点一起算进去 但实际上机械人是走不到那里去的
后面的时候就理解了,歇歇咯
谢谢咯
class Solution {
}
这个题dfs不会出错吗?
铁汁,这个接通的范围要怎么理解,没看明白orz
class Solution {
public:
int movingCount(int threshold, int rows, int cols)
{
if(rows==0||cols==0)
return 0;
int res=0;
int array[50][50];
DFS(threshold,rows,cols,0,0,array,&res);
return res;
}
void DFS(int k,int m,int n,int x,int y,int (array)[50],int res){
int a=x/10,b=x%10,c=y/10,d=y%10;
if(a+b+c+d>k)
return;
(*res);
array[x][y]=1;
int dx[4]={0,-1,0,1},dy[4]={-1,0,1,0};
for(int i=0;i<4;i){
int q=x+dx[i],w=y+dy[i];
if(q>=0&&q[HTML_REMOVED]=0&&w<n&&array[q][w]!=1)
DFS(k,m,n,q,w,array,res);
}
}
};
为什么这里先判断再入队结果不对?求解答
你可以试试看打印出进入队列的x, y坐标就知道问题了,因为一些点可以被多次入队。我调的C++代码如下:
只要加入队列的点,res都会++;
对于多个点的相同(合法正确)的邻点会多次入队列(入队前都是没有被访问的),导致重复计数
例如
0 1
2 3
1和2加入队列后,3会重复入队列多次
我做的时候就在思考这个问题,多谢解答
想问一下曼哈顿距离没法解决这个问题么?
请问为什么我这个代码在本地的VS跑结果是对的,在这里跑结果不对。
例子是$[3, 13, 14]$
你代码逻辑不对,比如点(11, 10),机器人一次只能走一步,没有有效路径可以到达这个点,但是你的代码会把它算上
而且你的ceil最后好像没有返回sum
如果是广度优先遍历,又是从原点 (0,0) 开始走,那么每次只用判断右边的格子和下边的格子。不需要上下左右都判定一遍。
老哥,要加一个 m和n都为0 就不用dfs了
你好,请问我这个哪里错了,报错看不懂。。。
if(i < 0 || i >= res.size() || j < 0 || j >= res[0].size()) return 0;
这段应该在dfs的第一句吧
class Solution {
public:
};
新手问一个问题:普遍做法是上下左右四个方向搜,但这题是走(0,0)点开始,似乎只用右和下两个方向也可以,这样子做会优化时间复杂度吗?
不影响时间复杂度,因为绝大部分格子都需要搜4个方向。
确实只需要两个方向就可以遍历完全部的格子哈,相当于优化时间复杂度中的常数项
暴力流
不错!DFS也是可以的,时间复杂度也是 $O(nm)$。
为什么是这个,我还以为是指数级别的,hh
因为有
vis[i][j]
判重,所以每个点只会搜索一遍,一共只有 $O(nm)$ 个格子,所以总时间复杂度仍然是 $O(nm)$。递归的时间复杂度不怎么会分析,听了y总回答,觉得很高兴
(i/10+i%10+j/10+j%10)>k)
i和j如果是123,这样能得到正确结果吗
这道题目的数据范围比较小,限定了
n <= 50, m <= 50
,所以i
和j
都在100以内。你这个程序结果咋不对呀
我这个是java程序,你看看是不是语言弄错了
hhh,我用的c++改的
真的暴力= =
仿照您的DFS代码,写的C++,不知道哪不对劲?
因为dfs会递归下去,参数传递的是形参,因此要在vis前面加个引用,表示这个数组的值已经修改
感谢您
很棒。
优秀
请问 这里DFS的为什么不用回溯呢
vis[i][j] = true
这里vis数组的作用是判重,避免重复搜索合法的节点,因此不需要回溯
是不是遍历完了四个方向之后也不需要往回走 所以不用回溯呢 新手对于回溯有点蒙
嗯,不要要往回走,只要往每个点4个方向一直搜就行
好的 谢谢DL
如果把整个棋盘当做一个状态,那就需要回溯;如果把棋盘中的每个点当做状态,就不需要回溯。
这份代码有问题,数组可能会越界。
请问这个地方如果把下标改成从1开始是不是就可以了?
if (st[t.first][t.second] || get_sum(t) > threshold) continude;
灿哥,重刷剑指Offer时候,发现这里有点懵,为什么当该格子不符合要求时,是直接跳出循环,而不需要将它的邻接点加入队列呢?求指教hh
因为机器人只能从某个合法格子走进相邻的合法格子,不能走进非法格子。
啊,发现了,看题不仔细了,嘿嘿~