题目
链接:https://leetcode-cn.com/problems/relative-sort-array
给你两个数组,arr1
和 arr2
,
arr2
中的元素各不相同
arr2
中的每个元素都出现在 arr1
中
对 arr1
中的元素进行排序,使 arr1
中项的相对顺序和 arr2
中的相对顺序相同。未在 arr2
中出现过的元素需要按照升序放在 arr1
的末尾。
示例:
输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
输出:[2,2,2,1,4,3,3,9,6,7,19]
提示:
arr1.length, arr2.length <= 1000
0 <= arr1[i], arr2[i] <= 1000
arr2 中的元素 arr2[i] 各不相同
arr2 中的每个元素 arr2[i] 都出现在 arr1 中
自定义排序
思路:
由于要按照arr2
中的顺序排序,因此可以先将arr2[i]与i
的映射map
,然后遍历数组arr1
:
- 如果比较的值x, y都出现在
map
中则根据x,y在map
中对应的下标进行排序 - 如果x,y都不在
map
中则小的排前面 - 除了以上两种情况,存在于
map
中的值更小
class Solution {
public int[] relativeSortArray(int[] arr1, int[] arr2) {
Map<Integer, Integer> map = new HashMap<>();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < arr2.length; i++) {
map.put(arr2[i], i);
}
for (Integer num : arr1) list.add(num);
Collections.sort(list, new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
if (map.containsKey(o1) && map.containsKey(o2)) {
return map.get(o1) - map.get(o2);
} else if (!map.containsKey(o1) && !map.containsKey(o2)) {
return o1 - o2;
} else if (map.containsKey(o1)) {
return -1;
} else {
return 1;
}
}
});
for (int i = 0; i < arr1.length; i++) {
arr1[i] = list.get(i);
}
return arr1;
}
}
将上面逻辑优化后的版本:
class Solution {
public int[] relativeSortArray(int[] arr1, int[] arr2) {
Map<Integer, Integer> map = new HashMap<>();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < arr2.length; i++) {
map.put(arr2[i], i);
}
for (Integer num : arr1) list.add(num);
Collections.sort(list, new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
if (map.containsKey(o1) || map.containsKey(o2)) {
return map.getOrDefault(o1, 1001) - map.getOrDefault(o2, 1001);
}
return o1 - o2;
}
});
for (int i = 0; i < arr1.length; i++) {
arr1[i] = list.get(i);
}
return arr1;
}
}
计数排序
思路:
由提示可知,arr1中的元素范围为[0,1000]
并不是很大因此可以使用计数排序,为了优化空间复杂度可以找到arr1
中的最大值upper
与最小值lower
,将arr1
中的元素映射到长度为upper - lower + 1
的freq
数组下标,arr1
中每个元素对应的位置为arr1[i] - lower
因此可以对arr1
中每个元素进行计数。
创建一个与arr1
等长的数组ans
,遍历arr2
,将freq
对应的出现次数的元素加入ans
中,此时arr1
中的每个arr2
的元素已经排序完成,后一步就是按照再按照从左往右的顺序遍历一遍freq
数组将其下标对应的元素i + lower
按照剩余的次数加入ans
数组中。
class Solution {
public int[] relativeSortArray(int[] arr1, int[] arr2) {
if (arr1.length == 0)
return new int[]{};
// 找到最大值与最小值
int upper = 0;
int lower = 1000;
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] > upper) {
upper = arr1[i];
}
if (lower > arr1[i]){
lower = arr1[i];
}
}
// 统计频率
int[] freq = new int[upper - lower + 1];
for (int i = 0; i < arr1.length; i++) {
freq[arr1[i] - lower]++;
}
// 按照频率加入答案
int[] ans = new int[arr1.length];
int index = 0;
for (int i = 0; i < arr2.length; i++) {
while (freq[arr2[i] - lower]-- > 0) {
ans[index++] = arr2[i];
}
}
// 再次遍历,按照频率加入答案
for (int i = 0; i < freq.length; i++) {
while (freq[i]-- > 0) {
ans[index++] = i + lower;
}
}
return ans;
}
}