朋友圈数量

题目:

给一个矩阵,里面记录着每个人同其他人是否是朋友关系,并且朋友关系具备可传递性。

题目连接:https://leetcode-cn.com/problems/friend-circles/?tdsourcetag=s_pctim_aiomsg

 

题目分析:

这个题说到底还是自己对递归理解的不深刻,同时为了强行套用以往的深搜的公式。应该以每个人为中心,对他以及认识的朋友进行搜索。以下图为例进行搜索过程的解析。

A的朋友是B,然后以B为中心对B展开搜索,B的朋友有C和D,分别以C和D为中心对C和D进行搜索,C没有朋友搜索结束,而D的朋友是E,继续以E为中心对E展开搜索。

与下面的岛屿面积一题相比,这一题解策略的构造是搜索整个节点空间,如果符合副中心点条件,再进行递归搜索。所以这一题的解策略是

for(int j = 0;j < M.length;j++)

而岛屿一题的解策略的构造是(-1,0),(1,0),(0,-1),(0,1)这四种策略。这也是两种典型的题目的区别,即一种是显式的矩形图的搜索,而另一种则是其他线性图或者树之类的结构。但是只要认真思考

其中递归策略以及解策略的构造即可把握题目的脉络。

代码如下:

class Solution {
    private void dfs(int[][] M,boolean[] visited,int i){
        
        for(int j = 0;j < M.length;j++){
            if(M[i][j] == 1 && !visited[j]){
                visited[j] = true;
                dfs(M,visited,j);
            }
        }
    }
    public int findCircleNum(int[][] M) {
        int result = 0;
        boolean[] visited = new boolean[M.length];
        // visiited代表的含义是每个人是否被访问过,因为这个是无向图,所以不需要存储互相的访问状态
        for(int i = 0;i < M.length;i++){
            if(!visited[i]){
                dfs(M,visited,i);
                result++;
            }
        }


        return result;
    }
}

  

 

 

这个题与LC中的第200题非常相似。

LC200 题目:

找出地图中岛屿的个数。

分析:遍历地图中的每一个角度,如果是陆地(‘1’),那么就以此点为中心往([x-1,y],[x+1,y],[x,y-1],[x,y+1])四个方向进行搜索。

以[x-1,y]方向为例,在[x-1,y]方向找到为‘1’的点后以[x-1,y]为中心往[x-1,y]的四个方向进行搜索,直到某一点不为‘1’,此过程为递归过程。

code:

 

1 class Solution {
 2      public void dfs(char[][] grid,int i,int j){
 3         if (i > grid.length || j > grid[0].length){
 4             return;
 5         }
 6         grid[i][j] = '0';
 7         if ((i-1) >= 0 && grid[i-1][j] == '1'){
 8             dfs(grid,i-1,j);
 9         }
10 
11         if ((i+1) < grid.length && grid[i+1][j] == '1'){
12             dfs(grid,i+1,j);
13         }
14 
15         if (j-1 >= 0 && grid[i][j-1] == '1'){
16             dfs(grid,i,j-1);
17         }
18 
19         if ((j+1) < grid[0].length && grid[i][j+1] == '1'){
20             dfs(grid,i,j+1);
21         }
22     }
23     public int numIslands(char[][] grid) {
24         if(grid.length == 0 || grid == null){
25             return 0;
26         }
27         int result = 0;
28         //boolean[][] visited = new boolean[grid.length][grid[0].length];
29         for (int i = 0;i < grid.length;i++){
30             for (int j = 0;j < grid[0].length;j++){
31                 if (grid[i][j] == '1'){
32                     dfs(grid,i,j);
33                     result++;
34                 }
35             }
36         }
37 
38         return result;
39     }
40 }

 

 

与上题的对比:

两者的搜索的方向并不相同。第一题是以某个人为中心后,将所有人重新扫描一边,如果找到朋友了,以该朋友为副中心继续扫描。

也就是说找到中心点后,搜索方向也就是所有人都会是递归的起点,所以第一题在for循环中调用了递归。

反观第二题,找到中心点之后,只需要从上下左右四个方向进行搜索,也就是说递归方向只有4个。

搜索的方向/范围,也就是递归开始的起点,搜索也就是寻找下一个中心点,而这个过程是个递归的过程。

posted @ 2019-10-27 15:01  知事  阅读(203)  评论(0)    收藏  举报