有这样一个场景,n个数字组成的一维数组,如下:
let arr = [11,23,332,24,134,3134,83,665,22,74];
如果要从中选取多个(如3个)最大的数字,如何处理呢?
解题思路
二进制的数据是由0和1来构成的,将每个数字都转换成2进制32位的数字,再切割转换为数组,然后循环数组arr,其中每一项出现数字1的下标较小的,即认为该项数字最大,将该项收集起来,达到选取数量了就停止,再将收集到的数字转为10进制,完成选择。
1.先将arr数组循环,再将数组的每一项由10进制转为2进制32位数,分割后保存。
for(var i=0;i<arr.length;i++){
let resArry = [];
resArry = arr[i].toString(2).split('');
for (let r = resArry.length; r < 32; r++) {
resArry.unshift(0);
}
arr[i] = resArry;
}
数组的每一项如下图:
//定义递归函数处理收集最大值
function digitalsort(e) {
let newarr = [];//用来保存最大值
let oldarr = [];//用来保存未被选为最大值的数字
for (let i = 0; i < arguments[0].length; i++) {
if (arguments[0][i][arguments[1]] == 1) {
newarr.push(arguments[0][i]);
} else {
oldarr.push(arguments[0][i]);
}
}
}
digitalsort(arr,0);
3.通常不会马上有项进入newarr(也就是最大值的集合),因此会遇到arguments[0]的长度和oldarr的长度相等,这时就要将下标游标加1,对比arguments[0]每一项的下一下标,直到下标+1为31,也就是每一项的最大长度。
if ((oldarr.length == arguments[0].length) && arguments[1] <= 30) {
digitalsort(arguments[0], arguments[1] + 1);
}
4.如果某项的下标为1,该项将被最大值集合newarr收集,而我们需要的最大值是3个,newarr数组长度小于3,就要进行递归。
//oldarr为arr中非最大值的集合,下标增加1,同时传入最大值的集合newarr,newarr长度为3之后,
//数组中的项将被处理为10进制并返回
digitalsort(oldarr, arguments[1] + 1, newarr);
5.对于上一步传入的newarr在函数中要做处理,如又找到了新的最大值,需要跟传入的newarr,也就是arguments[2]合并;如果在本次递归中没有找到新的最大值,依旧返回arguments[2]。
let arrlength = 0;//标记传入最大值集合的长度
if (arguments[2] && arguments[2].length > 0) {
arrlength = arguments[2].length;
}
...
//本轮递归收集到的最大值与传入的最大值集合的数量之和小于3
if(newarr.length>0&&(newarr.length < 3 - arrlength)){
if (arguments[1] <= 30) {
if (arrlength > 0) {
for (let i = 0; i < arguments[2].length; i++) {
//将两组合并
newarr.unshift(arguments[2][i]);
}
}
digitalsort(oldarr, arguments[1] + 1, newarr);
}
}
//如本轮递归未收集到最大值,就依旧传递最大值集合进入下一轮递归
if ((oldarr.length == arguments[0].length) && arguments[1] <= 30) {
if (arrlength > 0) {
digitalsort(arguments[0], arguments[1] + 1, arguments[2]);
}else{
digitalsort(arguments[0], arguments[1] + 1);
}
}
6.还有一种情况,在本轮递归中,arr数组每一项的当前下标所对应的值(arguments[0][i][arguments[1]])为1的情况,超过了3个,这时就需要比对arguments[1]+1的情况了。此时只需要传入符合本轮最大值筛选的项的集合就可以了。
if (newarr.length > 3 - arrlength) {
if (arguments[1] <= 30) {
if (arrlength > 0) {
digitalsort(newarr, arguments[1] + 1, arguments[2]);
} else {
digitalsort(newarr, arguments[1] + 1);
}
}
}
7.如果本轮收集的最大值和传入的最大值集合的总和等于3了,将两组集合合并,遍历数组转换为10进制数后,返回结果。
if (newarr.length == 3 - arrlength) {
if (arrlength > 0) {
for (var i = 0; i < arguments[2].length; i++) {
newarr.unshift(arguments[2][i]);
}
}
for (var k = 0; k < newarr.length; k++) {
newarr[k] = parseInt(newarr[k].join(''),2);
}
return newarr;
}
8.结束之后还要来总结一下,其实主要是把数组每个项都转换成2进制的32位数字,然后从高位进行比较,因为2进制只有0和1两个数字,不像十进制有10个数字,有两个数字的好处就是只需要判断是否为1,就能确定当前值是否为最大值,然后收集或者放入待判断的数组oldarr中,最终集齐规定的数量,再将数字转为10进制,返回结果完成。 附上完整代码:
var arr = [11,23,332,24,134,3134,83,665,22,74];
for(var i=0;i<10;i++){
var resArry = [];
resArry = arr[i].toString(2).split('');
for (var r = resArry.length; r < 32; r++) {
resArry.unshift(0);
}
arr[i] = resArry;
}
digitalsort(arr,0);
function digitalsort(e) {
var newarr = [];
var oldarr = [];
var arrlength = 0;
if (arguments[2] && arguments[2].length > 0) {
arrlength = arguments[2].length;
}
for (var i = 0; i < arguments[0].length; i++) {
if (arguments[0][i][arguments[1]] == 1) {
newarr.push(arguments[0][i]);
} else {
oldarr.push(arguments[0][i]);
}
}
if (newarr.length > 3 - arrlength) {
if (arguments[1] <= 30) {
if (arrlength > 0) {
digitalsort(newarr, arguments[1] + 1, arguments[2]);
} else {
digitalsort(newarr, arguments[1] + 1);
}
}
} else if (newarr.length == 3 - arrlength) {
if (arrlength > 0) {
for (var i = 0; i < arguments[2].length; i++) {
newarr.unshift(arguments[2][i]);
}
}
for (var k = 0; k < newarr.length; k++) {
newarr[k] = parseInt(newarr[k].join(''),2);
}
console.log(newarr);
return newarr;
} else if(newarr.length>0&&(newarr.length < 3 - arrlength)){
if (arguments[1] <= 30) {
if (arrlength > 0) {
for (var i = 0; i < arguments[2].length; i++) {
newarr.unshift(arguments[2][i]);
}
}
digitalsort(oldarr, arguments[1] + 1, newarr);
}
}
if ((oldarr.length == arguments[0].length) && arguments[1] <= 30) {
if (arrlength > 0) {
digitalsort(arguments[0], arguments[1] + 1, arguments[2]);
}else{
digitalsort(arguments[0], arguments[1] + 1);
}
}
}