今晚主要熟悉了DFS BFS 在一道题目里面的具体实现:


这道题目有两种方法:

DFS depth first search 深度优先搜索

DFS
采用递归的思想,直到找到最后一个满足条件的坐标,然后往回回溯;
一般来讲,就是定义自己的dfs函数,它的返回值就是满足条件的坐标个数;例如在本题里面,我需要找出机器人可以到达的所有格子总数,也就是满足条件的坐标总数。

我可以定义一个dfs函数 ,它的返回值就是满足条件的坐标总数:

 int movingCount(int m, int n, int k) {
   
        return dfs(0,0,0,0,m,n,k);
    }

然后,在dfs的具体实现中,当满足条件的时候,我返回1+dfs(向下一格)+dfs(向右一格)

int dfs(int i,int j,int si,int sj,int m,int n,int k){
   
        return 1+dfs(i+1,j,(i+1)%10==0? si-8:si+1,sj,m,n,k)+dfs(i,j+1,si,(j+1)%10==0? sj-8:sj+1,m,n,k);
    }

什么时候满足条件呢?
索引i j 需要满足m和n的约束 ;
坐标各位数之和需要满足k的约束;

 int dfs(int i,int j,int si,int sj,int m,int n,int k,vector<vector<bool>>& visited){
   
        if(i>=m||j>=n||(si+sj)>k) return 0;
        return 1+dfs(i+1,j,(i+1)%10==0? si-8:si+1,sj,m,n,k)+dfs(i,j+1,si,(j+1)%10==0? sj-8:sj+1,m,n,k);
    }

所以,一旦不满足这些条件,我就直接返回0;

至此,大概的思路我们有了,但是仔细一想(想个屁,跑测试出错了!)会有坐标被重复访问,因此我们需要添加一个额外的判断,如果该坐标已经访问过了,那么就return 0;
所以,我们 修改 主函数:采用一个二维的bool数组来存储元素被访问的情况,如果访问过,就置为true;

int movingCount(int m, int n, int k) {
   
        //DFS 深度优先搜索 从底部开始
        //使用递归,往底部深入,直到最后一个元素
        vector<vector<bool>> visited(m,vector<bool>(n,0));
        return dfs(0,0,0,0,m,n,k,visited);
    }

那么,如果该坐标为true,就return 0;因此,修改dfs:

int dfs(int i,int j,int si,int sj,int m,int n,int k,vector<vector<bool>>& visited){
   
        if(i>=m||j>=n||(si+sj)>k||visited[i][j]) return 0;
        visited[i][j]=true;
        return 1+dfs(i+1,j,(i+1)%10==0? si-8:si+1,sj,m,n,k,visited)+dfs(i,j+1,si,(j+1)%10==0? sj-8:sj+1,m,n,k,visited);
    }

BFS breath first search 广度优先搜索

2. BFS
BFS 的思想是使用队列来实现,也就是先进先出,从头部位置的格子坐标开始判断,具体来说就是:

首先,人为规定,向下方向>向右方向

还是这个图,那么判断的格子顺序就是:
(0,0)
(1,0)
(0,1)
(2,0)
(1,1)
(0,2)
(3,0)
(2,1)
(1,2)
(0,3)
(3,1)
(2,2)
(1,3)
(3,2)
(2,3)
(3,3)
我们每次从队列的头部吐出一个数据,如果满足条件,格子数+1,并且在尾巴上压入向下、向右方向的元素;
可以使用一个vector存储(i , j , si , sj)
判断的时候,判断条件和上面DFS一样,

if(i>=m||j>=n||(si+sj)>k) 不满足;
int movingCount(int m, int n, int k) {
     
        queue<vector<int> > pos ;
        pos.push({
   0,0,0,0});
        int res=0;
        while(pos.size()>0){
   
            vector<int> tmpArray=pos.front();
            pos.pop();
            int i=tmpArray[0],j=tmpArray[1],si=tmpArray[2],sj=tmpArray[3];
            if(i>=m||j>=n||(si+sj)>k) continue;
            res++;
            pos.push({
   i+1,j,(i+1)%10==0 ? si-8:si+1,sj});
            pos.push({
   i,j+1,si,(j+1)%10==0 ? sj-8:sj+1});

        }
        return res;
    }

同样的 也有元素重复访问的情况,因此,也需要一个二维bool数组存储被访问的情况;
于是,代码可以修改为:

int movingCount(int m, int n, int k) {
   
        //深度优先搜索DFS(栈的思想,从底部开始计数) 与 广度优先搜索BFS(队列的思想,从顶部开始计数)
        //1. 首先是采用BFS实现 
        //从坐标(0,0)开始往下遍历,顺序的往队列里面push元素,如果遇到了不满足的坐标,就直接continue,后面的向下向右push直接跳过;push的是坐标(i,j,si,sj)

        vector<vector<bool>> visited (m,vector<bool> (n,0));//用于存储已经访问过的元素,true false 
        queue<vector<int> > pos ;
        pos.push({
   0,0,0,0});
        int res=0;
        while(pos.size()>0){
   
            vector<int> tmpArray=pos.front();
            pos.pop();

            int i=tmpArray[0],j=tmpArray[1],si=tmpArray[2],sj=tmpArray[3];
            if(i>=m||j>=n||(si+sj)>k||visited[i][j]) continue;
            visited[i][j]=true;
            res++;
            pos.push({
   i+1,j,(i+1)%10==0 ? si-8:si+1,sj});
            pos.push({
   i,j+1,si,(j+1)%10==0 ? sj-8:sj+1});

        }
        return res;
    }

结尾:使用的时间远不止十分钟,但是很爽啊,现在的我思路顺畅,无欲无求!!!晚安