根据数字二级制表示中1的个数的排序问题

1.根据数字二级制表示中1的个数的排序问题

**题目描述:**给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。

如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。

请你返回排序后的数组。

提示:

  • 1 <= arr.length <= 500
  • 0 <= arr[i] <= 10^4

示例一:

输入:arr = [0,1,2,3,4,5,6,7,8]
输出:[0,1,2,4,8,3,5,6,7]
解释:[0] 是唯一一个有 0 个 1 的数。
[1,2,4,8] 都有 1 个 1 。
[3,5,6] 有 2 个 1 。
[7] 有 3 个 1 。
按照 1 的个数排序得到的结果数组为 [0,1,2,4,8,3,5,6,7]

示例二:

输入:arr = [1024,512,256,128,64,32,16,8,4,2,1]
输出:[1,2,4,8,16,32,64,128,256,512,1024]
解释:数组中所有整数二进制下都只有 1 个 1 ,所以你需要按照数值大小将它们排序。

示例三:

输入:arr = [10000,10000]
输出:[10000,10000]

题解:

这个问题的第一个重点是,统计一下每个数二进制中1的个数,有两种方法:一,暴力解法,不断进行除&于操作:

int count=0;  //统计1的个数
while(x){
    count+=x%2;
    x/=2;
}
//朴素的二进制求法,只需要将每二进制数的每一位进行相加求和,最后就是1的个数

二,递推预处理:定义 bit[i]作为 数字i的二进制数中1的个数,则写出递推式:

bit[i]=b[i>>1]+(i&1)

其中,i>>1是i右移一位,i&1 可以得到i的二进制数的最低为是0 or 1

for (int i = 1;i <= 10000; ++i) {
    bit[i] = bit[i>>1] + (i & 1);
}

可以得到从1到10000所有整数二进制数1的个数。

**在可以求得二进制数1的个数后,**接下来就是排序的问题了,只需要对sort函数改写一下排序规则:

sort(arr.begin(),arr.end(),[&](int x,int y){
   if (bit[x] < bit[y]) {//从小到大
        return true;
    }
   if (bit[x] > bit[y]) {
        return false;
    }
        return x < y;   //当二进制数中1的个数相等时,按他们本身大小升序排序
 });

完整代码:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int get(int x){
        int res = 0;
        while (x) {
            res += (x % 2);
            x /= 2;
        }
        return res;
    }


int main() {
        vector<int> arr;
        int x;
        while (cin>>x)
        {
            arr.push_back(x);
        }
        vector<int> bit(10001, 0);
    //暴力解法
        for (auto x: arr) {//类似迭代器,依次得到arr中的值赋给x
            bit[x] = get(x);
        }
    /*
    //位运算递归
    for (int i = 1;i <= 10000; ++i) {
    bit[i] = bit[i>>1] + (i & 1);
}
    */
    //改写排序规则:
        sort(arr.begin(),arr.end(),[&](int x,int y){
            if (bit[x] < bit[y]) {
                return true;
            }
            if (bit[x] > bit[y]) {
                return false;
            }
            return x < y;
        });
        for(auto p:arr)cout<<p<<" ";
        return 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值