【问题标题】:Sort Integers in an array by the number of 1 Bits in each integer按每个整数中 1 位的数量对数组中的整数进行排序
【发布时间】:2020-08-24 09:04:37
【问题描述】:

给定一个整数数组 arr。您必须按二进制表示中 1 的数量对数组中的整数进行升序排序,如果两个或多个整数具有相同数量的 1,则必须按升序对它们进行排序。

返回排序后的数组。

输入:arr = [0,1,2,3,4,5,6,7,8]
输出:[0,1, 2,4,8,3,5,6,7]
解释:[0]是唯一的0位整数。 [1,2,4,8] 都有 1 少量。 [3,5,6] 有 2 位。 [7] 有 3 位。按位排序的数组是 [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 二进制表示中的位,您应该只对它们进行排序 升序。

因此,我在这里使用了 Brian Kernigham 的算法来计算数组中每个整数中 1 的位数。这是我迄今为止编写的代码:-

class Solution {
public:
    vector<int> sortByBits(vector<int>& arr) {
        //firstly sort the input array
        sort(arr.begin(), arr.end());
        
        
        vector<int> count;
        //Using Brian Kernigham's Algorithm
        for(int i =0; i<arr.size(); i++){
            while(arr[i]){
                arr[i] = arr[i] & (arr[i] -1);
                count[i] ++;
            }
        } 
    }
};



但是,我不知道如何组合 count[] 数组和输入数组 arr[] 来获得输出。我曾想过使用 C++ 的 map() STL,但由于函数需要返回 vector&lt;int&gt;,所以我放弃了它。

有人可以提供进一步的解决方案吗?另外,请不要分享任何使用预定义函数builtin_popcount()的代码

【问题讨论】:

  • "请不要分享任何使用预定义函数 builtin_popcount() 的代码" 为什么不呢?这就是你已经拥有的功能,给定一些使用内置函数进行排序的代码,应该可以用你的计数函数替换它
  • std::bitset::count() 也算预定义吗?
  • 顺便说一句,我是 brian kernighaN。
  • 为什么不创建一个比较两个整数值的比较函数,如果第一个比第二个“更小”(位数少)则返回 true,然后将其传递给std::sort用作比较函数?
  • @Someprogrammerdude 因为这样计算位的函数必须被调用超过必要的次数。好吧,这是一种权衡,我选择了一个不同的答案

标签: c++ arrays bit-manipulation bit


【解决方案1】:

最简单(但不是最有效)是将数字和计数一起存储在一个容器中,对其进行排序,然后提取数字:

class Solution {
public:
    vector<int> sortByBits(vector<int>& arr) {
        vector<std::pair<int,int> temp;
        
        for(int i =0; i<arr.size(); i++){
            int count = 0;
            while(arr[i]){
                arr[i] = arr[i] & (arr[i] -1);
                count++;
            }
            temp.emplace_back(count,arr[i]);
        } 
       
        std::sort(temp.begin(),temp.end());   

        // extract the numbers again:
        std::vector<int> numbers;
        // ...
        return numbers;
    }
};

std::sort 不稳定,因此如果您先对数字进行排序,然后再对设置的位数进行排序,则必须使用std::stable_sort。另一方面,std::pair&lt;int,int&gt; 确实有一个operator&lt;,可以与std::sort 一起使用,按照first 排序,然后是second

或者,您可以编写一个比较器,让您对数字进行排序。这不会像上面那样进行所有不必要的复制,但它会调用函数来计算不必要的位数:

class Solution {
public:
    vector<int> sortByBits(vector<int>& arr) {
       std::sort(arr.begin(), arr.end(), [](int a,int b) {
               // count bits here
               auto n_bits_a = count_bits(a);
               auto n_bits_b = count_bits(b);
               if (n_bits_a == n_bits_b) return a < b;
               return n_bits_a < n_bits_b; });
        return arr;
    }
};

如果我们再次使用std::pair&lt;int,int&gt; 已经具有所需顺序的事实,则比较器可以写得更紧凑:

std::sort(arr.begin(), arr.end(), [](int a,int b) {
    auto proj = [](int x) { return std::pair<int,int>{ count_bits(x),x}; };
    return proj(a) < proj(b);
});  

不完全清楚,为什么函数通过引用获取向量返回一个向量。上面还对参数进行了排序。

【讨论】:

  • 可能是[](int lhs, int rhs) {return std::pair{count_bits(lhs), lhs} &lt; std::pair{count_bits(rhs), rhs};}。 (有些人写错了使比较器无效的 if 条件)。
  • @Jarod42 是的,我考虑过,但认为冗长的 OP 会更容易。反正我现在加了
  • 我个人必须阅读两次冗长的版本。我什至更喜欢带有 projection 的范围版本,因此,在比较器内部(当我们没有范围时):auto proj = [](int i){ return std::pair{count_bits(i), i}; }; return proj(lhs) &lt; proj(rhs);。 (范围:ranges::sort(arr, std::less&lt;&gt;{}, [](int i){ return std::pair{count_bits(i), i}; }))。
  • @Jarod42 我喜欢这个投影并偷了它作为答案,但我对ranges 不够流利,无法将其包含在我的答案中
【解决方案2】:

这是一个使用std::bitset 的解决方案,它使处理位更容易。 std::bitset 有一个 count() 函数,它返回设置为 1 的位数,您可以在您提供的比较器函数中使用它std::sort()

#include <bitset>
#include <algorithm>
#include <vector>

class Solution {
public:
    std::vector<int> sortByBits(std::vector<int>& arr) {
        std::vector<int> vec = arr;

        std::sort(vec.begin(), vec.end(),
            [](int a, int b) { 
                std::bitset<32> ba(a);
                std::bitset<32> bb(b);
                if (ba.count() == bb.count())
                    return a < b;
                else
                    return ba.count() < bb.count();
            });

        return vec;
    }
    
};

这是Demo

【讨论】:

  • 与 idclev-463035818 的备注相同,比较对/元组避免了一些潜在问题(尤其是对于初学者)。
猜你喜欢
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 2020-04-18
  • 1970-01-01
  • 1970-01-01
  • 2011-09-03
  • 2023-03-26
  • 1970-01-01
相关资源
最近更新 更多