记一道经典分积木问题

882 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

前言

前段时间,一个测试朋友在面试中碰到这样一道题。A和B是两兄弟,妈妈给了他们一大堆积木,每块积木都有自己的重量,现在他们想要将积木分成两堆。哥哥A负责分配,弟弟B要求两兄弟获得的积木总重量相等,(B数学学的有点奇葩,只会将两个数转为2进制然后进行相加,但是总是会忽略进位。)不然会哭(输出-1)。例如:25(11101)+11(1011)= 18(10010)。A比较坏,他知道B数学学的有点问题,想使自己拿到的重量最大并且不让B哭。问如何进行分配。

输入:

n - 积木总数 ;[n1, n2, ... , n] - 积木数组

输出: 哥哥可获得的最大积木重量

分析

这道题乍一看,好像没有什么思路。我们先捋一捋题干。首先可以确定的是,弟弟的加法就是异或(相同为0,相异为1)运算。知道这一点,我们根据异或的特点,将所有的积木重量依次进行异或,如果结果为0,那恰恰说明了按照弟弟的逻辑,是可以进行平分的,我们只需要将积木中最轻的一块交给弟弟即可(黑心商家啊!)。如果结果不为0,证明按照弟弟的逻辑是不能平分的,不管怎么分,弟弟都会哭。

实现

function divide(n, arr) {
    // 定义哭的条件,非0才会哭
    let cry = 0;
    // 对传进来的积木重量依次进行异或操作,判断是否可以平分
    arr.forEach(item => {
        cry ^= item;
    });

    if (cry === 0) {
        // 可以平分,对数组进行一次排序
        arr.sort();
        // 取出给弟弟的积木
        let result = arr[0];
        // 对积木重量进行累加,减去给弟弟的就是自己的
        return arr.reduce((a, b) => a + b) - result;
    }
    return -1;
}
console.log(divide(3, [3, 5, 6])); // 11

总结

很多时候,我们碰到题干看着比较难的题,先不要慌,大多数情况下,解题思路都在题干中指明了。就比如本题,只想能联想到异或,进而联想到异或的特点,就得到了解题的思路。顺着思路往下写就行。