每日算法 - 250530
记录一下今天完成的LeetCode算法题目,包含思路、解题过程、复杂度分析和代码实现。
3128. 直角三角形
题目
思路
数组
解题过程
显而易见的是,我们枚举中间的顶点最好计算。当我们的中间顶点是1时,它能够组成的直角三角形的个数就是这一行除了它以外的1的个数乘上这一列除了它以外的1的个数。
复杂度
- 时间复杂度: O ( N M ) O(NM) O(NM)
- 空间复杂度: O ( N + M ) O(N + M) O(N+M)
Code
class Solution {
public long numberOfRightTriangles(int[][] grid) {
long ret = 0;
int r = grid.length;
int c = grid[0].length;
int[] r1 = new int[r];
int[] c1 = new int[c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (grid[i][j] == 1) {
r1[i]++;
c1[j]++;
}
}
}
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (grid[i][j] == 1) {
ret += (long)(r1[i] - 1) * (c1[j] - 1);
}
}
}
return ret;
}
}
303. 区域和检索 - 数组不可变
思路
前缀和
解题过程
我们可以在初始化的时候将
nums
预处理成一个前缀和数组dp
。dp[i]
表示[0, i]
区间的和。那么sumRange(left, right)
方法只需返回dp[right] - dp[left - 1]
就可以得到[left, right]
区间的和了。
需要注意的是:当left=0
时,dp[right]
就是[0, right]
的和,此时不能减去dp[left - 1]
,可以直接返回dp[right]
。
复杂度
- 时间复杂度: 初始化是 O ( N ) O(N) O(N),
sumRange
是 O ( 1 ) O(1) O(1) - 空间复杂度: O ( N ) O(N) O(N) (如果创建新的
dp
数组) 或 O ( 1 ) O(1) O(1) (如果在原数组上修改,不计输入数组本身)
Code
class NumArray {
private int[] prefixSums;
public NumArray(int[] nums) {
prefixSums = new int[nums.length];
prefixSums[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
prefixSums[i] = prefixSums[i - 1] + nums[i];
}
}
public int sumRange(int left, int right) {
if (prefixSums.length == 0 || left < 0 || right >= prefixSums.length || left > right) {
return 0;
}
if (left == 0) {
return prefixSums[right];
}
return prefixSums[right] - prefixSums[left - 1];
}
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* int param_1 = obj.sumRange(left,right);
*/
3427. 变长子数组求和
题目
思路
前缀和
解题过程
- 首先,预处理得到前缀和数组
dp
,其中dp[i]
表示原数组nums
中区间[0, i]
的元素之和。- 遍历数组
nums
,对于每个索引i
:
- 题目描述指出,对于索引
i
,子数组nums[start...i]
的长度为nums[i]
。- 这意味着
i - start + 1 = nums[i]
,所以start = i - nums[i] + 1
。- 该子数组
nums[actualStart...i]
的和可以通过前缀和数组计算:dp[i] - (actualStart == 0 ? 0 : dp[actualStart - 1])
。- 将所有这些子数组的和累加起来即为最终答案。
复杂度
- 时间复杂度: O ( N ) O(N) O(N)
- 空间复杂度: O ( N ) O(N) O(N)
Code
class Solution {
public int subarraySum(int[] nums) {
int sum = 0, n = nums.length;
int[] dp = new int[n];
dp[0] = nums[0];
for (int i = 1; i < n; i++) {
dp[i] = dp[i - 1] + nums[i];
}
for (int i = 0; i < n; i++) {
int start = Math.max(0, i - nums[i]);
sum += (start == 0) ? dp[i] : dp[i] - dp[start - 1];
}
return sum;
}
}
2874. 有序三元组中的最大值 II(复习)
题目
这是第二次写这道题了,已经算是掌握了,就不再多说了,详细题解见每日算法-250527
代码
class Solution {
public long maximumTripletValue(int[] nums) {
long ret = 0;
int n = nums.length;
int[] suffixMax = new int[n];
suffixMax[n - 1] = nums[n - 1];
for (int i = n - 2; i >= 0; i--) {
suffixMax[i] = Math.max(suffixMax[i + 1], nums[i]);
}
int privMax = nums[0];
for (int i = 1; i < n - 1; i++) {
ret = Math.max(ret, ((long) (privMax - nums[i]) * suffixMax[i + 1]));
privMax = Math.max(privMax, nums[i]);
}
return ret;
}
}