题目及解题思路来源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
逻辑流程:
- 判断n中的硬币数量,如果n>2则执行2,否则执行5.
- 将n分为上图的四堆,拿 a 和 b 比较,如果 a == b ,则 假币在 c 或 d 中。否则假币在 a 或 b 中。
- 如果 a == b,则拿 a 和 c 比较。如果 a == c,则假币在d(余数堆)中。将 d 再次 执行流程1,并且n=n%3。如果不等,则假币在 c 中,将 c 再次 执行流程1,并且n=(n-n%3)/3。
- 如果 a != b,则拿 a 和 c 比较。如果 a == c,则假币在b中,将 b 再次 执行流程1,并且n=(n-n%3)/3。如果不等,则假币在 a 中,将 a 再次 执行流程 1,并且n=(n-n%3)/3。
- 如果n==2,则将两枚硬币进行比较找出假币。
- 如果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)用了递归