class Solution {
// 思路很简单:二进制1计数 + 重写比较器
// 麻烦的一点是:比较器的参数需要是T,int[]需要包装成Integer[],然后解包装...
public int[] sortByBits(int[] arr) {
Integer[] Arr = Arrays.stream(arr).boxed().toArray(Integer[]::new);
Arrays.sort(Arr, (o1, o2) -> {
int cnt1 = countBitOne(o1);
int cnt2 = countBitOne(o2);
return cnt1 == cnt2 ? o1 - o2 : cnt1 - cnt2;
});
return Arrays.stream(Arr).mapToInt(Integer::intValue).toArray();
}
// 计算二进制表示中1的个数
private int countBitOne(int n){
int cnt = 0;
while (n > 0){
if(n % 2 == 1){
cnt++;
}
n >>= 1;
}
return cnt;
}
}
class Solution {
// 链式编程
public int[] sortByBits(int[] arr) {
Comparator<Integer> myComparator = Comparator.comparingInt(Integer::bitCount).thenComparing(Integer::compare);
return Arrays.stream(arr).boxed().sorted(myComparator).mapToInt(Integer::intValue).toArray();
}
}
class Solution {
/**
*【HashMap + 冒泡排序】
* 这道题的思路其实不难,无非就是自定义排序方式————Python在这方面很擅长
*/
public int[] relativeSortArray(int[] arr1, int[] arr2) {
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < arr2.length; i++) {
map.put(arr2[i], i);
}
for(int i = 0; i < arr1.length - 1; i++){ // 冒泡趟数
for(int j = 0; j < arr1.length - 1 - i; j++){ // 冒泡指针
int n1 = arr1[j];
int n2 = arr1[j + 1];
// 以下分三种情况
if(map.containsKey(n1) && map.containsKey(n2) && map.get(n1) > map.get(n2)){
swap(arr1, j, j + 1);
}else if(!map.containsKey(n1) && map.containsKey(n2)){
swap(arr1, j, j + 1);
}else if(!map.containsKey(n1) && !map.containsKey(n2) && n1 > n2){
swap(arr1, j, j + 1);
}
}
}
return arr1;
}
private void swap(int[] arr, int i, int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
>>> 问题在于......打败了Java的5%.............于是参考评论区高赞,采用了一种特殊的【桶排序】,并追加了优化思路,打败100% :
class Solution {
/**
*【桶排序】其实是使用了桶的思想,但没有使用区间的思想————【计数排序】
*/
public int[] relativeSortArray(int[] arr1, int[] arr2) {
int[] bucket = new int[1001];
// 遍历arr1,把桶填好
for(int n : arr1){
bucket[n]++;
}
// 其实在arr1上原地修改就可以,但是用个res逻辑更清晰
int index = 0;
int[] res = new int[arr1.length];
// 遍历arr2,并依据桶来填res数组
for(int n : arr2){
while (bucket[n] > 0){
res[index++] = n;
bucket[n]--;
}
}
// 遍历桶,把剩下的数追加到res中
for(int i = 0; i < bucket.length; i++){
if(index == res.length){
break;
}
while (bucket[i] > 0){
res[index++] = i;
bucket[i]--;
}
}
return res;
}
}
>>> 其实【桶排序(计数排序)】仍可以优化,因为桶的大小是根据题设得出的1001
>>> 1·桶的大小取数的最大值 + 1
>>> 2·不仅找到最大值,还找出最小值————使用【偏移量】的思想继续缩小桶的大小,偏移量的大小即为min
class Solution {
/**
* 关键思路:
* 1·按身高h降序排序,身高h相同的按k升序排序
* 2·优先排身高高的———为什么呢?因为「后来的矮子,不会破坏已经排好队的高个子的排名的合理性」
* 3·比如(7,0)(6,1)排好了,再排(5,0)直接排在下表0处,整个队列变为(5,0)(7,0)(6,1)————高个子们依旧合理
*/
public int[][] reconstructQueue(int[][] people) {
Arrays.sort(people, ((o1, o2) -> (o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0])));
List<int[]> res = new ArrayList<>();
for(int[] arr : people){
res.add(arr[1], arr);
}
return res.toArray(new int[people.length][2]);
}
}
E
N
D
END
END