力扣-1630. 等差子数组
1.题目介绍
题目地址(1630. 等差子数组 - 力扣(LeetCode))
https://leetcode.cn/problems/arithmetic-subarrays/
题目描述
如果一个数列由至少两个元素组成,且每两个连续元素之间的差值都相同,那么这个序列就是 等差数列 。更正式地,数列 s
是等差数列,只需要满足:对于每个有效的 i
, s[i+1] - s[i] == s[1] - s[0]
都成立。
例如,下面这些都是 等差数列 :
1, 3, 5, 7, 9 7, 7, 7, 7 3, -1, -5, -9
下面的数列 不是等差数列 :
1, 1, 2, 5, 7
给你一个由 n
个整数组成的数组 nums
,和两个由 m
个整数组成的数组 l
和 r
,后两个数组表示 m
组范围查询,其中第 i
个查询对应范围 [l[i], r[i]]
。所有数组的下标都是 从 0 开始 的。
返回 boolean
元素构成的答案列表 answer
。如果子数组 nums[l[i]], nums[l[i]+1], ... , nums[r[i]]
可以 重新排列 形成 等差数列 ,answer[i]
的值就是 true
;否则answer[i]
的值就是 false
。
示例 1:
[4,6,5,9,3,7]
[0,0,2]
[2,3,5]
[true,false,true]
[5,9,3,7] 。
[3,5,7,9] 。
示例 2:
输入:nums = [-12,-9,-3,-12,-6,15,20,-25,-20,-15,-10], l = [0,1,6,4,8,7], r = [4,4,9,7,9,10] 输出:[false,true,false,false,true,true]
提示:
n == nums.length
m == l.length
m == r.length
2 <= n <= 500
1 <= m <= 500
0 <= l[i] < r[i] < n
-105 <= nums[i] <= 105
2.题解
2.1暴力枚举
思路
很简单,将数组根据l和r的要求进行拆分排序,然后从头到尾进行遍历,判断是否为等差数组
代码
- 语言支持:C++
C++ Code:
class Solution {
public:
vector<bool> checkArithmeticSubarrays(vector<int>& nums, vector<int>& l,vector<int>& r) {
int m = l.size();
vector<bool> ans;
for (int i = 0; i < m; i++) {
vector<int> subNums(nums.begin() + l[i], nums.begin() + r[i] + 1);
sort(subNums.begin(), subNums.end());
int n = subNums.size();
bool flag = true;
if (n == 2) {
ans.push_back(flag);
continue;
}
int sub = subNums[1] - subNums[0];
for (int j = 2; j < n; j++) {
if (subNums[j] - subNums[j - 1] != sub) {
flag = false;
break;
}
}
ans.push_back(flag);
}
return ans;
}
};
复杂度分析
- 时间复杂度:每个子数组的排序操作为‘o(k log k)’,其中‘k 是子数组的长度。
由于总共有“m个查询,所以总时间复杂度为”o(m*k log k)”,最坏情况下为 。 - 空间复杂度:需要额外的空间来存储每个子数组,最坏情况下总空间复杂度为
。
这个解决方案对于给定的限制是高效的,因为 n 和 m 都是 500 以内,排序操作在这个范围内是可以接受的。
2.2 优化(判断等差数列——去除排序步骤)
思路
对于每一个子数组,我们考虑不进行排序判断其是否为等差数列
第一次遍历,确定其最大值,最小值;通过这两个值我们可以判断该数组如果为等差,那么他的公差为
代码
class Solution {
public:
vector<bool> checkArithmeticSubarrays(vector<int>& nums, vector<int>& l,vector<int>& r) {
int m = l.size();
vector<bool> ans;
for (int i = 0; i < m; i++) {
int start = l[i], end = r[i];
int n = end - start + 1; // 子数组总个数
int max_value = INT_MIN, min_value = INT_MAX;
bool isArithmetic = true;
// 子数组长度为2则必为等差数列
if(n == 2){
ans.push_back(isArithmetic);
continue;
}
// 遍历子数组,获得最大值,最小值
for(int j = start; j <= end; j++){
max_value = max(max_value, nums[j]);
min_value = min(min_value, nums[j]);
}
// 判断子数组是否为等差数列
if((max_value - min_value) % (n - 1) != 0){
isArithmetic = false;
ans.push_back(isArithmetic);
continue;
}
// 计算公差
int diff = (max_value - min_value) / (n - 1);
if(diff == 0){
ans.push_back(isArithmetic);
continue;
}
vector<bool> visitor(n, false); // 判断是否遇到过该数
// 遍历数组
for(int j = start; j <= end; j++){
if((nums[j] - min_value) % diff != 0){
isArithmetic = false;
break;
}
int pos = (nums[j] - min_value) / diff;
if(pos >= n || visitor[pos]){
isArithmetic = false;
break;
}
visitor[pos] = true;
}
ans.push_back(isArithmetic);
}
return ans;
}
};
复杂度分析
- 时间复杂度:
每次查询中,我们需要遍历子数组找最小值和最大值,这需要 ”时间。·然后我们需要再次遍历子数组来判断每个数字的位置,最坏情况下总共需要 。
所以每个查询的时间复杂度是“o(k)”。
总共有“m个查询,所以总时间复杂度为’o(m*k)’最坏情况下为 - 空间复杂度:
主要是用于记录每个数字位置的布尔数组‘seen’,其大小为子数组的长度,最坏情况下为“o(n)”。总的空间复杂度为 'o(n) 。
分类:
力扣
, 数据结构与算法 / 数组
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了