js寻找n枚硬币中的假币

题目及解题思路来源6.3算法小节:【前端工程师面试宝典】学习说明_互联网校招面试真题面经汇总_牛客网

题目:在n枚外观相同的硬币中,有一枚是假币,并且已知假币与真币的重量不同,但不知道假币与真币相比较轻还是较重。可以通过一架天平来任意比较两组硬币,设计一个高效的算法来检测这枚假币。

思路:

        使用减治法的解题思路,将硬币分为3堆,则每堆的硬币数量为 n/3 ,但是这是在 n%3==0的情况下才能成立,所以我们将 n 枚硬币分为 3 堆加 1 堆 余数堆(余数堆可能为0),则可分为如下(n-n%3)/3, (n-n%3)/3, (n-n%3)/3, n%3。

        如下分组:
        a堆: (n-n%3)/3
        b堆: (n-n%3)/3
        c堆: (n-n%3)/3
        d(余数堆): n%3

        逻辑流程:

  1. 判断n中的硬币数量,如果n>2则执行2,否则执行5.
  2. 将n分为上图的四堆,拿 a 和 b 比较,如果 a == b ,则 假币在 c 或 d 中。否则假币在 a 或 b 中。
  3. 如果 a == b,则拿 a 和 c 比较。如果 a == c,则假币在d(余数堆)中。将 d 再次 执行流程1,并且n=n%3。如果不等,则假币在 c 中,将 c 再次 执行流程1,并且n=(n-n%3)/3。
  4. 如果 a != b,则拿 a 和 c 比较。如果 a == c,则假币在b中,将 b 再次 执行流程1,并且n=(n-n%3)/3。如果不等,则假币在 a 中,将 a 再次 执行流程 1,并且n=(n-n%3)/3。
  5. 如果n==2,则将两枚硬币进行比较找出假币。
  6. 如果n==1,则该硬币就是假币,输出结果结束。

实现:

        //计算数组和
        function sumArr(arr) {
            //eval():括号中必须为字符串,eval可以执行字符串中的表达式,如果参数是Javascript语句,eval()将执行 Javascript 语句
            //不建议用eval(),它使用与调用者相同的权限执行代码,所以尽可能的不要去使用它,以防被其他人员植入恶意代码.
            // console.log(eval(arr.join("+")));
            //forEach遍历
            let n = 0;
            arr.forEach(function (val, idx, obj) {
                n += val;
            }, 0);
            return n;
            // console.log(n);
        }

        //判断假币,arr为所有硬币重量的数组,t为真币的重量
        function Fcoin(arr, t) {
            if (arr.length == 1) {
                m = arr[0];
                return m;
            }
            if (arr.length == 2) {
                if (arr[0] != t) {
                    m = arr[0];
                } else {
                    m = arr[1];
                }
                return m;
            }
            //按数量等分为三组,剩下的余数归到第四组
            const n = (arr.length - arr.length % 3) / 3;
            // console.log(n);
            let arr1 = arr.slice(0, n);
            let arr2 = arr.slice(n, 2 * n);
            let arr3 = arr.slice(2 * n, 3 * n);
            let arr4 = arr.slice(3 * n, arr.length);
            // console.log(arr1, arr2, arr3, arr4);

            //第一组和第二组重量不同
            if (sumArr(arr1) != sumArr(arr2)) {
                if (sumArr(arr1) == sumArr(arr3)) {
                    Fcoin(arr2);
                } else if (sumArr(arr2) == sumArr(arr3)) {
                    Fcoin(arr1);
                }
                //第一组和第二组重量相同
            } else if (sumArr(arr1) == sumArr(arr2)) {
                if (sumArr(arr1) != sumArr(arr3)) {
                    Fcoin(arr3);
                } else if (sumArr(arr1) == sumArr(arr3)) {
                    Fcoin(arr4);
                }
            }
        }
        var m = 0;
        var a = [1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1];
        Fcoin(a, 1);
        console.log('第' + (a.indexOf(m) + 1) + '枚硬币是假币');

总结:

(1)计算数组和可以有多种方法,这里记录三种:传统for循环,forEach遍历(参数为函数,函数中有三个参数,分别为当前值,当前索引,当前对象),eval方法,其中eval方法不推荐,容易引起攻击,但是写起来很方便,需需要一行代码就可解决问题。

(2)函数中需要两个参数,arr为所有硬币重量的数组,t为真币的重量,最后返回的是假币在数组中的索引+1;

(3)外部定义m为0,在函数内部修改m的值。

(4)用了递归

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值