每日算法-250423
每日算法学习记录 - 2023年4月25日
记录今天学习和解决的几道 LeetCode 算法题。
LeetCode 3301. 高度互不相同的最大塔高和
题目描述
思路
贪心
解题过程 (基于提供的代码逻辑)
代码首先对
maximumHeight
数组进行排序。然后从后往前遍历。
- 初始化总和
sum
为排序后最后一个元素(被视为最高的塔)。- 从倒数第二个元素开始向前遍历 (
i
从n-2
到0
)。- 如果
maximumHeight[i] < maximumHeight[i + 1]
(排序后),则当前塔的高度可以直接设为maximumHeight[i]
并加入sum
。- 否则(即
maximumHeight[i] >= maximumHeight[i + 1]
),为了满足某种递减约束(比如高度必须比后一个塔低至少1),将当前塔的高度强制设为maximumHeight[i + 1] - 1
,并将其加入sum
。同时更新maximumHeight[i]
的值为maximumHeight[i + 1] - 1
以影响下一个迭代。- 在每次设置高度后,检查
maximumHeight[i]
是否小于等于 0。如果是,则认为无法构成有效序列,返回 -1。- 遍历完成后,返回计算出的总和
sum
。
复杂度
- 时间复杂度: 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 ( N ) O(N) O(N) (取决于排序算法实现)。通常记为 O ( 1 ) O(1) O(1) 辅助空间。
Code
class Solution {public long maximumTotalSum(int[] maximumHeight) {Arrays.sort(maximumHeight);int n = maximumHeight.length;long sum = maximumHeight[n - 1];for (int i = n - 2; i >= 0; i--) {if (maximumHeight[i] < maximumHeight[i + 1]) {sum += maximumHeight[i];} else {sum += maximumHeight[i + 1] - 1;maximumHeight[i] = maximumHeight[i + 1] - 1;}if (maximumHeight[i] <= 0) {return -1;}}return sum;}
}
LeetCode 945. 使数组唯一的最小增量
题目描述
思路
贪心
解题过程
目标是使得数组中所有元素唯一,并且总的增量最小。
- 排序:首先对数组
nums
进行升序排序。排序后,重复的元素或需要调整的元素会相邻出现。- 遍历与调整:从数组的第二个元素 (
i = 1
) 开始遍历。- 检查冲突:比较当前元素
nums[i]
与其前一个元素nums[i - 1]
。- 处理冲突:如果
nums[i - 1] >= nums[i]
,说明nums[i]
的值小于或等于前一个元素,违反了唯一性(或者说,为了后续元素更容易唯一化,我们希望它至少比前一个大1)。此时,需要将nums[i]
增加到nums[i - 1] + 1
。- 计算增量:需要增加的值是
(nums[i - 1] + 1) - nums[i]
。将这个增量累加到总计数count
中。- 更新数组:将
nums[i]
的值更新为nums[i - 1] + 1
。这一步是关键,因为它确保了当前元素相对于 调整后 的前一个元素是唯一的,并且为后续元素的调整奠定了基础(保证了数组在该点及之前的部分局部有序且满足nums[i] > nums[i-1]
)。- 遍历结束后,
count
即为所需的最小总增量。为什么要加上
>
的判断(即nums[i-1] >= nums[i]
)?因为nums[i-1]
可能在之前的步骤中被增加过,即使原始的nums[i]
大于原始的nums[i-1]
,增加后的nums[i-1]
仍可能大于或等于当前的nums[i]
。
复杂度
- 时间复杂度: O ( N log N ) O(N \log N) O(NlogN),瓶颈在于排序。
- 空间复杂度: O ( 1 ) O(1) O(1) (辅助空间)。
Code
class Solution {public int minIncrementForUnique(int[] nums) {int count = 0;Arrays.sort(nums);for (int i = 1; i < nums.length; i++) {if (nums[i - 1] >= nums[i]) {count += nums[i - 1] + 1 - nums[i];nums[i] = nums[i - 1] + 1;}}return count;}
}
LeetCode 1846. 减小和重新排列数组后的最大元素
题目描述
思路
贪心
解题过程
目标是在满足以下两个条件的前提下,最大化数组中的最大元素:
- 数组第一个元素必须是 1。
- 任意相邻两个元素的差的绝对值不能超过 1 (
abs(arr[i] - arr[i-1]) <= 1
)。为了让最终的最大元素尽可能大,我们应该让数组元素尽可能地形成一个递增序列,且相邻元素差尽可能为 1。
- 排序:首先对数组
arr
进行升序排序。这使得我们可以更容易地处理相邻元素的差值约束。- 设置首元素:根据条件 1,将排序后的数组第一个元素
arr[0]
强制设置为 1。- 遍历与调整:从数组的第二个元素 (
i = 1
) 开始遍历。- 应用约束:根据条件 2,
arr[i]
必须满足arr[i] <= arr[i-1] + 1
。由于数组已经排序,arr[i] >= arr[i-1]
总是成立的,所以我们只需要确保arr[i]
不会比arr[i-1] + 1
大太多。如果arr[i]
比arr[i-1] + 1
大(即arr[i] - arr[i-1] > 1
),为了满足约束且尽可能保持arr[i]
的值大,我们将arr[i]
减小到arr[i-1] + 1
。如果arr[i] - arr[i-1] <= 1
,则arr[i]
保持不变,因为它已经满足条件。- 结果:经过这样的调整,数组满足了所有条件,并且每个元素都被设置为在满足约束下的最大可能值。因此,数组的最后一个元素
arr[n-1]
就是可以得到的最大元素。
复杂度
- 时间复杂度: O ( N log N ) O(N \log N) O(NlogN),主要是排序的开销。
- 空间复杂度: O ( 1 ) O(1) O(1) (辅助空间)。
Code (Java)
class Solution {public int maximumElementAfterDecrementingAndRearranging(int[] arr) {Arrays.sort(arr);int n = arr.length;arr[0] = 1;for (int i = 1; i < n; i++) {if (arr[i] - arr[i - 1] > 1) {arr[i] = arr[i - 1] + 1;}}return arr[n - 1];}
}
LeetCode 3143. 正方形中的最多点数(复习)
题目描述
复习说明
这是第二次做这道题。这次做得更好,但仍然需要注意细节,比如坐标可能是负数,这会影响边界计算和点是否在正方形内的判断。使用 Math.abs()
处理坐标是关键。
详细题解可以参考之前的笔记:每日算法-250411
Code
class Solution {private int count = 0;public int maxPointsInsideSquare(int[][] points, String ss) {char[] s = ss.toCharArray();int left = 0, right = 0;for (int[] point : points) {right = Math.max(right, Math.max(Math.abs(point[0]), Math.abs(point[1])));}while (left <= right) {int mid = left + (right - left) / 2;if (check(points, mid, s)) {left = mid + 1;} else {right = mid - 1;}}return count;}private boolean check(int[][] arr, int len, char[] s) {int tmpCount = 0;int[] hash = new int[26];for (int i = 0; i < arr.length; i++) {int x = Math.abs(arr[i][0]), y = Math.abs(arr[i][1]);char ch = s[i];if (x <= len && y <= len) {hash[ch - 'a']++;if (hash[ch - 'a'] > 1) {return false;}tmpCount++;}}count = Math.max(count, tmpCount);return true;}
}