Leetcode1122. 数组的相对排序——自定义排序中的比较函数,妙用!


前言

这是一道简单题,我们可以很快地想到一种解决思路。我想记录下这道题是因为,它为自定义排序中的比较函数树立了典范(言重了→_→)。
总而言之,尤其是对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 0arr1[i]1000,因此计数数组的长度设为1001。接下来开始它的表演:

  1. 遍历 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出现的次数;
  2. 遍历 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]清零;
  3. 最后处理 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来说,它们有三种比较、排序情况:

  1. a , b a,b a,b都在 a r r 2 arr2 arr2中出现,那么直接按照下标排,谁的下标大谁排后面;
  2. a , b a,b a,b中有一个在 a r r 2 arr2 arr2中出现,那么出现在 a r r 2 arr2 arr2中的元素排在前面,另一个元素排在后面;
  3. 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

总结

虽然是简单题,也可以为我们之后的解题提供更多的基本思路。自定义比较函数,是个好东西啊!

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值