排序题目:数组序号转换

题目

标题和出处

标题:数组序号转换

出处:1331. 数组序号转换

难度

3 级

题目描述

要求

给定一个整数数组 arr \texttt{arr} arr,将数组中的每个元素替换为它们的序号。

序号代表了一个元素的大小。序号编号的规则如下:

  • 序号从 1 \texttt{1} 1 开始编号。
  • 一个元素越大,那么序号越大。如果两个元素相等,那么它们的序号相同。
  • 每个数字的序号都应该尽可能地小。

示例

示例 1:

输入: arr   =   [40,10,20,30] \texttt{arr = [40,10,20,30]} arr = [40,10,20,30]
输出: [4,1,2,3] \texttt{[4,1,2,3]} [4,1,2,3]
解释: 40 \texttt{40} 40 是最大的元素。 10 \texttt{10} 10 是最小的元素。 20 \texttt{20} 20 是第二小的数字。 30 \texttt{30} 30 是第三小的数字。

示例 2:

输入: arr   =   [100,100,100] \texttt{arr = [100,100,100]} arr = [100,100,100]
输出: [1,1,1] \texttt{[1,1,1]} [1,1,1]
解释:相等的元素有相同的序号。

示例 3:

输入: arr   =   [37,12,28,9,100,56,80,5,12] \texttt{arr = [37,12,28,9,100,56,80,5,12]} arr = [37,12,28,9,100,56,80,5,12]
输出: [5,3,4,2,8,6,7,1,3] \texttt{[5,3,4,2,8,6,7,1,3]} [5,3,4,2,8,6,7,1,3]

数据范围

  • 0 ≤ arr.length ≤ 10 5 \texttt{0} \le \texttt{arr.length} \le \texttt{10}^\texttt{5} 0arr.length105
  • -10 9 ≤ arr[i] ≤ 10 9 \texttt{-10}^\texttt{9} \le \texttt{arr[i]} \le \texttt{10}^\texttt{9} -109arr[i]109

解法

思路和算法

为了得到数组元素的序号,并按照原数组将每个元素替换成序号,需要复制原数组并对复制后的数组升序排序,根据排序后的数组得到每个元素对应的序号。

对于已经排序的数组,遍历数组元素的顺序是单调递增顺序(非严格)。由于相等元素的序号相同,每个数字的需要应该尽可能小,因此遍历排序后的数组的过程中,计算元素对应的序号的做法是:遇到相等元素则序号不变,遇到不相等的元素则序号加 1 1 1。该做法可以确保不相等的元素的序号一定不同,且每个元素的序号最小。

使用哈希表记录每个元素对应的序号。序号的初始值是 1 1 1,表示最小元素的序号是 1 1 1。对于遍历到的每个元素,执行如下操作:

  • 如果当前元素尚未存入哈希表,则将当前元素与当前序号存入哈希表,然后将序号加 1 1 1,更新后的序号为下一个更大的元素的序号;

  • 如果当前元素已经存入哈希表,则跳过当前元素。

遍历结束之后即可得到每个元素对应的序号。创建结果数组,将原数组中的每个元素对应的序号填入结果数组,最后返回结果数组。

代码

class Solution {
    public int[] arrayRankTransform(int[] arr) {
        int length = arr.length;
        int[] sorted = new int[length];
        System.arraycopy(arr, 0, sorted, 0, length);
        Arrays.sort(sorted);
        Map<Integer, Integer> rankMap = new HashMap<Integer, Integer>();
        for (int i = 0, rank = 1; i < length; i++) {
            int num = sorted[i];
            if (!rankMap.containsKey(num)) {
                rankMap.put(num, rank);
                rank++;
            }
        }
        int[] ranks = new int[length];
        for (int i = 0; i < length; i++) {
            ranks[i] = rankMap.get(arr[i]);
        }
        return ranks;
    }
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是数组 arr \textit{arr} arr 的长度。需要 O ( n ) O(n) O(n) 的时间将数组 arr \textit{arr} arr 中的元素复制到数组 sorted \textit{sorted} sorted 中,对数组 sorted \textit{sorted} sorted 排序需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间,遍历数组 sorted \textit{sorted} sorted 得到每个元素对应的序号和将序号填入结果数组都需要 O ( n ) O(n) O(n) 的时间,总时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 arr \textit{arr} arr 的长度。数组 sorted \textit{sorted} sorted 和哈希表需要 O ( n ) O(n) O(n) 的空间,对数组 sorted \textit{sorted} sorted 排序需要 O ( log ⁡ n ) O(\log n) O(logn) 的递归调用栈空间,空间复杂度是 O ( n ) O(n) O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值