leetcode 2026-02-25 每日一练 - 根据数字二进制下 1 的数目排序

题目描述

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

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

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

请你返回排序后的数组。


解题思路

这道题的核心是自定义排序规则:

  1. 首先统计每个数字二进制表示中 1 的个数
  2. 按照 1 的个数升序排序(个数少的排前面)
  3. 如果 1 的个数相同,则按照数值大小升序排序

Go 语言提供了 bits.OnesCount() 函数来统计二进制中 1 的个数,非常方便。


代码实现

方法一:冒泡排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func sortByBits(arr []int) []int {
n := len(arr)
for i := 0; i < n-1; i++ {
for j := 0; j < n-1-i; j++ {
cntA := bits.OnesCount(uint(arr[j]))
cntB := bits.OnesCount(uint(arr[j+1]))

if cntA > cntB || (cntA == cntB && arr[j] > arr[j+1]) {
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
return arr
}

方法二:标准库排序(推荐)

1
2
3
4
5
6
7
8
9
10
11
func sortByBits(arr []int) []int {
// 使用slices包的SortFunc进行自定义排序
slices.SortFunc(arr, func(a, b int) int {
// cmp.Or:先判断第一个表达式,若不为0则返回,否则返回第二个表达式
return cmp.Or(
bits.OnesCount(uint(a)) - bits.OnesCount(uint(b)), // 优先按1的个数比较
a - b // 个数相同时按数值比较
)
})
return arr
}

核心细节

  1. bits.OnesCount():Go 标准库函数,用于统计无符号整数二进制表示中 1 的个数
  2. 排序条件cntA > cntB || (cntA == cntB && arr[j] > arr[j+1])
    • 如果 1 的个数不同,个数多的排后面
    • 如果 1 的个数相同,数值大的排后面
  3. cmp.Or():Go 1.21+ 新增函数,简化多条件比较逻辑

复杂度分析

方法一(冒泡排序)

  • 时间复杂度O(n² × log(max(arr))),其中 n 是数组长度,log(max(arr)) 是统计 1 个数的时间
  • 空间复杂度O(1),原地排序

方法二(标准库排序)

  • 时间复杂度O(n log n × log(max(arr))),标准库使用快速排序或归并排序
  • 空间复杂度O(log n),排序递归栈空间

总结

这道题考察自定义排序规则的实现:

  • 方法一适合理解排序原理,但效率较低
  • 方法二使用标准库,代码简洁且高效,推荐使用
  • cmp.Or() 是处理多条件排序的优雅方式