按照频率将数组升序排序

标签: 数组 哈希表 排序

难度: Easy

给你一个整数数组 nums ,请你将数组按照每个值的频率 升序 排序。如果有多个值的频率相同,请你按照数值本身将它们 降序 排序。 

请你返回排序后的数组。

 

示例 1:

输入:nums = [1,1,2,2,2,3]
输出:[3,1,1,2,2,2]
解释:'3' 频率为 1,'1' 频率为 2,'2' 频率为 3 。

示例 2:

输入:nums = [2,3,1,3,2]
输出:[1,3,3,2,2]
解释:'2' 和 '3' 频率都为 2 ,所以它们之间按照数值本身降序排序。

示例 3:

输入:nums = [-1,1,-6,4,5,-6,1,4,1]
输出:[5,-1,4,4,-6,-6,1,1,1]

 

提示:

  • 1 <= nums.length <= 100
  • -100 <= nums[i] <= 100

Submission

运行时间: 22 ms

内存: 16.1 MB

class Solution:
    def frequencySort(self, nums: List[int]) -> List[int]:
        cnt = collections.Counter(nums)
        l = []
        for i, j in cnt.items():
            l.append([i,j])
        l.sort(key = lambda x: (x[1], -x[0]))

        res = []
        for i, k in l:
            for _ in range(k):
                res.append(i)
        
        return res

Explain

首先,使用collections.Counter来统计数组nums中每个数值的出现频率,将频率和数值存储为元组列表。然后,根据频率进行升序排序,若频率相同,则按数值降序排序。这通过一个排序函数实现,其中使用lambda函数作为排序键,首先按频率(x[1])升序排序,如果频率相同,则按数值(-x[0])降序排序。排序后,遍历排序结果,按照每个数值的频率将数值按顺序添加到结果列表中。

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

空间复杂度: O(n)

# 定义Solution类

class Solution:
    def frequencySort(self, nums: List[int]) -> List[int]:
        # 使用Counter来计算nums中每个元素的频率
        cnt = collections.Counter(nums)
        l = []
        # 将元素和其频率作为列表存储到l中
        for i, j in cnt.items():
            l.append([i,j])
        # 对列表l进行排序,首先按频率升序,频率相同按元素值降序
        l.sort(key = lambda x: (x[1], -x[0]))

        res = []
        # 根据排序后的频率添加元素到结果列表
        for i, k in l:
            for _ in range(k):
                res.append(i)
        
        return res

Explore

虽然可以直接从Counter对象进行操作,但将频率和数值存储为元组列表是为了更方便地进行自定义排序。Counter对象本身按照元素出现的顺序进行存储,不支持根据频率或元素值来直接排序。通过将数据转换为列表,可以自由地应用自定义的排序规则,尤其是当需要同时根据频率和数值的多重条件进行排序时。此外,列表提供了更灵活的数据操作方式,便于实现复杂的排序逻辑。

这种排序策略确保了首先考虑元素的频率,较少频率的元素在结果数组中出现得更早。当两个元素频率相同时,通过按数值降序排序,可以确保较大的数值先排在前面。这样的排序方法直接符合题目的要求,即按照频率的升序进行排列,如果频率相同,则按照数值的降序进行排列。这保证了结果数组中元素的顺序既按照频率排序又考虑了数值大小的优先级。

在Python中,当使用元组作为排序键时,默认是进行升序排序。为了在频率相同的情况下按数值降序排序,需要对数值取负(`-x[0]`)。这样,原本较大的数值在取负后变得较小,因此在默认的升序排序中会排在后面,实际上达到了降序的效果。使用`-x[0]`是一种简洁有效的方法,避免了编写更复杂的排序函数。

当前的方法通过在循环中重复添加元素来构建结果列表,这在Python中效率较低,尤其是当元素频率较高时。一个更高效的方法是使用列表的`extend`方法,它可以一次性添加多个相同元素。例如,可以使用`res.extend([i] * k)`来替换内层循环,其中`[i] * k`创建了一个包含元素`i`重复`k`次的列表。这样减少了循环的次数并可利用列表操作的内部优化,提高了代码的执行效率。