[*学习新的clone数组的方法] 1331. 数组序号转换

140 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

每日刷题 2022.07.28

题目

  • 给你一个整数数组 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;
};