目录
一、1913. 两个数对之间的最大乘积差
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]) 之间的 乘积差 取到 最大值 。
返回以这种方式取得的乘积差中的 最大值 。
2.分析
- 要使得乘积差尽可能大,则 ( a ∗ b ) (a*b) (a∗b) 尽可能大, ( c ∗ d ) (c*d) (c∗d) 尽可能小。
- 所以对数组排序后, a , b a,b a,b 取最大的两个值, c , d c,d c,d 取最小的两个值即可。
3.代码
class Solution {
public int maxProductDifference(int[] nums) {
Arrays.sort(nums);
int length = nums.length;
return (nums[length - 1] * nums[length - 2]) - (nums[0] * nums[1]);
}
}
二、976. 三角形的最大周长
1.题目
给定由一些正数(代表长度)组成的数组 A,返回由其中三个长度组成的、面积不为零的三角形的最大周长。
如果不能形成任何面积不为零的三角形,返回 0。
2.分析
- 假设三条边分别为 a , b , c(a > b),要使得这三条边能组成一个三角形,必须满足: a + b > c 且 a − b < c a+b>c且a-b<c a+b>c且a−b<c
- 所以求能形成三角形的最大周长,可以先将数组排序,再从最大数开始遍历,只要满足 n u m s [ i − 1 ] + n u m s [ i − 2 ] > n u m s [ i ] nums[i - 1] +nums[i - 2] > nums[i] nums[i−1]+nums[i−2]>nums[i] 的第一个周长就是最大周长(排序后(两边之差小于第三边)必定满足)
3.代码
class Solution {
public int largestPerimeter(int[] nums) {
Arrays.sort(nums);
int i;
for (i = nums.length - 1;i >= 2;i--){
if (nums[i - 1] + nums[i - 2] > nums[i]){
return nums[i - 1] + nums[i - 2] + nums[i];
}
}
return 0;
}
}
三、561. 数组拆分 I
1.题目
给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。
返回该 最大总和 。
2.分析
- 举个例子:
- 从例子可以发现,要想数对的较小值的总和尽可能大,就要在
m
i
n
(
a
,
b
)
min(a,b)
min(a,b) 时,尽可能将数组中较大的值保留下来。
- 如果最大值和最小值比较,则保留下来的一定是最小值。
- 如果最大值和第二大的值比较,则可以保留下来第二大的值。
- 所以,只需要将排序后的数组,每两个元素为一对,取较小值的总和,得到的总和就是最大总和。
- 即:遍历排序后的数组,累加偶数位下标对应的值。
3.代码
class Solution {
public int arrayPairSum(int[] nums) {
Arrays.sort(nums);
int i,ans = 0;
for (i = 0;i < nums.length;i += 2){
ans += nums[i];
}
return ans;
}
}
四、881. 救生艇
1.题目
第 i 个人的体重为 people[i],每艘船可以承载的最大重量为 limit。
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit。
返回载到每一个人所需的最小船数。(保证每个人都能被船载)。
2.分析
- 排序后,双指针遍历
对数组 i n t [ ] p e o p l e int[] people int[]people 进行排序,再进行遍历。
分别用 i i i 和 j j j 标记数组两边的元素,如果符合 p e o p l e [ j ] + p e o p l e [ i ] < = l i m i t people[j] + people[i] <= limit people[j]+people[i]<=limit,说明可以2人一艘船。否则,只能体重较重的人一艘船。 - 注意遍历的边界:
- 如下图的情况,当 i = j i=j i=j 时,说明最后剩下一个人没上船,所以要将计数 c o u n t count count 加1
3.代码
class Solution {
public int numRescueBoats(int[] people, int limit) {
Arrays.sort(people);
int i = 0,j = people.length - 1,count = 0;
while (i < j){
//小于等于limit,则i++,j--(2人一艘船)
//大于limit,则j--(一人一艘船)
if (people[j] + people[i] <= limit){
i++;
}
j--;
count++;
}
return i == j ? ++count : count;
}
}
五、324. 摆动排序 II
1.题目
给你一个整数数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]… 的顺序。
你可以假设所有输入数组都可以得到满足题目要求的结果。
2.分析
- 将原数组克隆出一个新数组, n u m s . c l o n e ( ) ; nums.clone(); nums.clone();,并对新数组进行排序。
- 将新数组看成两部分,一部分从下标 j = ( l e n g t h − 1 ) > > 1 j = (length - 1) >> 1 j=(length−1)>>1 位置开始,另一部分从下标 k = l e n g t h − 1 k = length - 1 k=length−1 开始。
- 最后,遍历原数组,逆序插入值。当下标为偶数,将新数组下标 j j j 对应的值存到原数组中, j j j 自减;当下标为奇数,将新数组下标 k k k 对应的值存到原数组中, k k k 自减。
3.代码
class Solution {
public void wiggleSort(int[] nums) {
int i,length = nums.length;
int[] nums_copy = nums.clone();
Arrays.sort(nums_copy);
int j = (length - 1) >> 1,k = length - 1;
//将数组分成两部分,逆序插入
for (i = 0;i < length;i++){
if ((i & 1) == 0){
nums[i] = nums_copy[j--];
} else {
nums[i] = nums_copy[k--];
}
}
}
}
六、455. 分发饼干
1.题目
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
2.分析
- 将胃口数组 i n t [ ] g int[] g int[]g 以及饼干数组 i n t [ ] s int[] s int[]s 进行排序
- 优先将饼干满足胃口小的,这样得到满足的数量就是最多的。
3.代码
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int kid = 0,cookie = 0;
//先满足胃口小的,再满足胃口大的
while (kid < g.length && cookie < s.length){
if (g[kid] <= s[cookie]){
kid++;
}
cookie++;
}
return kid;
}
}
七、1827. 最少操作使数组递增
1.题目
给你一个整数数组 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 的数组是严格递增的一种特殊情况。
2.分析
- 因为这里不打算修改数组中的元素,所以定义了一个变量 m a x max max 来存储上一个元素的值(有可能是存储上一个元素修改过的值)
- 遍历数组,如果当前元素比 m a x max max 大时,说明还保持着严格递增,直接 c o n t i n u e continue continue 进入下一轮循环。
- 如果当前元素 < = m a x <=max <=max,则计算当前元素自增到等于 m a x + 1 max + 1 max+1,需要自增多少次,累加到变量 c o u n t count count,循环结束后返回。
3.代码
class Solution {
public int minOperations(int[] nums) {
int i,count = 0;
//较大值
int max = nums[0];
for (i = 1;i < nums.length;i++){
if (nums[i] > max){
max = nums[i];
continue;
}
max++;
count += max - nums[i];
}
return count;
}
}
八、945. 使数组唯一的最小增量
1.题目
给你一个整数数组 nums 。每次 move 操作将会选择任意一个满足 0 <= i < nums.length 的下标 i,并将 nums[i] 递增 1。
返回使 nums 中的每个值都变成唯一的所需要的最少操作次数。
2.分析
- 数组唯一的最小增量,其实可以解读为:数组排序后,最少操作使数组递增。
- 所以只要将数组排序后,再以上一题同样的方法来计算操作次数即可。
3.代码
class Solution {
public int minIncrementForUnique(int[] nums) {
Arrays.sort(nums);
int i,count = 0;
//较大值
int max = nums[0];
for (i = 1;i < nums.length;i++){
if (nums[i] > max){
max = nums[i];
continue;
}
count += ++max - nums[i];
}
return count;
}
}
九、611. 有效三角形的个数
1.题目
给定一个包含非负整数的数组,你的任务是统计其中可以组成三角形三条边的三元组个数。
2.分析
- 对数组进行排序。
- 确定一条最长边 i i i,再令另外两条边分别从 l = 0 , r = i − 1 l = 0,r = i - 1 l=0,r=i−1 开始遍历。
- 如果判断出现了
n
u
m
s
[
l
]
+
n
u
m
s
[
r
]
>
n
u
m
s
[
i
]
nums[l] + nums[r] > nums[i]
nums[l]+nums[r]>nums[i],那么
l
l
l 和
r
r
r
之间的元素也必定满足这个条件,不用再遍历这些元素,可以直接累加: c o u n t + = r − l ; count += r - l; count+=r−l;,累加后 r r r 左移一位。否则, l l l 右移一位。
3.代码
class Solution {
public int triangleNumber(int[] nums) {
Arrays.sort(nums);
int i,count = 0;
for (i = nums.length - 1;i >= 2;i--){
int l = 0,r = i - 1;
while (l < r){
if (nums[l] + nums[r] > nums[i]){
count += r - l;
r--;
} else {
l++;
}
}
}
return count;
}
}