JavaScript算法26- 按位与结果大于零的最长组合(leetCode:6065)周赛

6065. 按位与结果大于零的最长组合


一、题目

对数组 nums 执行 按位与 相当于对数组 nums 中的所有整数执行 按位与

  • 例如,对 nums = [1, 5, 3] 来说,按位与等于 1 & 5 & 3 = 1
  • 同样,对 nums = [7] 而言,按位与等于 7
    给你一个正整数数组 candidates 。计算 candidates 中的数字每种组合下 按位与 的结果。 candidates 中的每个数字在每种组合中只能使用 一次

返回按位与结果大于 0最长 组合的长度。

示例 1:

输入:candidates = [16,17,71,62,12,24,14]
输出:4
解释:组合 [16,17,62,24] 的按位与结果是 16 & 17 & 62 & 24 = 16 > 0 。
组合长度是 4 。
可以证明不存在按位与结果大于 0 且长度大于 4 的组合。
注意,符合长度最大的组合可能不止一种。
例如,组合 [62,12,24,14] 的按位与结果是 62 & 12 & 24 & 14 = 8 > 0 。

示例 2:

输入:candidates = [8,8]
输出:2
解释:最长组合是 [8,8] ,按位与结果 8 & 8 = 8 > 0 。
组合长度是 2 ,所以返回 2 。

提示:

  • 1 <= candidates.length <= 105
  • 1 <= candidates[i] <= 107

二、思路

找出符合条件的组合的特点
以 示例1的组合 [16,17,62,24] 为例

十进制对应二进制
1600010000
1700010001
6200111110
2400011000

通过观察,可以发现:按位与的结果要大于0,得保证组合中某一位都为1
结论:统计二进制中的每一位上,为1的整数个数,个数最大值即为本题结果

三、题解

方法1(菜鸟版,可忽略)

  • 利用toString(2),将所有整数降序排列后,转为二进制字符,存入到一个新的数组bCandidates
  • 用双重for循环,外层循环遍历,执行条件为:小于最大整数的二进制字符串长度bCandidates[0].length,用occurNum记录该位上为1的整数个数
  • 内层循环遍历bCandidates,若bCandidates[j]的第i个字符为1,occurNum++
    由于数组是降序排列的,若bCandidates[j]的第i个字符为undefined,则后续的bCandidates[j+1] bCandidates[j+2]…上的第i个字符一定也为undefined,所以可以使用break,跳出内层循环
/**
 * @param {number[]} candidates
 * @return {number}
 */
var largestCombination = function (candidates) {
    candidates.sort((a, b) => b - a)
    let bCandidates = candidates.map(item => item.toString(2))
    const iLength = bCandidates[0].length
    let res = 0,sum;
    for (let i = 0; i < iLength; i++){
       sum = 0;
        for (let j = 0; j < bCandidates.length; j++){
            let str = bCandidates[j]
            let strLength = str.length
            if (str[strLength - i - 1] === '1') {
                sum ++
            } else if (str[strLength - i - 1] === undefined) {
                break
            }           
        }
        res = Math.max(res, sum)
    }
    return res
};

在这里插入图片描述

方法2(进阶简洁版)

方法1中,我们判断整数的二进制第 i 位是否为1:先将整数转为二进制字符串,再获取字符串的第i位的值。

其实我们可以利用 按位与&左移运算符<< 更快速的判断candidates[j] & (1 << i)

/**
 * @param {number[]} candidates
 * @return {number}
 */
var largestCombination = function (candidates) {
    let res = 0, sum;
    for (let i = 0; i < 32; i++) {
        sum = 0;
        for (let j = 0; j < candidates.length; j++) {
            if (candidates[j] & (1 << i)) {
                // candidate[i] 的第 i 位是 1
                sum++;
            }
        }
        res = Math.max(res, sum)
    }
    return res;
};

性能大幅提升!nice
在这里插入图片描述

四、知识拓展

1、& 和 && 的区别

按位与& :

  • a&b是把 a 和 b 都转换成二进制数然后再进行与的运算
  • &对所有表达式都得判断。

逻辑与&&:

  • a&&b就是当且仅当两个操作数均为 true时,其结果才为 true,只要有一个为false,a&&b就为false。
  • &&进行的是短路判断,即第一个表达式不成立的话,后面的表达式不运算,直接返回。

2、<< 左移运算符

左移运算符(<<)表示将一个数的二进制值向左移动指定的位数,尾部补0,即乘以2的指定次方(最高位即符号位不参与移动)。
例:表达式14 << 2的值为56,因为14(即二进制的00001110)向左移两位等于56(即二进制的00111000)

3、js中十进制和二进制的转换

var num = 10;

num.toString(2);        // 十进制转二进制

parseInt(num, 2);     // 二进制转十进制;num 被看做是二进制的数

parseInt(num, 2).toString(8);     // 二进制转八进制;也可以看做是二进制先转成十进制,再转成八进制
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值