1. 两个数对之间的最大乘积差
- 题目
两个数对
(a, b)
和(c, d)
之间的 乘积差 定义为(a * b) - (c * d)
。例如,
(5, 6)
和(2, 7)
之间的乘积差是(5 * 6) - (2 * 7) = 16
。
给你一个整数数组nums
,选出四个 不同的 下标w、x、y
和z
,使数对(nums[w], nums[x])
和(nums[y], nums[z])
之间的 乘积差 取到 最大值 。返回以这种方式取得的乘积差中的 最大值 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-product-difference-between-two-pairs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
返回两个数对的最大值,那么就需要将数组中最大和次大的数相乘、最小与次小的数相乘,前一项减去后一项即为最大乘积差。对数组排序即可解答本题
- 源码实现
int cmp(const void* a, const void *b)
{
return *(int *)a - *(int *)b;
}
int maxProductDifference(int* nums, int numsSize){
qsort(nums, numsSize, sizeof(int), cmp); //排序
return nums[numsSize - 1] * nums[numsSize - 2] - nums[0] * nums[1];
}
2. 数组拆分
- 题目
给定长度为
2n
的整数数组nums
,你的任务是将这些数分成n
对, 例如(a1, b1), (a2, b2), ..., (an, bn)
,使得从1
到n
的min(ai, bi)
总和最大。返回该 最大总和 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/array-partition-i
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
每一次选取的是数对的较小值,要使得总和最大,那么每次拆分的数对中的较小值应该仅次于较大值。根据这个条件,我们可以对数组进行排序,然后选取偶数位的元素相加即可
- 源码实现
int cmp(const void* a, const void *b)
{
return *(int *)a - *(int *)b;
}
int arrayPairSum(int* nums, int numsSize){
//先排序
qsort(nums, numsSize, sizeof(int), cmp);
int i;
int ret = 0;
for(i = 0; i < numsSize; i += 2)
{
ret += nums[i]; //取偶数位的值相加
}
return ret;
}
3. 摆动排序 II
- 题目
给你一个整数数组
nums
,将它重新排列成nums[0] < nums[1] > nums[2] < nums[3]...
的顺序。你可以假设所有输入数组都可以得到满足题目要求的结果。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/wiggle-sort-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
显而易见这题是需要进行排序的,问题在于排序之后怎么排列元素,观察题目给出的示例,可以看到较大值一定是在奇数位的,按照升序排列之后,较大的元素值一定是在数组的右半边,那么我们是不是可以先从数组的最右边开始遍历,将元素按指定位置插入新数组中,较大值插入完毕后,剩下的就是较小值。
- 源码实现
int cmp(const void *a, const void* b)
{
return *(int *)a - *(int *)b;
}
void wiggleSort(int* nums, int numsSize){
qsort(nums, numsSize, sizeof(int), cmp);
int ans[numsSize];
int i;
for(i = 0; i < numsSize; ++i)
{
ans[i] = nums[i]; //赋值到新数组
}
int r = numsSize - 1; //注意是从大到小插入
for(i = 1; i < numsSize; i += 2) //先插较大值
{
nums[i] = ans[r--];
}
for(i = 0; i < numsSize; i += 2) //在插较小值
{
nums[i] = ans[r--];
}
}
4. 分发饼干
- 题目
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子
i
,都有一个胃口值g[i]
,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干j
,都有一个尺寸s[j]
。如果s[j] >= g[i]
,我们可以将这个饼干j
分配给孩子i
,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/assign-cookies
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
本题其实就是求s数组中的元素大于等于g数组中元素的个数
- 源码实现
int cmp(const void* a, const void* b)
{
return *(int *)a - *(int *)b;
}
int findContentChildren(int* g, int gSize, int* s, int sSize){
qsort(g, gSize, sizeof(int), cmp); //先排序
qsort(s, sSize, sizeof(int), cmp);
int p2 = sSize - 1;
int p1 = gSize - 1;
int cnt = 0; //统计满足的孩子的数量
//先满足胃口最大的孩子
while(p1 >= 0 && p2 >= 0)
{
if(s[p2] >= g[p1])
{
cnt++;
p1--;
p2--;
}
else
{
p1--;
}
}
return cnt;
}
5. 最少操作使数组递增
- 题目
给你一个整数数组
nums
(下标从 0 开始)。每一次操作中,你可以选择数组中一个元素,并将它增加 1 。比方说,如果
nums = [1,2,3]
,你可以选择增加nums[1]
得到nums = [1,3,3]
。
请你返回使nums
严格递增 的 最少 操作次数。我们称数组
nums
是 严格递增的 ,当它满足对于所有的0 <= i < nums.length - 1
都有nums[i] < nums[i+1]
。一个长度为 1 的数组是严格递增的一种特殊情况。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-operations-to-make-the-array-increasing
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
求最小的操作次数,只需要比前面的元素大1就行。
- 双层循环可以解答本题,外层循环控制前一个元素,内层循环控制后一个元素。
- 使用单层循环加条件语句。外循环控制前一个元素,条件语句保证后一个元素比前一个元素大
- 源码实现
int minOperations(int* nums, int numsSize){
int i;
int cnt = 0;
int pre = nums[0] + 1; //只需要比前一个元素大1即可
for(i = 1; i < numsSize; ++i)
{
if(pre < nums[i])
{
pre = nums[i] + 1; //小于更新为当前nums[i]的元素并加1
}
else
{
cnt += pre - nums[i]; //统计数量
++pre; //大于就加1,直到小于更新pre值
}
}
return cnt;
}
/*
模拟:[1, 1, 1]
第一次 pre = 2 大于 nums[1] cnt统计前一个元素和后一个元素的差值(即操作数) cnt = 1;
第二次 pre = 3 大于 nums[2] cnt = 1 + 3 - 1;
所以最终结果为3。
*/
6. 使数组唯一的最小增量
- 题目
给你一个整数数组
nums
。每次 move 操作将会选择任意一个满足0 <= i < nums.length
的下标i
,并将nums[i]
递增1
。返回使
nums
中的每个值都变成唯一的所需要的最少操作次数。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-increment-to-make-array-unique
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
要保证数组中每一个元素是唯一的增量,需要找出数组中不唯一的值,利用排序先将数组中相同的值放在一起,然后参照上一题的思路求解
- 源码实现
int cmp(const void* a, const void *b)
{
return *(int *)a - *(int *)b;
}
int minIncrementForUnique(int* nums, int numsSize){
qsort(nums, numsSize, sizeof(int), cmp);
int i;
int pre = nums[0] + 1;
int cnt = 0;
for(i = 1; i < numsSize; ++i)
{
if(pre < nums[i])
{
pre = nums[i] + 1;
}
else
{
cnt += pre - nums[i];
++pre;
}
}
return cnt;
}
7. 三角形的最大周长
- 题目
给定由一些正数(代表长度)组成的数组
A
,返回由其中三个长度组成的、面积不为零的三角形的最大周长。如果不能形成任何面积不为零的三角形,返回
0
。
- 思路分析
利用贪心算法思想,要想得到最大的周长的值,只需要判断该数组中最大的三个元素是否构成三角形。
- 构成三角形的条件:任意两边之和大于第三边。三个元素任意两个组合相加判断是否大于第三边固然是可以的,但是操作复杂且时间复杂度高,不建议使用。
- 像这种情况我们可以先进行排序,排序之后我们发现
a < b < c
已经得出两个结论b + c > a
和a + c < b
,现在只需要比较a + b > c
- 最后求最大周长的值
- 源码实现
int cmp(const void* a, const void *b)
{
return *(int *)a - *(int *)b;
}
int largestPerimeter(int* nums, int numsSize){
if(numsSize < 2) //两个元素是无法构成三角形的
{
return 0;
}
qsort(nums, numsSize, sizeof(int), cmp);
int i;
//从最后的元素开始遍历,只要能构成三角形,那么结果就为最大周长
for(i = numsSize - 1; i >= 2; --i)
{
if(nums[i - 2] + nums[i - 1] > nums[i])
{
return nums[i - 2] + nums[i - 1] + nums[i];
}
}
return 0;
}
8. 救生艇
- 题目
第 i 个人的体重为
people[i]
,每艘船可以承载的最大重量为limit
。每艘船最多可同时载两人,但条件是这些人的重量之和最多为
limit
。返回载到每一个人所需的最小船数。(保证每个人都能被船载)。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/boats-to-save-people
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
要求所需最小船数,就必须保证每次乘坐的是能乘坐的最大值。这种情况使用排序就比较方便对其进行求解。
- 第一步,排序
- 第二步,判断最大的体重和最小体重能否一起乘坐一艘船,能就一起走,不能就先让体重大的人先走
- 第三步,返回结果
- 源码实现
int cmp(const void* a, const void *b)
{
return *(int *)a - *(int *)b;
}
int numRescueBoats(int* people, int peopleSize, int limit){
//体重people[i] , 船能承载的最大体重是limit
//同时载两人
//求载到每一个人所需的最小船数
qsort(people, peopleSize, sizeof(int), cmp);
int ans = 0; //统计船的数量
int left = 0;
int right = peopleSize - 1;
while(left <= right)
{
if(left == right) //只有一个人了,直接走
{
++ans;
break;
}
else if(people[left] + people[right] > limit) //最小的与最大的比较,如果大于就让最大的先走
{
++ans;
right--;
}
else
{
++ans;
right--;
left++;
}
}
return ans;
}
9. 有效三角形的个数
- 题目
给定一个包含非负整数的数组,你的任务是统计其中可以组成三角形三条边的三元组个数。
- 思路分析
(参照的官方思路)先排序,在二分查找有效三角形的个数。
- 假定数组
[a ,b ,c]
, 排序完成后a < b < c
,分析数组中元素可以得出两个结论b + c > a
和a + c < b
,然后通过二分法查找满足a + b > c
的元素个数。- 统计mid左边到
j
位置的元素个数。
- 源码实现
int cmp(int *a, int *b) {
return *a - *b;
}
int triangleNumber(int* nums, int numsSize){
int cnt = 0; //统计有效三角形的数量
//先排序,后比较
int i, j;
qsort(nums, numsSize, sizeof(int), cmp);
for(i = 0; i < numsSize; ++i)
{
for(j = i + 1; j < numsSize; ++j)
{
int left = j + 1;
int right = numsSize - 1;
int k = j; //防止枚举a,b的出现0的时候,二分查找失败
while(left <= right)
{
int mid = left + (right - left) / 2;
if(nums[mid] < nums[j] + nums[i])
{
k = mid;
left = mid + 1;
}
else
{
right = mid - 1;
}
}
cnt += k - j; //统计每次循环有效三角形的个数
}
}
return cnt;
}