前言
这是一道简单题,我们可以很快地想到一种解决思路。我想记录下这道题是因为,它为自定义排序中的比较函数树立了典范(言重了→_→)。
总而言之,尤其是对C语言用户,排序的比较函数设计真至关重要,我是python用多了不怎么设计sort中的key,所以猛一下看到这个自定义函数还是很震撼的(⊙ˍ⊙)…
一、题目描述
原题链接
题目的意思也比较明确了,就是对数组
a
r
r
1
arr1
arr1有特殊要求的排序。注意它给定了数组中每个值的取值区间,因此可以考虑计数排序。
题解参考官方题解 链接。
二、使用哈希表(计数排序)/字典
1.思路
利用计数排序思想,我们要构建一个用于统计各元素出现次数的数组 f r e q u e n c y frequency frequency,数组长度要由元素可能的取值范围决定,本题已说明 0 ≤ a r r 1 [ i ] ≤ 1000 0\le arr1[i] \le 1000 0≤arr1[i]≤1000,因此计数数组的长度设为1001。接下来开始它的表演:
- 遍历 a r r 1 arr1 arr1,统计其中每种元素出现的次数,即 f r e q u e n c y [ i ] frequency[i] frequency[i]表示 a r r 1 arr1 arr1中 i i i出现的次数;
- 遍历 a r r 2 arr2 arr2,设当前遍历到的数字是 i i i,将 f r e n q u e n c e [ i ] frenquence[i] frenquence[i]个 i i i添加到排序后的新数组中,并把 f r e n q u e n c e [ i ] frenquence[i] frenquence[i]清零;
- 最后处理 a r r 2 arr2 arr2之外的元素。遍历 f r e n q u e n c e frenquence frenquence中不为零的值,将它们添加到新数组中。
完成!
我通常使用python,因此对字典更熟悉一些,在这里使用字典代替计数数组。基本操作都一样,不过在第3步时,需要先对字典的key进行sorted排序。因为字典中的key是按插入先后排的,而我们需要它按大小顺序排。
2.完整代码(python)
代码如下(示例):
class Solution:
def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
dic = defaultdict(int)
for num in arr1:
dic[num] += 1
res = []
for num in arr2:
res += [num for _ in range(dic[num])]
for k in sorted(list(dic.keys())):
if k not in arr2:
res += [k for _ in range(dic[k])]
return res
看起来也很简练哦~
三、自定义比较函数
1.思路
现在我们使用元素比较的方法对数组进行排序,需要自定义比较函数。首先,我们要搞清楚排序的原则是什么,才能设计比较函数。
在本题中,要求对 a r r 1 arr1 arr1中的元素先按在 a r r 2 arr2 arr2中的出现顺序排序,剩下的元素再按照大小升序排列。我们可以获得两个比较要素:元素在 a r r 2 arr2 arr2中的出现顺序,即下标大小(主要);和元素本身大小(次要)。
对于两个 a r r 1 arr1 arr1中的元素 a , b a,b a,b来说,它们有三种比较、排序情况:
- a , b a,b a,b都在 a r r 2 arr2 arr2中出现,那么直接按照下标排,谁的下标大谁排后面;
- a , b a,b a,b中有一个在 a r r 2 arr2 arr2中出现,那么出现在 a r r 2 arr2 arr2中的元素排在前面,另一个元素排在后面;
- a , b a,b a,b都不在 a r r 2 arr2 arr2中,直接按照元素大小排序,谁大排后面。
这样捋一遍后,比较函数的设计就明了了,下面我们用C语言实现cmp函数。对cmp函数的用法有疑问的小伙伴可以参考这篇博文哦:qsort函数。
可以照着前面的思路,大概过一下代码(里面有自定义函数,可以直接看完整代码):
int cmp(void* _a, void* _b) {
int a = *((int*)_a), b = *((int*)_b);
# 在arr2中寻找a和b,找到了就返回查询结果,没有找到就返回空
struct hashTable *fa = find(a), *fb = find(b);
if (fa == NULL) {
return fb == NULL ? a - b : 1;
} else {
return fb == NULL ? -1 : fa->val - fb->val;
}
}
作者:LeetCode-Solution
2.完整代码(C)
构建哈希表来存放 a r r 2 arr2 arr2中每个元素的值及下标,即把 ( a r r 2 [ i ] , i ) (arr2[i], i) (arr2[i],i) 这一键值对放入哈希表中。这样方便我们判断一个元素是不是存在于 a r r 2 arr2 arr2中,并可以同时获得其下标。这里使用C语言中一个常用的哈希表函数库:uthash
struct hashTable {
int key;
int val;
UT_hash_handle hh;
};
struct hashTable* hashtable;
struct hashTable* find(int ikey) {
struct hashTable* tmp;
HASH_FIND_INT(hashtable, &ikey, tmp);
return tmp;
}
void insert(int ikey, int ival) {
struct hashTable* tmp = malloc(sizeof(struct hashTable));
tmp->key = ikey, tmp->val = ival;
HASH_ADD_INT(hashtable, key, tmp);
}
int cmp(void* _a, void* _b) {
int a = *((int*)_a), b = *((int*)_b);
struct hashTable *fa = find(a), *fb = find(b);
if (fa == NULL) {
return fb == NULL ? a - b : 1;
} else {
return fb == NULL ? -1 : fa->val - fb->val;
}
}
int* relativeSortArray(int* arr1, int arr1Size, int* arr2, int arr2Size, int* returnSize) {
hashtable = NULL;
for (int i = 0; i < arr2Size; ++i) {
insert(arr2[i], i);
}
qsort(arr1, arr1Size, sizeof(int), cmp);
*returnSize = arr1Size;
return arr1;
}
作者:LeetCode-Solution
总结
虽然是简单题,也可以为我们之后的解题提供更多的基本思路。自定义比较函数,是个好东西啊!