剑指 Offer II 075. 数组相对排序(1122. 数组的相对排序)

题目:

 

思路:

【1】其实最简单的便是计数排序,先将全部按照map进行映射,然后根据第二个数组的顺序先塞,最后的把剩下的再塞进去。

【2】当然还有一种自定义排序的方式,只能说有点秀。

由于数组arr2​ 规定了比较顺序,因此我们可以使用哈希表对该顺序进行映射:
即对于数组 arr2 中的第 i 个元素,我们将 (arr2[i],i)这一键值对放入哈希表 rank 中,就可以很方便地对数组 arr1 中的元素进行比较。

比较函数的写法有很多种,例如我们可以使用最基础的比较方法,对于元素 x 和 y:
    如果 x 和 y 都出现在哈希表中,那么比较它们对应的值 rank[x] 和 rank[y];
    如果 x 和 y 都没有出现在哈希表中,那么比较它们本身;
    对于剩余的情况,出现在哈希表中的那个元素较小。

 

 

 

代码展示:

自定义排序的方式:

//时间3 ms击败29.66%
//内存41.8 MB击败5.77%
class Solution {
    public int[] relativeSortArray(int[] arr1, int[] arr2) {
        Map<Integer, Integer> map = new HashMap<>();
        List<Integer> list = new ArrayList<>();
        for(int num : arr1) list.add(num);
        for(int i = 0; i < arr2.length; i++) map.put(arr2[i], i);
        Collections.sort(list, (x, y) -> {
            if(map.containsKey(x) || map.containsKey(y)) return map.getOrDefault(x, 1001) - map.getOrDefault(y, 1001);
            return x - y;
        });
        for(int i = 0; i < arr1.length; i++) arr1[i] = list.get(i);
        return arr1;
    }
}

//大佬使用流的方式,实现的自定义排序,流这个特性貌似在JAVA8中就已经开始了,充分利用CPU。
//但是貌似写的人很少,可以学习一下
//时间7 ms击败6.13%
//内存41.5 MB击败23.5%
class Solution {
    public int[] relativeSortArray(int[] arr1, int[] arr2) {
        Map<Integer,Integer> numPostions = IntStream.range(0,arr2.length).boxed().collect(Collectors.toMap(i->arr2[i],i->i));
        return  Arrays.stream(arr1).boxed().sorted((o1, o2) -> {
            int a1 = numPostions.getOrDefault(o1, 1001);
            int a2 = numPostions.getOrDefault(o2, 1001);
            if (a1 != 1001 || a2 != 1001) {
                return a1 - a2;
            }

            return o1 - o2;
        }).mapToInt(o->o).toArray();
    }
}

 

计数排序的方式:

//时间0 ms击败100%
//内存40.3 MB击败53.73%
//时间复杂度:O(n),因为是遍历三次,其中最大的就是arr1的长度,也就是最多3n次(关键是其他的都不大于n)。
//空间复杂度:O(n),因为根据题目才设定了固定的数组长度,如果没有规定的话其实这个空间是n,因为不确定。
class Solution {
    public int[] relativeSortArray(int[] arr1, int[] arr2) {
        int[] map = new int[1001];
        int[] res = new int[arr1.length];
        int index = 0;
        //遍历数组1,将数组1中元素出现次数记录到map数组
        for(int i: arr1) {
            map[i]++;
        }
        //遍历数组2,将数组2中元素按照数组1中出现次数添加到res数组
        for(int j: arr2) {
            while (map[j]-- > 0 ) {
                res[index++] = j;
            }
        }
        //剩下的是数组1中剩下的元素,按照顺序依次添加到res数组中
        for(int k = 0; k < 1001; k++) {
            while(map[k]-- > 0) {
                res[index++] = k;
            }
        }
        return res;
    }
}

 

posted @ 2023-03-01 12:30  忧愁的chafry  阅读(13)  评论(0编辑  收藏  举报