⭐LeetCode周赛 3468. 可行数组的数目——暴力与数学⭐
⭐LeetCode周赛 3468. 可行数组的数目——暴力与数学⭐
示例 1:
输入:original = [1,2,3,4], bounds = [[1,2],[2,3],[3,4],[4,5]]
输出:2
解释:
可能的数组为:
[1, 2, 3, 4]
[2, 3, 4, 5]
示例 2:
输入:original = [1,2,3,4], bounds = [[1,10],[2,9],[3,8],[4,7]]
输出:4
解释:
可能的数组为:
[1, 2, 3, 4]
[2, 3, 4, 5]
[3, 4, 5, 6]
[4, 5, 6, 7]
提示:
2 <= n == original.length <= 105
1 <= original[i] <= 109
bounds.length == n
bounds[i].length == 2
1 <= bounds[i][0] <= bounds[i][1] <= 109
题解:
暴力法+数学法 具体见代码注释
代码:
// 暴力 超时
// 思路为一旦copy[0]确定 则copy数组即确定 因各元素间距由original可提前算出
// 故仅对copy[0]的值进行模拟 从u0遍历到v0
// 同时判断按照上述情况得到的copy数组如copy[1] copy[2]等是否满足他们的ui和vi限制即可
// 即由于各元素间距固定 故多个需要遍历的变量可以变为进遍历单一变量copy[0] 再加以对所有可能的数组进行验证即可
class Solution1 {
public int countArrays(int[] original, int[][] bounds) {
int len = original.length;
int res = 0;
int[] next_len = new int[len];
for(int i=1;i<len;i++){
next_len[i] = original[i] - original[i-1];
}
int L = bounds[0][0];
int R = bounds[0][1];
while(L <= R){
int[] temp = new int[len];
temp[0] = L;
for(int i=1;i<len;i++){
temp[i] = temp[i-1] + next_len[i];
}
boolean flag = true;
for(int i=1;i<bounds.length;i++){
if(temp[i] >= bounds[i][0] && temp[i] <= bounds[i][1]){
continue;
}
else{
flag = false;
break;
}
}
if(flag){
res++;
}
L++;
}
return res;
}
}
// 数学 算出copy[0]的实际可取值范围即为关键
// 公式化简可知 copy[i] = copy[0] + di 即copy的任一元素均可由copy[0]推演得到
// 故 ui <= copy[i] <= vi ---> ui-di <= copy[0] <= vi-di
// 则上述式子即为copy[0]的取值范围限制 对所有情况的i均算出 取交集即可
class Solution {
public int countArrays(int[] original, int[][] bounds) {
int len = original.length;
// 先定义copy[0]取值范围为本身的限制 即此时为最宽泛情况
// 即先进行u0-d0 <= copy[0] <= v0-d0第一层限制
int L = bounds[0][0];
int R = bounds[0][1];
// 后面遍历bounds 依次得到ui和vi 对copy[0]区间进行缩小
for(int i=1;i<len;i++){
int di = original[i] - original[0];
int ui = bounds[i][0];
int vi = bounds[i][1];
L = Math.max(L,ui-di);
R = Math.min(R,vi-di);
}
// 若最后得到为负 则代表无符合题目条件的数组 故返回0
return R-L+1 > 0 ? R-L+1 : 0;
}
}