目录
455. 分发饼干
题目描述:
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
一个人居然能有那么多孩子?!注定要饿死。
我的想法:对两个数组进行排序使用双指针,最优匹配,优先满足胃口最小的孩子,ret计数最多能满足多少孩子。
int cmp_int(const void* e1,const void* e2){
return *(int*)e1-*(int*)e2;
}
int findContentChildren(int* g, int gSize, int* s, int sSize){
//排序
qsort(g,gSize,sizeof(int),cmp_int);
qsort(s,sSize,sizeof(int),cmp_int);
int ret=0;
int left=0,right=0;
while(right<sSize&&left<gSize){
if(g[left]<=s[right]){
ret++;left++;
}
right++;
}
return ret;
}
376. 摆动序列
题目描述:
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。
给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。
对于这个题目!首先,我得看得懂题!
有好多点需要注意:
- nums只有两个元素时,要判断两元素是否相同:相同是平的,摆动序列是1;相反,两元素不相同的情况下,摆动序列是2。
- nums数组的大小大于2的情况下,max的初始值并不是1。就如上面一条,如果前两个元素相同,只有一个应该被包含在摆动序列中;而如果两个元素不相同,两个元素都应该包含在摆动序列中(第9行代码)
- 遇到当前元素与前一元素差值为0的情况,应该有continue的操作以避免对predif做更新。如果更predif做更新,predif必然等于0,后续sign的值就永远为0,因此必然要continue。(第14行代码)
- 在对sign做判断时,条件如果是sign<0会漏掉一个序列元素。(第17行代码)
如果没有对curdif=0的情况continue,那么容易在后面sign做判断时使用条件sign<0,就会造成下面错误:
正确代码如下:
int wiggleMaxLength(int* nums, int numsSize){
int max=0;
if(numsSize==1) return max=1;
//predif表示前一个差值
int predif=nums[1]-nums[0];
if(numsSize==2){
return max=(predif==0)?1:2;
}
max=(predif==0)?1:2;
for(int i=1;i<numsSize;i++){
//curdif表示当前差值
int curdif=(nums[i]-nums[i-1]);
//当前差值为0的话,continue而不进行predif的更新
if(curdif==0) continue;
int sign=predif*curdif;
//等于0的情况保证前面是平坡的正确性
if(sign<=0){
max++;
}
predif=curdif;
}
return max;
}
53. 最大子数组和
太经典的题目很多种解法。
1. 分治法
int CrossingSubArray(int* nums,int low,int mid,int high){
int max_left=INT_MIN,max_right=INT_MIN;
int sum=0;
//计算包括中间左边的最大子数组和
for(int i=mid;i>=low;i--){
sum+=nums[i];
max_left=fmax(sum,max_left);
}
sum=0;
//计算包括中间右边的最大子数组和
for(int i=mid+1;i<=high;i++){
sum+=nums[i];
max_right=fmax(sum,max_right);
}
//两数相加=跨越中间的最大子数组和
return max_left+max_right;
}
int maxArray(int* nums, int low,int high){
if(low==high) return nums[low];
int mid=(low+high)/2;
//分(左闭右闭)
int S1=maxArray(nums,low,mid);
int S2=maxArray(nums,mid+1,high);
//计算跨越中间的最大子数组和
int S3=CrossingSubArray(nums,low,mid,high);
//比较最大值
int max=fmax(S1,S2);
max=fmax(max,S3);
return max;
}
int maxSubArray(int* nums, int numsSize){
int max=maxArray(nums,0,numsSize-1);
return max;
}
2. 动态规划
int maxSubArray(int* nums, int numsSize){
int* dp=(int*)malloc(sizeof(int)*numsSize);
dp[0]=nums[0];
int max=dp[0];
for(int i=1;i<numsSize;i++){
dp[i]=fmax(dp[i-1]+nums[i],nums[i]);
max=(dp[i]>max)?dp[i]:max;
}
return max;
}
3.贪心
连续和小于0的情况下,子序列重新开始选取;
连续和大于0的情况下,将元素添加到子序列并更新连续和的大小。
int maxSubArray(int* nums, int numsSize){
int ret=INT_MIN;
int sum=0;
for(int i=0;i<numsSize;i++){
sum+=nums[i];
if(sum>ret) ret=sum;
if(sum<0) sum=0;
}
return ret;
}