Easy

题目描述

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

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

请你返回排序后的数组。

示例 1:

输入: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]

示例 2:

输入: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 ,所以你需要按照数值大小将它们排序。

约束条件:

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

解题思路

这道题的核心是按照两个条件进行排序:

  1. 首先按照数字二进制表示中1的个数升序排列
  2. 如果1的个数相同,则按照数值大小升序排列

解决思路:

方法一:自定义排序(推荐)

  • 使用内置的排序函数,自定义比较器
  • 比较器逻辑:先比较二进制中1的个数,相同则比较数值大小
  • 计算二进制中1的个数可以使用位运算或内置函数

方法二:预处理+排序

  • 先遍历数组,计算每个数字的1的个数
  • 将(数值, 1的个数)配对存储
  • 按照规则排序后提取数值

对于计算二进制中1的个数,有多种方法:

  • 使用 __builtin_popcount() (C++)、bin(x).count('1') (Python) 等内置函数
  • 使用位运算:n & (n-1) 可以消除最低位的1
  • 逐位检查:不断右移并检查最低位

时间复杂度主要由排序决定,为O(n log n)。

代码实现

class Solution {
public:
    vector<int> sortByBits(vector<int>& arr) {
        sort(arr.begin(), arr.end(), [](int a, int b) {
            int countA = __builtin_popcount(a);
            int countB = __builtin_popcount(b);
            if (countA == countB) {
                return a < b;
            }
            return countA < countB;
        });
        return arr;
    }
};
class Solution:
    def sortByBits(self, arr: List[int]) -> List[int]:
        return sorted(arr, key=lambda x: (bin(x).count('1'), x))
public class Solution {
    public int[] SortByBits(int[] arr) {
        Array.Sort(arr, (a, b) => {
            int countA = CountBits(a);
            int countB = CountBits(b);
            if (countA == countB) {
                return a.CompareTo(b);
            }
            return countA.CompareTo(countB);
        });
        return arr;
    }
    
    private int CountBits(int n) {
        int count = 0;
        while (n > 0) {
            count += n & 1;
            n >>= 1;
        }
        return count;
    }
}
var sortByBits = function(arr) {
    const countBits = (n) => {
        let count = 0;
        while (n > 0) {
            count += n & 1;
            n >>= 1;
        }
        return count;
    };
    
    return arr.sort((a, b) => {
        const bitsA = countBits(a);
        const bitsB = countBits(b);
        return bitsA === bitsB ? a - b : bitsA - bitsB;
    });
};

复杂度分析

复杂度类型复杂度说明
时间复杂度O(n log n)排序的时间复杂度,其中计算每个数字的1的个数为O(log k),k为数字的最大值
空间复杂度O(1)原地排序,只使用常数额外空间(不考虑排序算法本身的栈空间)

相关题目