根据数字二进制下 1 的数目排序

标签: 位运算 数组 计数 排序

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

示例 3:

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

示例 4:

输入:arr = [2,3,5,7,11,13,17,19]
输出:[2,3,5,17,7,11,13,19]

示例 5:

输入:arr = [10,100,1000,10000]
输出:[10,100,10000,1000]

提示:

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

Submission

运行时间: 29 ms

内存: 16.2 MB

class Solution:
    def sortByBits(self, arr: List[int]) -> List[int]:
        arr.sort(key=lambda x:(bin(x).count("1"), x))
        return arr

Explain

解题思路是首先按照数组中元素的二进制表示中1的个数进行排序,如果1的个数相同,则按照元素的自然数值进行排序。使用Python的排序函数sort,通过一个lambda函数作为key,其中bin(x).count('1')计算x的二进制表示中1的个数,x则是原始数值,这样可以实现先按1的个数,再按数值大小进行排序。

时间复杂度: O(n log(n) log(max(arr)))

空间复杂度: O(log(n))

class Solution:
    def sortByBits(self, arr: List[int]) -> List[int]:
        # 使用sort函数,key由lambda函数指定,包含两个排序标准:
        # 1. 二进制中1的数量
        # 2. 原始数值大小
        arr.sort(key=lambda x: (bin(x).count('1'), x))
        # 返回排序后的数组
        return arr

Explore

选择使用`bin(x).count('1')`来计算二进制中1的数量是因为这种方法简单直观,易于理解和实现。`bin(x)`函数将整数x转换为其二进制表示的字符串,然后使用字符串的`count('1')`方法计算其中1的数量。尽管这种方法效率较高,但还有其他方法可以计算二进制中1的数量,例如位操作技术。一种常用的位操作方法是使用Brian Kernighan算法,该算法通过不断清除最低位的1直到数字变为0来计数,每次操作可以直接移除最低位的1,这通常比转换为字符串更快。

在排序时,通过使用一个元组`(bin(x).count('1'), x)`作为排序的关键字可以保证这一点。在Python中,当排序关键字是元组时,首先会根据元组的第一个元素进行排序,如果第一个元素相同,则会根据第二个元素进行排序。这样,在二进制中1的数量相同的情况下,就会自动按照原始数值的大小进行排序。

Python的sort函数是稳定的,这意味着如果两个元素具有相同的排序关键字,它们在排序后的数组中将保持原始顺序。对于本题目,这表明如果两个数字在二进制中1的数量和数值大小都相同,它们在排序后的顺序将与它们在原数组中的顺序相同。这种稳定性是有益的,因为它保持了元素之间的相对顺序,这对于某些应用场合可能是需要的。尽管本题中的第二排序标准保证了数值的唯一性,使得原始顺序的保持不是必须的,但稳定性在处理复杂数据结构时仍然是一个有价值的特性。