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

2016年小米校招笔试第三题(西安站)

假如已知有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个朋友圈。
参考解法(Java版):<Q:316190672,欢迎交流>
package XiaoMi;

import java.util.LinkedList;
import java.util.List;

public class test17 {
    /*****************************************************************************************
     *@Author:guomutian911
     * 算法思想:每一对好友为一项,如{1,5},{3,7},{2,5}为三项。第一项中1为项的左值,5为项的右值。
     * 用布尔数组b[]标记遍历过的项,因为while循环是跳跃进行的,如上述关系所示,第一项为{1,5},因为
     * 第二项中无第一项中元素则跳跃至第三项。算法借助了两个集合:list放遍历过的元素,数组b放项标记。
     ****************************************************************************************/
    public static void main(String[] args) {
        int[][] r = { { 1, 5 }, { 3, 5 }, { 4, 5 }, { 1, 4 }, { 5, 6 },
                { 8, 1 }, { 9, 20 }, { 98, 11 }, { 13, 76 }, { 98, 77 },{2,1} };
        friends( r);
    }

    /**
     * 根据二维数组输出朋友圈
     * @param r 关系数组
     * @return void
     * */
    static void friends(int[][] r) {
        boolean[] b = new boolean[r.length]; //标志是否遍历过,并加入朋友圈集合中
        int s = r[0][0]; //从第一项左边开始遍历
        List<Integer> list = new LinkedList<Integer>(); //插入操作多所以使用LinkedList
        boolean flag = true; //判断循环条件是否终止,while停止标记

        b[0] = true; //从第一项开始,表示已经遍历过,并加入集合所以设置为true
        while (flag) {
            list = new LinkedList<Integer>();
            list.add(s); //加入一项中的左或右值
            for (int j = 0; j < list.size(); j++) {
                int key = list.get(j); //从头遍历list
                for (int i = 0; i < r.length; i++) {
                    if (r[i][0] == key) { //从头遍历所有项,分别取其左右值同list中key值比较
                        if (!list.contains(r[i][1])) { //list中有左边值,无右边值(若用set则不用判断)
                            list.add(r[i][1]); //加入右边值
                        }
                        b[i] = true; //标记该项已遍历
                    } else if (r[i][1] == key) { 
                        if (!list.contains(r[i][0])) { //list中有右边值,无左边值
                            list.add(r[i][0]); 
                        }
                        b[i] = true; //标记该项已遍历
                    }
                }
            }

            System.out.println(list); //输出一条朋友圈
            
            //while循环为跳跃前进,所以需要对标记数组从头遍历
            for (int i = 0; i < b.length; i++) {
                if (b[i] == false) {
                    s = r[i][0]; //如果没有遍历过,则定位到该处
                    break; //结束for循环,继续上一步while循环
                }else if (i == b.length - 1&&allScan(b)) //使用短路与,减少复杂度
                    flag = false; //停止while循环
            }
        }
    }

    /**
     * 判断一个boolean数组里面的值是不是全为true
     * @param b 接受的数组
     * @return boolean 如果数组全为true返回true
     * */
    static boolean allScan(boolean[] b){
        for(int i=0;i<b.length;i++){
            if(b[i] == false){
                return false;
            }
        }
        return true;
    }
}


运行结果:
[1, 5, 4, 8, 2, 3, 6]
[9, 20]
[98, 11, 77]
[13, 76]

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值