[LeetCode] 1356. Sort Integers by The Number of 1 Bits 根据数字二进制下1 的数目排序

发布时间 2023-10-22 01:14:00作者: Grandyang

You are given an integer array arr. Sort the integers in the array in ascending order by the number of 1's in their binary representation and in case of two or more integers have the same number of 1's you have to sort them in ascending order.

Return the array after sorting it.

Example 1:

Input: arr = [0,1,2,3,4,5,6,7,8]
Output: [0,1,2,4,8,3,5,6,7]
Explantion: [0] is the only integer with 0 bits.
[1,2,4,8] all have 1 bit.
[3,5,6] have 2 bits.
[7] has 3 bits.
The sorted array by bits is [0,1,2,4,8,3,5,6,7]

Example 2:

Input: arr = [1024,512,256,128,64,32,16,8,4,2,1]
Output: [1,2,4,8,16,32,64,128,256,512,1024]
Explantion: All integers have 1 bit in the binary representation, you should just sort them in ascending order.

Constraints:

  • 1 <= arr.length <= 500
  • 0 <= arr[i] <= 104

这道题给了一个数组 arr,让我们给数组中的数字排序,按照数字的二进制表示中的1的个数从少到多排序,如果1的个数相同,则按照数字从小到大排。其实主要就是考察了一个求数字的二进制表示中的1的个数,计算方法是用个 while 循环,每次通过'与'上1来得到最低位上的数字,如果得到1,则计数器自增1,然后将数字向右平移一位。知道了如何统计1的个数,这道题就没啥难度了,这里博主最开始的做法是将统计的个数和原数字本身组成一个数对儿,放入到一个新的数组中,然后对这个新数字进行自定义排序,排序的方法是首先按1的个数从小到大排,若个数相等,则按原数字从小到大排。最后只需要按顺序从排序后的数组中提取原数字加入到结果 res 中即可,参见代码如下:


解法一:

class Solution {
public:
    vector<int> sortByBits(vector<int>& arr) {
        vector<int> res;
        vector<vector<int>> nums;
        for (int num : arr) {
            int cnt = 0, d = num;
            while (d > 0) {
                cnt += d & 1;
                d >>= 1;
            }
            nums.push_back({cnt, num});
        }
        sort(nums.begin(), nums.end(), [](vector<int> &a, vector<int> &b) {
            return a[0] < b[0] || (a[0] == b[0] && a[1] < b[1]);
        });
        for (auto &a : nums) {
            res.push_back(a[1]);
        }
        return res;
    }
};

再来看一种写法,这里就主要是把自定义排序方式,和统计1的个数都拆分成了单独的子函数,还有就是统计1的个数的时候和前面的解法稍有些不同。这里采用的是 num & (num - 1),这个操作实际上是快速移除右起第一个1的方法,可以举个例子来看,比如 101 & 100 = 100 这里的 101 就变成了 100,最右边的1被移除了。或者 1100 & 1011 = 1000,1100 变成了 1000,右起第一个1被移除了,这样的话每次操作必定会移除一个1,则计算器可以自增1,循环退出条件也是当数字变为0了退出。这样计算的效率能比之前一位一位检查的高一些,参见代码如下:


解法二:

class Solution {
public:
    vector<int> sortByBits(vector<int>& arr) {
        sort(arr.begin(), arr.end(), compare);
        return arr;
    }
    static bool compare(int a, int b) {
        int cntA = cntOne(a), cntB = cntOne(b);
        return cntA == cntB ? (a < b) : (cntA < cntB);
    }
    static int cntOne(int num) {
        int cnt = 0;
        while (num > 0) {
            num = num & (num - 1);
            ++cnt;
        }
        return cnt;
    }
};

再来看一种利用 C++ 自带统计1的个数的方法,用到了 __builtin_popcount 这个函数,当然如果面试中你这么玩的话,估计过不了,只是放上来秀一下而已,大家还是老老实实用前面的解法吧,参见代码如下:


解法三:

class Solution {
public:
    vector<int> sortByBits(vector<int>& arr) {
        sort(arr.begin(), arr.end(), [](int &a, int &b) {
            int cntA = __builtin_popcount(a), cntB = __builtin_popcount(b);
            return cntA == cntB ? (a < b) : (cntA < cntB);
        });
        return arr;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1355


类似题目:

Find Subsequence of Length K With the Largest Sum


参考资料:

https://leetcode.com/problems/sort-integers-by-the-number-of-1-bits/

https://leetcode.com/problems/sort-integers-by-the-number-of-1-bits/solutions/758095/cpp-simple-solution-using-self-defined-comparator/

https://leetcode.com/problems/sort-integers-by-the-number-of-1-bits/solutions/517017/c-in-place-sort-popcount/


LeetCode All in One 题目讲解汇总(持续更新中...)