Medium
题目描述
如果一个数字序列由至少两个元素组成,且每两个连续元素之间的差值都相同,则称该序列为等差数列。更正式地,当且仅当对于所有有效的 i,都有 s[i+1] - s[i] == s[1] - s[0] 时,序列 s 才是等差数列。
例如,这些都是等差数列:
- 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,其中 answer[i] 为 true 当且仅当子数组 nums[l[i]], nums[l[i]+1], …, nums[r[i]] 可以重新排列形成等差数列。
示例 1:
输入: nums = [4,6,5,9,3,7], l = [0,0,2], r = [2,3,5]
输出: [true,false,true]
解释:
第 0 个查询,子数组是 [4,6,5]。可以重新排列为 [6,5,4],这是一个等差数列。
第 1 个查询,子数组是 [4,6,5,9]。无法重新排列为等差数列。
第 2 个查询,子数组是 [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
- -10^5 <= nums[i] <= 10^5
解题思路
解题思路
这道题要判断给定范围内的子数组能否重新排列成等差数列。关键在于理解等差数列的性质:
- 核心观察:一组数字能组成等差数列当且仅当排序后的序列是等差数列
- 等差数列判断:排序后相邻元素的差值必须相等
解法分析
方法一:排序 + 逐一检查(推荐)
- 对每个查询范围提取子数组
- 排序后检查相邻元素差值是否相等
- 时间复杂度较低,实现简单
方法二:数学优化
- 利用等差数列性质:最大值、最小值、长度确定差值
- 检查是否存在重复元素且能形成完整等差数列
- 适用于特定场景,但实现复杂度较高
算法步骤:
- 遍历每个查询 [l[i], r[i]]
- 提取对应子数组并排序
- 检查排序后数组是否为等差数列:
- 长度至少为2
- 计算公差 d = sorted[1] - sorted[0]
- 验证所有相邻元素差值都等于 d
这种方法直观易懂,代码简洁,适合解决该问题。
代码实现
class Solution {
public:
vector<bool> checkArithmeticSubarrays(vector<int>& nums, vector<int>& l, vector<int>& r) {
vector<bool> result;
for (int i = 0; i < l.size(); i++) {
vector<int> subarray(nums.begin() + l[i], nums.begin() + r[i] + 1);
sort(subarray.begin(), subarray.end());
bool isArithmetic = true;
if (subarray.size() >= 2) {
int diff = subarray[1] - subarray[0];
for (int j = 2; j < subarray.size(); j++) {
if (subarray[j] - subarray[j-1] != diff) {
isArithmetic = false;
break;
}
}
}
result.push_back(isArithmetic);
}
return result;
}
};
class Solution:
def checkArithmeticSubarrays(self, nums: List[int], l: List[int], r: List[int]) -> List[bool]:
result = []
for i in range(len(l)):
subarray = nums[l[i]:r[i]+1]
subarray.sort()
is_arithmetic = True
if len(subarray) >= 2:
diff = subarray[1] - subarray[0]
for j in range(2, len(subarray)):
if subarray[j] - subarray[j-1] != diff:
is_arithmetic = False
break
result.append(is_arithmetic)
return result
public class Solution {
public IList<bool> CheckArithmeticSubarrays(int[] nums, int[] l, int[] r) {
List<bool> result = new List<bool>();
for (int i = 0; i < l.Length; i++) {
int[] subarray = new int[r[i] - l[i] + 1];
Array.Copy(nums, l[i], subarray, 0, subarray.Length);
Array.Sort(subarray);
bool isArithmetic = true;
if (subarray.Length >= 2) {
int diff = subarray[1] - subarray[0];
for (int j = 2; j < subarray.Length; j++) {
if (subarray[j] - subarray[j-1] != diff) {
isArithmetic = false;
break;
}
}
}
result.Add(isArithmetic);
}
return result;
}
}
var checkArithmeticSubarrays = function(nums, l, r) {
const result = [];
for (let i = 0; i < l.length; i++) {
const subarray = nums.slice(l[i], r[i] + 1);
subarray.sort((a, b) => a - b);
let isArithmetic = true;
if (subarray.length >= 2) {
const diff = subarray[1] - subarray[0];
for (let j = 2; j < subarray.length; j++) {
if (subarray[j] - subarray[j-1] !== diff) {
isArithmetic = false;
break;
}
}
}
result.push(isArithmetic);
}
return result;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(m × k × log k) | 其中 m 是查询次数,k 是子数组平均长度,排序需要 O(k log k) |
| 空间复杂度 | O(k) | 需要额外空间存储子数组进行排序 |