特此说明,本文算法改自于《从一个数组中找出 N 个数,其和为 M 的所有可能--最 nice 的解法》一文。本文不同的是,采用二进制正序表示法,这种实现思路更直观、更简单些。

问题

从一个数组中找出 N 个数,其和为 M 的所有可能。

举个例子,从数组 [1, 2, 3, 4] 中选取 2 个元素,求和为 5 的所有可能。答案是两组组合: 1,4 和 2,3。

假设封装函数为 search

function search(arr, count, sum) {...return res
}
复制代码

则有,

search([1,2,3,4],2,5)
// => [[2,3],[1,4]]
复制代码

实现思路

这里我们简单说一下总体思路:根据数组长度构建二进制数据,再选择其中满足条件的数据。

我们用 1 和 0 来表示数组中某位元素是否被选中。因此,可以用 0110 来表示数组中第 1 位和第 2 位被选中了。

下面列一下长度为 4 的所有二进制数据表示情况:

  • 0000 表示没有选择数组中的任何元素
  • 0001 表示选择了数组中第 3 位元素
  • 0010 表示选择了数组中第 2 位元素
  • 0011 表示选择了数组中第 2、3位元素
  • 0100 表示选择了数组中第 1 位元素
  • 0101 表示选择了数组中第 1、3 位元素
  • 0110 表示选择了数组中第 1、2 位元素
  • 0111 表示选择了数组中第 1、2、3 位元素
  • 1000 表示选择了数组中第 0 位元素
  • 1001 表示选择了数组中第 0、3 位元素
  • 1010 表示选择了数组中第 0、2 位元素
  • 1011 表示选择了数组中第 0、2、3 位元素
  • 1110 表示选择了数组中第 0、1、2 位元素
  • 1111 表示选择了数组中所有位元素

那么开篇的例子, 4 选 2,满足条件的二进制有 0011、0101、0110、1001、1010、1100 共 6 种可能。而符合对应元素之和为 5 的只有 0110 和 1001。

看到了吗,思路是我们构建了所有长度为 4 的二进制,再找到符合条件的二进制。

这里条件有两个。

  • 其一是,被选中的个数是 2。
  • 其二是,被选中的和是 5。

我们的算法思路逐渐清晰起来: 遍历所有二进制,判断选中个数是否为 2,然后再求对应的元素之和,看其是否为 5。

第一个问题,如何遍历所有二进制数据呢?

这个难不到我们,数组长度为 4,那么所有二进制数据是 0 - 15。

for (var i = 0; i < 16; i++) {...
}
复制代码

数组长度 4,对应16,即 1 << 4。

注意 1 << 31 为-2147483648,可以使用Math.pow(2, 31)来代替

第二个问题,如何求取被选中的元素个数呢?即求取二进制字符串中 1 的个数呢?

实现方式有多种,比如其中一种是:

function n(i) {var count = 0;while( i ) {if(i & 1){++count;}i >>= 1;}return count;
}
console.log(n(0b1010))
// => 2
复制代码

上述算法的思路其实很简单,将二进制逐步右移 1 位,看看末尾为 1 的个数。比如 10 的二进制是 1010,逐步右移的所有可能是 1010->101->10->1->0,其中有 2 次末尾是 1。因此结果是 2。

第三个问题,如何根据二进制数据来求和呢?

比如 0110,我们应该求和 arr[1] + arr[2]。

问题转化成了如何判断数组下标是否在 0110 中呢?

其实也很简单,比如下标 1 在,而下标 3 不在。我们把 1 转化成 0100,0110 & 0100 为 0100, 大于 0,因此下标 1 在。而 0110 & 0001 为 0,因此 下标 3 不在。

所以求和我们可以如下实现:

var arr = [1,2,3,4]
var s = 0, temp = [];
for (var i = 0, len = arr.length; i < len; i++) {if ( 0b0110 & 1 << (len - 1 - i)) {s += arr[i]temp.push(arr[i])}
}
console.log(temp)
// => [2,3]
复制代码

最终实现

有了以上铺垫,这里给出最终实现:

function search(arr, count, sum) {var len = arr.length, res = [];for (var i = 0; i < Math.pow(2, len); i++) {if (n(i) == count) {var s = 0, temp = [];for (var j = 0; j < len; j++) {if (i & 1 << (len - 1 -j)) {s += arr[j]temp.push(arr[j])}}if (s == sum) {res.push(temp)}}}return res;
}function n(i) {var count = 0;while( i ) {if(i & 1){++count;}i >>= 1;}return count;
}console.log(search([1,2,3,4],2,5))
// => [[2,3],[1,4]]
复制代码

最后,可以看出其实没必要引入各种概念就可以把本算法说清楚。

本文完。

改进,从一个数组中找出 N 个数,其和为 M 的所有可能相关推荐

  1. c++如何输入数组_从一个数组中找出 N 个数,其和为 M 的所有可能最 nice 的解法...

    编者按:本文由前端狂想录公众号授权奇舞周刊转载. 故事的背景 这是一个呆萌炫酷吊炸天的前端算法题,曾经乃至现在也是叱咤风云在各个面试场景中. 可以这样说,有 90% 以上的前端工程师不会做这个题目. ...

  2. 从一个数组中找出 N 个数,其和为 M 的所有可能--最 nice 的解法

    比起讨论已经存在的大牛,我们更希望有更多有潜力的前端小伙伴成为大牛,只有这样,前端在未来才能够持续不断的发光发热. 故事的背景 这是一个呆萌炫酷吊炸天的前端算法题,曾经乃至现在也是叱咤风云在各个面试场 ...

  3. 在数组中找出3个数使得它们和为0

    题目: 给定一个集合S,试找出3个数a, b, c,使得a+b+c=0.也即从集合中找出所有的和为0的3个数. 例如:集合S={-1,0, 1, 2, -1, 4},则满足条件的3个数有2对:(-1, ...

  4. 从一个数组中找出最接近目标_LeetCode每日一题 | 转变数组后最接近目标值的数组和...

    题目来源:LC1300 这道题目是一道比较经典的二分查找题. 我们注意到,当value越大时,数组之和越大,当value越小时,数组之和越小.因此,我们可以利用数组之和是value的单调递增函数这个性 ...

  5. 数据结构与算法--有序数组中找出和为s的两个数字

    有序数组中找和为s的两个数字 题目:输入一个递增排序的数组array, 和一个数字s, 在数组中找出两个数,使得这两个数的和是s,如果有多对,输出一对即可. 最简单方案 双循环,每次获取一个数据,和数 ...

  6. 编写一个程序,从10亿个数字的数组中找出100个最大的数字

    本文翻译自:Write a program to find 100 largest numbers out of an array of 1 billion numbers I recently at ...

  7. 给定一个整数数组 nums和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标。

    问: /** 给定一个整数数组 nums和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标. 你可以假设每种输入只会对应一个答案.但是,数 ...

  8. 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标

    题目链接:https://leetcode-cn.com/problems/two-sum/solution/liang-shu-zhi-he-by-leetcode-2/ 给定一个整数数组 nums ...

  9. 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,数组中同一个元素不能使用两遍. ...

最新文章

  1. Python,OpenCV中的K近邻(knn K-Nearest Neighbor)及改进版的K近邻
  2. 理解深度学习中的学习率及多种选择策略
  3. oa 中会议推送 实现_诗尼曼:大OA+费控赋能千店一体,打造家居数字化标杆
  4. 正则 禁止连续逗号_正则
  5. JPA休眠替代方案。 如果JPA或Hibernate对于我的项目而言不够好,该怎么办?
  6. 追加画面文言时注意【×硬换行】与【○软换行】
  7. 汇编语言编译文件报 error A2105: Excepted: instruction or directive
  8. 网易云课堂资源合集百度云分享 下载
  9. vmware linux top si高以及网卡队列、软负载相关优化
  10. ubuntu18基本软件安装
  11. 计算机是不是属于文具类,计算器属于学生文具吗?
  12. 各个小组对“躲避小球”游戏的评价
  13. ng test 运行报错SassError: Can‘t find stylesheet to import, 导致case 一个都没有执行
  14. CCLE:肿瘤细胞系百科全书
  15. 关于Oracle 12c ocp认证考试
  16. [Windows 10](Windows 10 解决开机小键盘灯不亮)
  17. 抖音C#版,自己抓第三方抖音网站
  18. 【LOJ6515】贪玩蓝月
  19. ScannerException: while scanning for the next token found character ‘@‘ 问题解决
  20. 目标检测、追踪梳理:帧差法、光流法、背景减除法

热门文章

  1. @程序员,什么键盘最耐用?| 每日趣闻
  2. 【机器学习PAI实战】—— 玩转人工智能之综述
  3. 给定一个n,输出从1到n的整数
  4. init 0-6 (启动级别:init 0,1,2,3,4,5,6)
  5. 转载 一个渣硕iOS春招总结 | 掘金技术征文
  6. 1-PC1有默认网关/Normal-ARP(正常ARP)
  7. WebStorm Git 分支操作
  8. 一致性Hash算法(KetamaHash)的c#实现
  9. 十进制 转换为 二进制
  10. jQuery选择器之动态列表显示Demo