Problem
Given two arrays arr1
and arr2
, the elements of arr2
are distinct, and all elements in arr2
are also in arr1
.
Sort the elements of arr1
such that the relative ordering of items in arr1
are the same as in arr2
. Elements that do not appear in arr2
should be placed at the end of arr1
in ascending order.
Examples
Example 1:
Input: arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
Output: [2,2,2,1,4,3,3,9,6,7,19]
Example 2:
Input: arr1 = [28,6,22,8,44,17], arr2 = [22,28,8,6]
Output: [22,28,8,6,17,44]
Constraints
1 <= arr1.length, arr2.length <= 1000
0 <= arr1[i], arr2[i] <= 1000
- All the elements of
arr2
are distinct. - Each
arr2[i]
is inarr1
.
Solution
We can either use map
+ sorting
, or TreeMap
OR map
+ heap
or bucket to sort this problem. Here is the video explanation:
Method 1 - Using Map and Sorting
- We can use
counts
as frequency map onarr1
. - Then, we loop on
arr2
, and if key is present incounts
, we append to thepresent
list forvalue
number of times - Then, we check
arr2
andcounts
map to find the keys that don’t exist inarr2
and append themvalue
number of times tonotPresent
list - Then, we sort
notPresent
list - Finally, we append
notPresent
list topresent
list and that is our answer.
Code
Java
class Solution {
public int[] relativeSortArray(int[] arr1, int[] arr2) {
Map<Integer, Long> counts = Arrays.stream(arr1).boxed().collect(
Collectors.groupingBy(
Function.identity(),
HashMap::new, // can be skipped
Collectors.counting()
)
);
Set<Integer> set = Arrays.stream(arr2).boxed().collect(Collectors.toSet());
List<Integer> present = new ArrayList<>();
for (int num : arr2) {
long count = counts.get(num);
for (int i = 0; i < count; i++) {
present.add(num);
}
}
List<Integer> notPresent = new ArrayList<>();
for (int k : counts.keySet()) {
if (!set.contains(k)) {
long count = counts.get(k);
for (int i = 0; i < count; i++) {
notPresent.add(k);
}
}
}
notPresent.sort(Comparator.comparingInt(o -> o));
int n = present.size();
int m = notPresent.size();
int[] ans = new int[present.size() + notPresent.size()];
IntStream.range(0, n).forEach(i -> {
ans[i] = present.get(i);
});
IntStream.range(0, m).forEach(i -> {
ans[i + n] = notPresent.get(i);
});
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(n log n)
- 🧺 Space complexity:
O(n)
Method 2 - Using Bucketsort with array
- Because
0 <= arr1[i], arr2[i] <= 1000
, we use an array to count every element, lets call itcnt
. - Now, we don’t need
arr1
, we can actually fill the sorted array in place. So, we will go througharr2
, from left to right. When, we find frequency of it incnt
, we fill it inarr1
. - Now, we fill in remaining elements in cnt, which are not yet encountered.
Code
Java
class Solution {
public int[] relativeSortArray(int[] arr1, int[] arr2) {
int[] cnt = new int[1001];
for(int num : arr1) {
cnt[num]++;
}
int i = 0;
for(int num : arr2) {
while(cnt[num]-- > 0) {
arr1[i++] = num;
}
}
for(int num = 0; num < cnt.length; num++) {
while(cnt[num]-- > 0) {
arr1[i++] = num;
}
}
return arr1;
}
}
Complexity
- ⏰ Time complexity:
O(n)
- 🧺 Space complexity:
O(n)
for using the count array