[学习报告]《LeetCode零基础指南》(第四讲) 指针
作者:互联网
学习内容:https://blog.csdn.net/WhereIsHeroFrom/article/details/120875926
一、今日知识点总结
实现简单,时间效率低:冒泡、选择、插入排序
实现相对复杂,效率较高的:归并、快排、希尔排序 等
非比较排序:基数排序、计数排序、桶排序
C语言排序API:qsort
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*));
参数 | 说明 |
---|---|
base | 要排序的数组的第一个元素的指针 |
nitems | 数组的个数 |
size | 数组元素的大小(数组数据类型的字节大小) |
compar | 用来比较两个元素大小的函数,即函数指针(比较算法的回调函数) |
qsort的使用范式
//排序回调函数:用于表示比较的两个数谁在前谁在后的规则
int cmp(const void *a, const void *b){
return (*(int *)a) - (*(int *)b);//升序排列
//or
return (*(int *)b) - (*(int *)a);//降序排列
}
//...
int a[7] = {0,2,4,1,2,6,1};
qsort(a,7,sizeof(int),cmp);
//...
奇偶排序
int qua(int x){
return x & 1;//(1) 当奇数,返回1,偶数返回0
}
int cmp(const void *a, const void *b){
return qua(*(int *)a) - qua(*(int *)b); //(2) 实现了偶数排前面,奇数排后面
}
为何是偶数排前面,奇数排后面?
qua(x)判断结果是,奇数返回1,偶数返回0;(2)这行表达式实现的是升序排列
代表偶数的0小于代表奇数的1,所以偶数排前面,奇数排后面
关键思想是,根据实际题目需要,根据数据的特点,对排序的元素进行一个转换计算,进而改变排序的规则
二、今日解题
战绩:
912. 排序数组
int cmp(const void *p1,const void*p2){
return *(int *)p1 - *(int *)p2; //(1) 比较函数
}
int* sortArray(int* nums, int numsSize, int* returnSize){
qsort(nums,numsSize,sizeof(int),cmp);//(2)调用排序API
*returnSize = numsSize;//(3)告诉调用者排序后的元素个数
return nums;//(4)返回排序后的数组首地址
}
169. 多数元素
int cmp(const void *p1,const void *p2){
return *(int *)p1 - *(int *)p2; //比较函数,升序排列
}
int majorityElement(int* nums, int numsSize){
qsort(nums,numsSize,sizeof(int),cmp);//调用排序函数,得到升序排列后的nums
return nums[numsSize/2];//题意全部数组都满足存在多数元素(个数超过一半,也就是>n/2),无论这个多数元素是大还是小,[n/2]肯定是他
}
217. 存在重复元素
int cmp(const void *a,const void *b){
return *(int *)a - *(int *)b;//升序排列
}
bool containsDuplicate(int* nums, int numsSize){
qsort(nums,numsSize,sizeof(int),cmp);//排序升序
for(int i = 1;i<numsSize;i++){
if(nums[i] == nums[i-1]){//重复的元素必定相邻
return true;
}
}
return false;
}
164. 最大间距
int cmp(const void *a,const void *b){
return *(int *)a - *(int *)b;//升序
}
int maximumGap(int* nums, int numsSize){
if(numsSize<2){
return 0;
}
qsort(nums,numsSize,sizeof(int),cmp);//升序排序
int max = 0;//最大值,若后续最大值比max大,max就等于新的最大值
for(int i = 1;i<numsSize;i++){//后一个减前一个,所有i从1开始
if(nums[i]-nums[i-1]>max){//相邻元素相减,因为升序排列,故[i]-[i-1]
max = nums[i]-nums[i-1];//替换最大值
}
}
return max;
}
905. 按奇偶排序数组***
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int odd(int num){
return num&1;//根据奇数二进制最后一位必定为1,偶数为0;位于1后,奇数返回1,偶数返回0;
}
int cmp(const void *a,const void *b){
return odd(*(int *)a) - odd(*(int *)b);//升序排列,所以偶数排在前面,奇数排在后面
}
int* sortArrayByParity(int* nums, int numsSize, int* returnSize){
int *ans = (int *)malloc(sizeof(int)*numsSize);//申请一段长度为numSize个int的内存空间,首地址赋值给ans
for(int i = 0;i<numsSize;i++){
ans[i] = nums[i];//复制数组元素
}
*returnSize = numsSize;//告诉调用者返回的新数组的元素个数
qsort(ans,numsSize,sizeof(int),cmp);//执行排序
return ans;
}
539. 最小时间差
int cmp(const void *a,const void *b){
return *(int *)a - *(int *)b;//升序排列 -- 把时间按照最小到最大排序
//因为相邻的时间点的时间差肯定最小(贪心)
}
int findMinDifference(char ** timePoints, int timePointsSize){
int *times = (int *)malloc(sizeof(int)*timePointsSize);//申请了一个长度为sizeof(int)*timePointsSize的内存空间,首地址赋值给times
int i,h,m = 0,min = 1440;//24小时的最大时间差为1440分钟,从0点到24点(一天有1440分钟)
for(i = 0;i<timePointsSize;i++){
sscanf(timePoints[i],"%d:%d",&h,&m);//通过sscanf把反格式化时间字符串得到小时和分钟
times[i] = h*60 + m;//计算分钟数,以分钟表示
}
qsort(times,timePointsSize,sizeof(int),cmp);//排序
for(i = 1;i<timePointsSize;i++){//思路和最大间距类似,只是换成了「比小」
if(times[i] - times[i-1]<min){
min = times[i] - times[i-1];
}
}
if((times[0] + 1440 - times[timePointsSize-1])<min){//要特别留意的地方:根据上面的计算方式,会漏掉首位和末位这两个时间的比较,最小值和最大值也是相邻的,它们之间是存在时间差最小的可能的情况 ==> 最小时间是排在最大时间之后,例如最大时间是11:55,最小时间是00:01,时间差为6分钟
min = times[0] + 1440 - times[timePointsSize-1];//如何理解加1440,从计时器的角度,可以设定每个时间都是从00:00开始计时,而00:01可能是已经走完了24小时并走了1分钟,故加 1440即为00:01的计时
}
return min;
}
976. 三角形的最大周长
// 贪心
// a+b>c
// 周长最大 只要c最大,a+b也就最大,没必要全部都相互组合检查一下
int cmp(const void *a,const void *b){
return *(int *)a - *(int *)b; //讲线段升序排列
}
int largestPerimeter(int* nums, int numsSize){
qsort(nums,numsSize,sizeof(int),cmp);
for(int i=numsSize-1;i>=2;i--){//从最大一条线开始检查
if(nums[i-2]+nums[i-1]>nums[i]){//若该线的前面两条线满足三角形 a+b>c,则该三角形周长一定最大
return nums[i] + nums[i-1] + nums[i-2];
}
}
return 0;
}
881. 救生艇
以下两个解法就只是在循环结束条件的选用不同
//一次最多两人
//两人重量小于limit
//如果重量大于limit,只能上一个,就让最重的人先上,轻的留下,看是否有可以搭配的
//试错效率最高的就是先对人的重量进行排序,让最轻的和最重的人匹配,试错次数最低。
int cmp(const void *a,const void *b){
return *(int *)a - *(int *)b;
}
int numRescueBoats(int* people, int peopleSize, int limit){
qsort(people,peopleSize,sizeof(int),cmp);
int l = 0,r = peopleSize-1,cnt = 0;
while(peopleSize>0){
if(people[l] + people[r] <= limit){
l++;
r--;
peopleSize -=2;
}else{
r--;
peopleSize--;
}
cnt++;
}
return cnt;
}
//最好就是一次两人,但如何最高效率呢,就是刚好能匹配limit,就是两人重量之和最接近limit
//要能凑满,就相当于凑满减,加最少的钱就能达到优惠线,也就是最大加最小
int cmp(int *a,int *b){
return *a - *b;//升序排列
}
int numRescueBoats(int* people, int peopleSize, int limit){
qsort(people,peopleSize,sizeof(int),cmp);
//次数people按照升序排列了
//先让最重的和最轻组合比较,让重的先走,能稍上轻的就稍上轻的,这样船只的承重能力最不浪费
//且剩余的能组合成功的概率会更大
//双指针?
int l=0,r=peopleSize-1;
int cnt = 0;
while(l<=r){
if((people[r] + people[l])<=limit){
l++;r--;
}else{
r--;
}
cnt++;
}
return cnt;
}
三、今日收获
四、今日疑问
五、其他参考
标签:指南,return,nums,int,void,const,cmp,LeetCode,指针 来源: https://blog.csdn.net/campchan/article/details/123582674