排序的思想总结和题解

在这里插入图片描述

今天学习到的内容是八大排序


八大排序思想简述:

冒泡排序

每次比较相邻的两个数,让最大的数右移(或者最小的数)

选择排序

遍历每个元素,让其插入前面的有序区间,要求插入后仍然有序,如果按升序,也就是将比插入元素大的元素右移,直到该位置左边比插入元素小右边比插入元素大,就在该位置插入。

插入排序

每次都选择数组中最小的与数组第一个元素交换,第二次就是次最小的与第二个元素交换,以此类推。

希尔排序

先将元素分组,假设有八个元素,那么以元素个数的一半为步长,例如:将下标 0,4分为一组,1,5,分为一组,对每组元素执行插入排序,排好序之后,步长减半,例如:将0,2,4,6,分为一组,再次执行插入排序,直到步长为1,执行最后全部元素为一组的插入排序。

归并排序

先利用递归每次将数组分为两组,最后递归到两个元素,就进行归并排序,先把这两个元素拷贝到两个数组,然后比较大小将小的先放回原数组,再将大的放回原数组,就完成了归并,然后再将两个有序的数组进行归并,直到最后对大数组进行归并,就排好序了。

快速排序

每次选取区间第一个元素为pivot标准值,然后用两个指针遍历,一个从left一个right,先看如果right指向的值大于pivot则right–,直到right指向的值小于pivot,将right指向的元素赋值给left指向的位置,然后移动left,left不断++找到一个大于pivot的值然后赋值给right,再次开始移动right,直到最后right==left,这个位置就是pivot的位置,将pivot放到这里,然后再次对pivot左边进行同样的操作,右边进行同样的操作,直到该区间只有一个值。

计数排序

只适合于数组元素的大小较小的数组,创建一个哈希表,将元素映射到哈希表中,然后遍历哈希表取出数组元素即可。

基数排序

创建一个0~9的哈希,第一次迭代将按照个位将数组映射到哈希表中,然后按照升序取出哈希表中的数组,然后再按照十位将数组映射到哈希表中,再就是百位,千位,直到最高位元素的位数,最后升序取出的元素就是已经排好序的了。

今日题解

1464. 数组中两元素的最大乘积

排序后直接最大-1乘上次大-1,返回即可

int cmp(const void* str1,const void* str2)
{
    return *(int*)str1 - *(int*)str2;
}
int maxProduct(int* nums, int numsSize){
    qsort(nums,numsSize,sizeof(int),cmp);
    return (nums[numsSize-1]-1)*(nums[numsSize-2]-1);
}

1636. 按照频率将数组升序排序

思路:根据题干,按照频率升序排序,如果频率相同则按照数值大小降序排列,定义一个哈希表,记录数字出现的频率,然后使用哈希表的频率用qsort对数组排序,如果频率相同,就用数值进行降序排序。
注意:这里数字范围为-100到100,所以要在映射哈希表的时候加上一个偏移量,我加的是100,这样下标范围就是0–200,哈希表大小就是201;


int hash[201];
int cmp(const void*str1,const void* str2)
{
    if(hash[*(int*)str1+100] - hash[*(int*)str2+100]==0)//频率相同,用数值排序
    {
        return -(*(int*)str1 - *(int*)str2);
    }
    return hash[*(int*)str1+100] - hash[*(int*)str2+100];//调用哈希表中的频率进行排序。
}

int* frequencySort(int* nums, int numsSize, int* returnSize){
    //int* ans = (int*)malloc(sizoef(int)*numsSize);
    *returnSize = numsSize;
    memset(hash,0,sizeof(int)*201);
    for(int i = 0;i<numsSize;i++)
    {
        ++hash[nums[i]+100];//加上一个偏移量
    }
    qsort(nums,numsSize,sizeof(int),cmp);//按照频率升序
    return nums;
}

1287. 有序数组中出现次数超过25%的元素

思路:定义一个count记录数字出现的次数,定义一个count_num记录出现的数字是哪个,然后遍历数组,如果arr[i] = = count_num 那么计数器就++,如果不相等就更新count_num 并且计数器归1(因为这个数出现了一次)循环过程中判断,如果count大于了arrsize/4就跳出循环返回count_num;

int findSpecialInteger(int* arr, int arrSize){
    int count = 0;
    int count_num = arr[0];
    for(int i =0;i<arrSize;i++)
    {
        if(count>(arrSize/4))
        {
            break;
        }
        if(count_num==arr[i])
        {
            count++;
        }
        else
        {
            count_num = arr[i];
            count = 1;
        }
    }
    return count_num;
}

436. 寻找右区间

二位数组按照第一列元素排序的需要特别注意,传过去的是一个模拟的二维数组,首元素地址,是一维数组的地址,每个元素是(int*)特别是设计cmp函数设计,因为str1,是一级指针的地址,所以用二级指针接受,然后解引用拿到这个一维数组的地址,再次解引用访问数组元素。
思路:就是先创建一个start数组,二维数组,第一个位置存放start i 数据,第二个位置,存放下标。然后对它进行排序,然后遍历intervals数组,用end i 在start里面进行二分查找,找到>=end i 的最小下标,然后将该下标保存,存放到ans数组中。

int cmp(const void** str1,const void** str2)
{
    return (*(int**)str1)[0] - (*(int**)str2)[0];
}

int* findRightInterval(int** intervals, int intervalsSize, int* intervalsColSize, int* returnSize){
    int** start_i = (int**)malloc(sizeof(int*)*intervalsSize);
    for(int i =0;i<intervalsSize;i++)
    {
        start_i[i] = (int*)malloc(sizeof(int)*2);
    }
    for(int i =0;i<intervalsSize;i++)
    {
        start_i[i][0] = intervals[i][0];//存数据
        start_i[i][1] = i;//存下标
    }
    int* ans = (int*)malloc(sizeof(int)*intervalsSize);
    *returnSize = 0;
    qsort(start_i,intervalsSize,sizeof(int*),cmp);
    for(int i =0;i<intervalsSize;i++)
    {
        int left = 0;
        int right = intervalsSize-1;
        int min = -1;
        while(left<=right)
        {
            int mid = (left+right)>>1;
            if(start_i[mid][0]>=intervals[i][1])
            {
                min = start_i[mid][1];
                right = mid-1;
            }
            else
            {
                left = mid+1;
            }
        }
        ans[*returnSize] = min;
        (*returnSize)++;
    }
    return ans;
}

宫水三叶的莫队思想解法:优雅的暴力:思路同前面,就是将开始的数据和下标存放到start数组,end的数组和下标存放到end数组里面。然后对这两个二维数组按照数据大小排序,然后用双指针遍历end数组的数值位,找到>=end_i[i][0] 的start_i的数值,然后将其数值,赋值给ans数组,如果找不到>=end_i[i][0]的start_i的数值,就给ans赋值为-1。最后返回即可。

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int cmp(const void** str1,const void** str2)
{
    return (*(int**)str1)[0] - (*(int**)str2)[0];
}

int* findRightInterval(int** intervals, int intervalsSize, int* intervalsColSize, int* returnSize){
    int** start_i = (int**)malloc(sizeof(int*)*intervalsSize);
    int** end_i = (int**)malloc(sizeof(int*)*intervalsSize);
    int* ans = (int*)malloc(sizeof(int)*intervalsSize);
    *returnSize = intervalsSize;
    int i = 0;
    int j = 0;

    for(i =0;i<intervalsSize;i++)
    {
        start_i[i] = (int*)malloc(sizeof(int)*2);
        end_i[i] = (int*)malloc(sizeof(int)*2);
    }
    for(i =0;i<intervalsSize;i++)
    {
        start_i[i][0] = intervals[i][0];//存数据
        start_i[i][1] = i;//存下标
        end_i[i][0] = intervals[i][1];//存数据
        end_i[i][1] = i;//存下标
    }
    
    qsort(start_i,intervalsSize,sizeof(int*),cmp);
    qsort(end_i,intervalsSize,sizeof(int*),cmp);
    i = 0;
    j = 0;
    for(i = 0;i<intervalsSize;i++)
    {
        while(j<intervalsSize && start_i[j][0] < end_i[i][0] )
        {
            j++;
        }
        if(j>=intervalsSize)
        {
            ans[end_i[i][1]] = -1;
        }
        else
        {
            ans[end_i[i][1]] = start_i[j][1];
        }
    }

    return ans;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KissKernel

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值