携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
每日刷题 2022.07.28
- leetcode原题链接:leetcode.cn/problems/ra…
- 难度:简单
- 方法:模拟
题目
- 给你一个整数数组 arr ,请你将数组中的每个元素替换为它们排序后的序号。
- 序号代表了一个元素有多大。序号编号的规则如下:
- 序号从 1 开始编号。
- 一个元素越大,那么序号越大。如果两个元素相等,那么它们的序号相同。
- 每个数字的序号都应该尽可能地小。
示例
- 示例1
输入:arr = [40,10,20,30]
输出:[4,1,2,3]
解释:40 是最大的元素。 10 是最小的元素。 20 是第二小的数字。 30 是第三小的数字。
- 示例2
输入: arr = [100,100,100]
输出: [1,1,1]
解释: 所有元素有相同的序号。
- 示例3
输入: arr = [37,12,28,9,100,56,80,5,12]
输出: [5,3,4,2,8,6,7,1,3]
提示
0 <= arr.length <= 10^5-10^9 <= arr[i] <= 10^9
解题思路
- 根据题意可知:需要将数组
arr中的元素,对应的序号输出。- 序号需要保证尽可能的小(转换说法 =》 那么序号需要先排列小的,从小到大依次排列上来,保证
arr数组中的每个元素所对应的序号尽可能的小) - 元素越大,序号越大(转换说法 =》
arr数组中的元素的数值越大,那么所对应的序号就越大) - 序号从1开始编号(转换说法 =》 打消了之前常规的序列号从0开始计算,题目中要求的是从1开始)
- 序号需要保证尽可能的小(转换说法 =》 那么序号需要先排列小的,从小到大依次排列上来,保证
- 分析完成后,来想想如何实现?
- 为什么需要拷贝一份,不改变原数组
arr中的元素位置呢?因为最终需要输出原数组arr中对应的序列号。 - 将原数组
arr拷贝一份到新的数组a中,对a数组进行升序排序。那么此时就可以将序列按照a数组中的元素依次分发(注:重复的数值需要保证一样的序号) - 分发的时候使用
map来记录,每一个元素的值所对应的序列号 - 创建一个新的存储序号
ans的数组,最后遍历原数组arr,从map中取出arr数组中的数值对应的序列号,并将其存放在ans数组中 - 最终,返回序列号数组
ans即可
- 为什么需要拷贝一份,不改变原数组
优化(针对数组的clone)
- 使用下述两种方法都可以将原本的数组拷贝一份,给新的数组。但是方法一,拷贝后的数组中的元素会变成字符串,和原
arr数组中的元素不同。方法二很好的解决了这个问题,并且再一次让我学习到了sort()函数不仅仅只能给数组排序,还可以给其他更多的类型的元素进行排序。 - 方法一:存在问题,因为是将数组中的元素拼接成一个字符串,再分割成数组的,因此最终得到的数组中的每一个元素都是字符串,并不是
Number类型。
let a = arr.join(' ').split(' ');
- 方法二:使用解构运算符实现数组的拷贝,操作拷贝后的数组,不会影响到原数组
let a = [...arr]
AC代码
/**
* @param {number[]} arr
* @return {number[]}
*/
var arrayRankTransform = function(arr) {
// 将数组中的元素从小到大进行排序
// 将数值和对应的序列号存储在map集合中
// let a = arr.join(' ').split(' ');
// a.sort((a, b) => a - b)
const a = [...new Set(arr)].sort((a,b)=>a-b);
// console.log(a)
console.log(a, arr)
let idx = 1, map = new Map();
for(let one of a) {
let cur = Number(one);
if(!map.has(cur)) {
map.set(cur, idx++);
}
}
// console.log(map)
let ans = [];
for(let one of arr) {
ans.push(map.get(one));
}
return ans;
};