奇安信笔试编程题完整解析附代码

昨天晚上奇安信笔试,两道编程题做的都不好,有紧张的元素,也有自己实力不够硬的问题,总之把两道编程题又做了一遍,思路屡清楚,下次继续努力!

其实两道题非常非常简单,如果放在高中数学,基本就是送分题了,但是最近疫情期间,在家都躺退化了。。。算了,开搞!

1. 第一题,抽硬币题

**题干:**有1000枚硬币,其中有10枚是金币,从中取出n枚硬币,求这n枚硬币中有金币的概率。答案保留6位小数。如抽取一枚,金的概率0.010000

**解题思路:**一道简单的高中数学送分题,如果正着去思考,那这n枚硬币中有可能是1枚金的,也可能是2枚金的,甚至更多,那就没法算了。

我们可以逆向思维,可能性只有两种,要么有金的,要么没金的,那我们可以计算没有金的的概率,用(1-没有金的),不就是有金的概率了吗?

好的我们来列一下数学公式:

没有金的概率 = (从990枚中抽取n枚的所有可能)/(从1000枚中抽取n枚的所有可能)

数学公式:

奇安信笔试编程题完整解析附代码_第1张图片

是不是一股熟悉的气息冒上心头,诶!对了,就是概率题嘛~

当然,有两个极端情况需要处理,那就是当抽取硬币大于990的时候,那就是百分百的概率了。当抽取小于0的时候,参数是错误的。这个相信每个boy和girl都好理解!

接下来还有一个问题要解决,那就是理论是理论,实际是实际,如果正好抽990个,那难道我们要把990的阶乘算一遍吗?显然是不行的,一来double类型根本是放不下的,而来题目也有时间和内存的要求,有同学想到字符串化之后处理,那么看看分子和分母,相除以。。。算了,我们来看看怎么办吧!

细心的胖友已经发现了,分子与分母有一段是重叠的,我们可以互相抵消,那么有多少是重叠的呢?

其实很简单,分母从1000到990是自己独占的,分母的最后一位(1000-n+1)和分子抵消后,分子还没有结束,直到(990-n+1)

接下来就简单了,我们只需要计算分母为1000到990的累乘,分子为(1000-n)到(990-n+1)的累乘即可。

接下来就是代码啦!代码里我也会标着我提到的点的注释,欢迎大家探讨纠错!

public class GoldSelect {
    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()) {
            // 取出的数量 与 返回的结果
            int n = in.nextInt();
            double result = 0;
            if (n <= 0) {
                result = 0;
            }
            if (n > 990) {
                result = 1;
            }
            // 设置分子分母,因为累乘,所以为1
            double top = 1;
            double under = 1;
            
            // 分母为1000到991
            for (int action = 1000; action > 990; action --)
            {
                under *= action;
            }
            // 分子为1000-n 到 990-n+1
            for (int action = 1000-n; action >= 990-n+1; action--)
            {
                top *= action;
            }

            result = 1 - top / under;

            // 格式化小数位数
            BigDecimal a = new BigDecimal(result);
            System.out.println(a.setScale(6,BigDecimal.ROUND_DOWN));
        }
    }
}

2. 第二题,我的兔子真能生与长生不老

**题干:**有一对可爱的兔子,他们从出生后的第五个月开始,每个月生1对小兔子,新生的小兔子五个月后也会开始生兔子,兔子不会死亡,那么第n个月的时候,会有多少对兔子呢?如第五个月,答案:2对。

**解析:**同样的高中数学题,或许是小学奥数题吧,我没有学过奥数。这道题也应证了“不管甲方的要求多么无理,做就完了”,这道题昨天我的完成度没有到百分之百,修正思路后彻底解决了问题。

首先我们可以写一下由简入难,从第一个月到第四个月都是1对,第五个月开始变成2对,3对,4对,5对,那么第九个月会是6对吗?非也!

第九个月的时候,第五个月出生的1对小兔子。也长大了,迎来了它的第五月,开启了无尽的生娃旅程。所以除了祖宗那1对,又1对加入了生娃大军,所以这个月会增加两对,即变成了7对!

这时候可以发现思路其实非常简单,该月增长的对数,就等于四个月前的那个月的兔子对数。

比方说五月有多少对,九月就增长多少对,五月以后的还没长大,我们应该保存着。

所以只是一个典型的队列题,只要保存近四个月的数量即可。每次循环都是三步:四个月前的数字出队,给当前兔子对数加上,当前兔子对数入队。

就像开开冰箱门,给大象整进去,再关上冰箱门~~明白了吧!

接下来是代码,有详细的注释,欢迎讨论!

public class Rabbit {
    public static void
    main(String[] args) {
        Scanner reader = new Scanner(System.in);

        while (reader.hasNextInt()) {
            // 第n月
            int n = reader.nextInt();
            if (n <= 0) {
                System.out.println("非法参数");
                continue;
            }
            // 初始兔子1对 与 增伤对数,初始0
            int rabbitNum = 1;
            int item = 0;
            // 队列存前四个月的数量
            Queue queue = new LinkedList<Integer>();

            // 每次循环的目的是出队四个月前的数量,入队当月数量
            for (int i = 1; i <= n; i ++) {
                // 1,2,3,4月的前四个月什么都没有,直接入队
                if ( i - 4 <= 0){
                    queue.offer(1);
                    continue;
                }
                // 得到四个月前的那个月有多少对
                int poll = (Integer)queue.poll();
                // 增加兔子的对数
                rabbitNum += poll;
                // 存入该月对数
                queue.offer(rabbitNum);
            }
            System.out.println("兔子对数:" +rabbitNum);
        }
    }
}

3. 总结

其实这两道题都非常简单, 如果是高考前的盆友们,一定是分分钟秒杀!可惜啊,最近在家吃的多喝得多,脑子都不太好使了,得减减肥啦!

加油吧朋友们,祝你们前程似锦,一路高歌!

你可能感兴趣的:(大聖的错题本)