每日算法-250428
每日算法 - 2024年4月28日
记录今天完成的几道 LeetCode 算法题。
1877. 数组中最大数对和的最小值
题目描述:
思路
贪心策略。
解题过程
为了最小化所有数对和中的最大值,直观的想法是避免让两个较大的数相加。因此,最优策略是将数组中最小的元素与最大的元素配对,次小的元素与次大的元素配对,以此类推。这样可以使得每个数对的和相对均衡,从而让其中的最大和尽可能小。
具体步骤如下:
- 对数组
nums
进行升序排序。 - 使用双指针
left
和right
分别指向数组的开头和结尾。 - 初始化一个变量
ret
来记录遇到的最大数对和,初始值为 0。 - 当
left < right
时,持续循环:- 计算当前配对
nums[left] + nums[right]
的和。 - 更新
ret = Math.max(ret, nums[left] + nums[right])
。 - 将
left
指针右移一位 (left++
),right
指针左移一位 (right--
),考虑下一对元素。
- 计算当前配对
- 循环结束后,
ret
即为所求的最小的最大数对和。
复杂度
- 时间复杂度: O ( N log N ) O(N \log N) O(NlogN),主要开销在于对数组进行排序。
- 空间复杂度: O ( 1 ) O(1) O(1) 或 O ( log N ) O(\log N) O(logN),取决于排序算法所使用的额外空间(原地排序通常认为是 O ( 1 ) O(1) O(1) 额外空间)。
Code
class Solution {public int minPairSum(int[] nums) {Arrays.sort(nums);int ret = 0;int left = 0, right = nums.length - 1;while (left < right) {ret = Math.max(ret, (nums[left] + nums[right]));left++;right--;}return ret;}
}
881. 救生艇
题目描述:
思路
贪心策略。
解题过程
目标是使用最少的船只。每艘船最多载两人,且总重量不超过 limit
。为了最大化每艘船的利用率(即尽量让每艘船载两人),我们应该优先考虑最重的人。
具体步骤如下:
- 对
people
数组(代表每个人的体重)进行升序排序。 - 使用双指针
left
指向体重最轻的人,right
指向体重最重的人。 - 初始化船只数量
boats = 0
。 - 当
left <= right
时,持续循环(<=
是为了处理最后只剩一人的情况):- 每次循环代表需要派遣一条新船,因此
ret++
。 - 让最重的人 (
people[right]
) 上船。 - 检查当前最轻的人 (
people[left]
) 是否能和这位最重的人同乘一条船,即判断people[left] + people[right] <= limit
。 - 如果可以同乘 (
people[left] + people[right] <= limit
),那么最轻的人也上船,将left
指针右移一位 (left++
)。 - 无论最轻的人是否能上船,最重的人都已经确定要上这条船了,所以将
right
指针左移一位 (right--
)。
- 每次循环代表需要派遣一条新船,因此
- 循环结束后,
ret
即为所需的最小船只数量。
复杂度
- 时间复杂度: O ( N log N ) O(N \log N) O(NlogN),主要开销在于排序。
- 空间复杂度: O ( 1 ) O(1) O(1) 或 O ( log N ) O(\log N) O(logN),取决于排序算法使用的额外空间。
Code
class Solution {public int numRescueBoats(int[] people, int limit) {Arrays.sort(people);int left = 0, right = people.length - 1;int ret = 0;while (left <= right) {int light = people[left];int weight = people[right];ret++;right--;if (light + weight <= limit) {left++;}}return ret;}
}
2592. 最大化数组的伟大值
题目描述:
思路
贪心策略。
解题过程
题目要求找到数组 nums
的一个排列 perm
,使得满足 nums[i] < perm[i]
的索引 i
的数量最大化。这个最大数量就是数组的“伟大值”。
一个有效的贪心策略是:
- 对原数组
nums
进行升序排序。 - 我们希望为尽可能多的
nums[i]
找到一个比它大的nums[j]
来作为perm[i]
。为了给后面的nums
元素留下更多(可能更大)的选择,对于当前的nums[i]
,我们应该寻找满足nums[j] > nums[i]
的最小的nums[j]
来进行配对。 - 使用双指针
i
和j
来实现这个过程:- 指针
i
:指向当前需要寻找配对的元素nums[i]
。 - 指针
j
:指向可用于配对的候选元素nums[j]
。
- 指针
- 初始化
i = 0
,j = 1
,以及伟大值计数greatness = 0
。 - 当
j
未越界 (j < nums.length
) 时,持续循环:- 如果
nums[i] < nums[j]
: 找到了一个有效的配对。nums[j]
可以作为nums[i]
的perm[i]
。增加伟大值greatness++
。同时移动两个指针i++
和j++
,表示nums[i]
和nums[j]
都已被使用,接下来考虑nums[i+1]
和nums[j+1]
。 - 如果
nums[i] >= nums[j]
: 说明nums[j]
不够大,不能与nums[i]
配对。我们需要一个更大的元素来配对nums[i]
。因此,保持i
不动,只移动j
指针 (j++
),去寻找下一个可能满足条件的nums[j]
。
- 如果
- 循环结束后,
greatness
即为最大化的伟大值。
复杂度
- 时间复杂度: O ( N log N ) O(N \log N) O(NlogN),主要开销在于排序。
- 空间复杂度: O ( 1 ) O(1) O(1) 或 O ( log N ) O(\log N) O(logN),取决于排序算法使用的额外空间。
Code
import java.util.Arrays;class Solution {public int maximizeGreatness(int[] nums) {// 1. 对数组排序Arrays.sort(nums);int n = nums.length;int greatness = 0; // 记录伟大值int i = 0; // 指向需要被配对的元素 nums[i]int j = 1; // 指向用于配对的候选元素 nums[j]// 2. 使用双指针寻找配对while (j < n) {if (nums[i] < nums[j]) {// 找到有效配对 (nums[i], nums[j])greatness++;i++; // 移动 i,考虑下一个需要配对的元素j++; // 移动 j,考虑下一个候选元素} else {// nums[j] 不够大,不能配对 nums[i]// 保持 i 不动,移动 j 寻找更大的候选元素j++;}}// 3. 返回结果return greatness;}
}