力扣1365. 有多少小于当前数字的数字---利用哈希表逐步优化

1365. 有多少小于当前数字的数字

给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目。

换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 nums[j] < nums[i] 。

以数组形式返回答案。

示例 1:

输入:nums = [8,1,2,2,3]
输出:[4,0,1,1,3]
解释:
对于 nums[0]=8 存在四个比它小的数字:(1,2,2 和 3)。
对于 nums[1]=1 不存在比它小的数字。
对于 nums[2]=2 存在一个比它小的数字:(1)。
对于 nums[3]=2 存在一个比它小的数字:(1)。
对于 nums[4]=3 存在三个比它小的数字:(1,2 和 2)。
示例 2:

输入:nums = [6,5,4,8]
输出:[2,1,0,3]
示例 3:

输入:nums = [7,7,7,7]
输出:[0,0,0,0]

提示:
2 <= nums.length <= 500
0 <= nums[i] <= 100

题解:

我们可以通过暴力循环的角度解决该题,但利用哈希表进行存储数据更能提高一下效率.
这是我刚开始利用哈希表的做法,但这法循环较多,每没有真正的去利用哈希表的特性的进行解题,因为我只是看到了哈希表很浅很浅的一层。

代码:

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* smallerNumbersThanCurrent(int* nums, int numsSize, int* returnSize){
    
    
    int hash[101]={
    
    0};//创建哈希表
    int *sum = (int*)malloc(sizeof(int)*numsSize);
    memset(sum,0,sizeof(int)*numsSize);//先都变成0
    for(int i=0;i<numsSize;i++)
    {
    
    
        hash[nums[i]]++;//哈希表存储数字出现的次数
    }
    for(int i=0;i<numsSize;i++)//遍历一遍nums数组的每个数
    {
    
    
        for(int j=0;j<101;j++)//对选定的那个数进行遍历一遍哈希表找到比他小的
        {
    
    
            if(j<nums[i])
            {
    
    
                sum[i]=sum[i]+hash[j];
            }
        }
    }
    *returnSize=numsSize;
    return sum;
}

后来发现第二个for+for的循环可以缩小一下检索范围:

代码:

int* smallerNumbersThanCurrent(int* nums, int numsSize, int* returnSize){
    
    
    int hash[101]={
    
    0};//创建哈希表
    int *sum = (int*)malloc(sizeof(int)*numsSize);
    memset(sum,0,sizeof(int)*numsSize);//先都变成0
    for(int i=0;i<numsSize;i++)
    {
    
    
        hash[nums[i]]++;//哈希表存储数字出现的次数
    }
    for(int i=0;i<numsSize;i++)//遍历一遍nums数组的每个数
    {
    
    
        for(int j=0;j<nums[i];j++)//对选定的那个数进行遍历一遍哈希表找到比他小的
        {
    
    
            if(j<nums[i])
            {
    
    
                sum[i]=sum[i]+hash[j];
            }
        }
    }
    *returnSize=numsSize;
    return sum;
}

优化后:

即利用哈希表一种“自我排序”的特性,即在将哈希表存储完数组次数后直接开始遍历哈希表进行“改造”哈希表,让他由一个存储数字对应次数的表变成存储数组中比该下标对应数小的数的个数的表,即直接将他变成满足我们题目所要的答案的表格。
这是由于一种特性:
即对于1,比他小的数字的个数为0的个数;对于2,比他小的数字的个数为0和1的个数…依次类推。

见代码:

int* smallerNumbersThanCurrent(int* nums, int numsSize, int* returnSize){
    
    
    int hash[101]={
    
    0};//先初始化
    int *sum = (int*)malloc(sizeof(int)*numsSize);
    memset(sum,0,sizeof(int)*numsSize);
    for(int i=0;i<numsSize;i++)
    {
    
    
        hash[nums[i]]++;//先存储进去
    }
    for(int i=1;i<101;i++)
    {
    
    
        hash[i]=hash[i]+hash[i-1];//即此时hash[i]代表的是数字i的个数以及比i小的数字的个数
    }
    for(int i=0;i<numsSize;i++)
    {
    
    
        if(nums[i]==0)//防止下面越界,所以单拉出一种情况
        {
    
    
            sum[i]=0;
            continue;
        }
        sum[i] = hash[nums[i]-1];
    }
    *returnSize=numsSize;
    return sum;
}

猜你喜欢

转载自blog.csdn.net/xiangguang_fight/article/details/112543746