【互联网面试】朋友圈问题

本文介绍了一种使用并查集算法解决朋友圈数量问题的方法,通过优化数据结构减少空间复杂度。

王道面试P231

问题描述:

假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或间接的好友(好友的好友的好友...),

则认为他们属于同一个朋友圈,

请写程序求出这n个人里一共有多少个朋友圈。

假如:n = 5, m = 3, r = {{1 , 2} , {2 , 3} ,{4 , 5}},表示有5个人,1和2是好友,2和3是好友,4和5是好友,

则1、2、3属于一个朋友圈,4、5属于另一个朋友圈,结果为2个朋友圈。

最后请分析所写代码的时间、空间复杂度。评分会参考代码的正确性和效率。



小米2013年招聘笔试算法题--朋友圈

 

[cpp]  view plain copy
 
    1. //朋友圈问题  
    2.   
    3. #include <iostream>  
    4. using namespace std;  
    5.   
    6. int set[10001];  
    7. //带路径优化的并查集查找算法  
    8. inline int find(int x)               
    9. {    
    10.     int i,j,r;   
    11.     r = x;    
    12.     while(set[r] != r)     
    13.     {  
    14.         r = set[r];    
    15.     }  
    16.     i = x;  
    17.     while(i != r)  
    18.     {  
    19.         j = set[i];  
    20.         set[i] = r;  
    21.         i = j;  
    22.     }    
    23.     return r;    
    24. }   
    25. //优化的并查集归并算法  
    26. inline void merge(int x, int y)         
    27. {    
    28.     int t = find(x);    
    29.     int h = find(y);    
    30.     if(t < h)    
    31.     {  
    32.         set[h] = t;    
    33.     }  
    34.     else    
    35.     {  
    36.         set[t] = h;    
    37.     }  
    38. }  
    39.   
    40. int friends(int n , int m , int r[][2])    
    41. {    
    42.     int i , count;    
    43.     //初始化并查集,各点为孤立点,分支数为n  
    44.     for(i = 1 ; i <= n ; ++i)         
    45.     {  
    46.         set[i] = i;    
    47.     }  
    48.     for(i = 0 ; i < m ; ++i)    
    49.     {  
    50.         merge(r[i][0] , r[i][1]);    
    51.     }  
    52.     for(i = 1 ; i <= n ; ++i)         
    53.     {  
    54.         cout << set[i] <<" ";    
    55.     }  
    56.     count = 0;    
    57.     for(i = 1 ; i <= n ; ++i)    
    58.     {    
    59.         if(set[i] == i)    
    60.         {  
    61.             ++count;    
    62.         }  
    63.     }    
    64.     return count;    
    65. }  
    66.   
    67. void main()  
    68. {  
    69.     int n=5;  
    70.     int m=3;  
    71.     int a[][2]={{1,2},{2,3},{4,5}};  
    72.     cout << friends(n,m,a) <<endl;  
    73. }  
      1. http://blog.youkuaiyun.com/bxyill/article/details/8965530#comment
        1. 转载请注明:http://krystism.is-programmer.com/若有错误,请多多指正,谢谢!

          题目描述:假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或间接的好友(好友的好友的好友...),则认为他们属于同一个朋友圈,请写程序求出这n个人里一共有多少个朋友圈。

          假如:n = 5 , m = 3 , r = {{1 , 2} , {2 , 3} , {4 , 5}},表示有5个人,1和2是好友,2和3是好友,4和5是好友,则1、2、3属于一个朋友圈,4、5属于另一个朋友圈,结果为2个朋友圈。 最后请分析所写代码的时间、空间复杂度。评分会参考代码的正确性和效率。

          显然本质就是求无向图的连通分量个数。而要求连通分量数,就是遍历图的过程。遍历完所有节点,需要调用遍历几次就是连通分量个数。比如题目中使用DFS,从节点1出发,可以遍历节点2,3,而要遍历完所有节点还需从节点4出发,再遍历一次,共遍历两次,因此连通分量数为2。实现代码如下:

          ?
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          #include <stdio.h>
          #include <stdlib.h>
          #include <string.h>
          #define N 10000
          char map[N][N];
          char used[N];
          void dfs( int i, int n)
          {
               int j;
               used[i] = 1;
               for (j = 1; j <= n; j++) {
                   if (map[i][j] && !used[j])
                       dfs(j, n);
               }
          }
          /* 判断是否存在未访问节点
            * 若存在,则返回第一个未访问节点编号
            * 若不存在,则返回-1
            */
          int isVisitedAll( int n)
          {
               int i;
               for (i = 1; i <= n; i++)
                   if (used[i] == 0)
                       return i;
               return -1;
          }
          int main( int argc, char **argv)
          {
               int n, m;
               int a, b, i, sum, cur;
               while ( scanf ( "%d%d" , &n, &m) != EOF) {
                   if (n == 0)
                       break ;
                   memset (map, 0, sizeof (map));
                   memset (used, 0, sizeof (used));
                   sum = 0;
                   for (i = 0; i < m; i++) {
                       scanf ( "%d%d" , &a, &b);
                       map[a][b] = map[b][a] = 1;
                   }
                   while ((cur = isVisitedAll(n)) != -1) {
                       sum++;
                       dfs(cur, n);
                   }
                   printf ( "%d\n" , sum);
               }
               return 0;
          }

          暂且不说时间复杂度吧,空间复杂度就足够吓人了。首先需要一个表示图的01矩阵,大小为O(n  * n), 还需要记录是否节点是否已经被访问,需要大小为O(n)的空间。

          换一种思路,其实根据题目朋友圈,我们就应该想到每一个圈其实就是一个集合,存在关系的,归为一个集合中,最后即需要求有多少个不相交的集合即有多少个圈子。由此不难想出,这其实就是并查集。不了解并查集可以查看维基百科并查集

          想到了并查集,不难写出代码:

          ?
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          50
          51
          52
          53
          54
          55
          56
          57
          58
          #include <stdio.h>
          #include <stdlib.h>
          #include <string.h>
          #define N 100000
          int father[N];
          void init( int n)
          {
               int i;
               for (i = 1; i <= n; i++)
                   father[i] = i;
          }
          int getFather( int v)
          {
               if (father[v] == v)
                   return v;
               else {
           
                   father[v] = getFather(father[v]);
                   return father[v];
               }
          }
          void merge( int x, int y)
          {
               int fx = getFather(x);
               int fy = getFather(y);
               if (fx < fy)
                   father[fx] = fy;
               else
                   father[fy] = fx;
          }
          int same( int x, int y)
          {
               return getFather(x) == getFather(y);
          }
          int main( int argc, char **argv)
          {
               int n, m;
               int a, b;
               int i;
               int sum;
               while ( scanf ( "%d%d" , &n, &m) != EOF) {
           
                   if (n == 0)
                       break ;
                   init(n);
                   sum = 0;
                   for (i = 1; i <= m; i++) {
                       scanf ( "%d%d" , &a, &b);
                       merge(a, b);
                   }
                   for (i = 1; i <= n; i++) {
                       if (getFather(i) == i)
                           sum++;
                   }
                   printf ( "%d\n" , sum);
               }
               return 0;
          }

          显然空间大大减少了,只需要O(n)的空间。

### 腾讯产品经理面试概述 腾讯作为中国领先的互联网公司之一,在招聘产品经理时通常会关注候选人的综合素质和实际能力。以下是关于腾讯产品经理职位的要求、面试经验和准备建议。 #### 职位要求 腾讯的产品经理岗位一般需要候选人具备以下几个方面的能力和背景: - **行业理解力**:熟悉互联网行业的趋势和发展方向,能够敏锐捕捉市场机会并制定相应策略[^1]。 - **数据分析能力**:擅长通过数据驱动决策,能有效利用各种工具和技术完成复杂的数据分析工作。 - **沟通协调能力**:能够在跨部门协作中起到桥梁作用,推动项目的顺利实施。 - **创新思维**:具有较强的创新能力,可以设计出满足用户需求的新功能或新产品。 #### 面试经验 根据以往的经验分享,腾讯的产品经理面试流程可能包括多个环节,具体如下: - **简历筛选阶段**:重点考察求职者的教育背景、工作经验以及过往成就等内容。一份清晰明了且突出个人优势的简历至关重要。 - **初面(电话/视频)**:主要测试基本素质与逻辑思考水平,可能会涉及行为类问题或者情景模拟题型[^2]。 ```plaintext 示例问题:“请描述一次团队合作失败的经历及其教训。” ``` - **多轮技术面谈**:深入探讨专业知识领域内的具体内容,比如如何规划一款新应用?怎样评估竞品表现等等。 ```plaintext 示例问题:“假设我们要开发一个社交软件,请谈谈您的设计方案?” ``` #### 准备建议 为了更好地应对腾讯产品经理的面试挑战,可以从以下几个方面着手准备: - **研究目标企业**:深入了解腾讯的企业文化、核心业务板块及相关产品线的信息,做到心中有数。 - **梳理项目经历**:整理自己曾参与过的重要项目资料,提炼关键点以便于回答有关实践操作层面的问题。 - **练习常见题目**:针对可能出现的各种类型考题进行反复演练,提高临场发挥能力和表达技巧。 ```python def prepare_interview(): research_company = "深入了解腾讯企业文化及主营业务" organize_projects = ["总结过去成功案例", "强调解决难题过程"] practice_questions = [ "如果让你重新设计微信朋友圈你会怎么做?", "讲述一段克服困难达成目标的故事" ] return f"{research_company}, {organize_projects}, 并不断重复{practice_questions}" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值