等差数列划分 II - 子序列
难度:
标签:
题目描述
给你一个整数数组 nums
,返回 nums
中所有 等差子序列 的数目。
如果一个序列中 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该序列为等差序列。
- 例如,
[1, 3, 5, 7, 9]
、[7, 7, 7, 7]
和[3, -1, -5, -9]
都是等差序列。 - 再例如,
[1, 1, 2, 5, 7]
不是等差序列。
数组中的子序列是从数组中删除一些元素(也可能不删除)得到的一个序列。
- 例如,
[2,5,10]
是[1,2,1,2,4,1,5,10]
的一个子序列。
题目数据保证答案是一个 32-bit 整数。
示例 1:
输入:nums = [2,4,6,8,10] 输出:7 解释:所有的等差子序列为: [2,4,6] [4,6,8] [6,8,10] [2,4,6,8] [4,6,8,10] [2,4,6,8,10] [2,6,10]
示例 2:
输入:nums = [7,7,7,7,7] 输出:16 解释:数组中的任意子序列都是等差子序列。
提示:
1 <= nums.length <= 1000
-231 <= nums[i] <= 231 - 1
代码结果
运行时间: 259 ms, 内存: 0.0 MB
/*
题目思路:
1. 使用一个数组dp来记录以每个元素结尾的等差子序列的数目。
2. 使用一个HashMap数组dp来记录以每个元素结尾且公差为某值的等差子序列的数目。
3. 遍历每个元素,对于每个元素再遍历其之前的所有元素,计算公差。
4. 使用该公差更新dp数组。
5. 累加所有dp数组中的值,即为所求的等差子序列的数目。
6. 使用Java Stream API来实现遍历和累加。
*/
import java.util.HashMap;
import java.util.stream.IntStream;
public class ArithmeticSlicesStream {
public int numberOfArithmeticSlices(int[] nums) {
int n = nums.length;
if (n < 3) return 0;
HashMap<Integer, Integer>[] dp = IntStream.range(0, n)
.mapToObj(i -> new HashMap<Integer, Integer>())
.toArray(HashMap[]::new);
int[] total = {0};
IntStream.range(0, n).forEach(i -> {
IntStream.range(0, i).forEach(j -> {
long diff = (long) nums[i] - (long) nums[j];
if (diff <= Integer.MIN_VALUE || diff > Integer.MAX_VALUE) return;
int d = (int) diff;
int count = dp[j].getOrDefault(d, 0);
total[0] += count;
dp[i].put(d, dp[i].getOrDefault(d, 0) + count + 1);
});
});
return total[0];
}
}
解释
方法:
这个题解使用动态规划的方法来解决问题。主要思路如下:
1. 使用两个字典 left 和 right 分别记录每个数字最左边和最右边的出现位置。
2. 从右往左遍历数组,对于每个位置 i 上的数字 m:
- 更新 right[m],删除当前位置
- 枚举所有可能的等差数列的另外两个数 l 和 r,其中 m = (l + r) / 2
- 对于每个符合条件的 l 和 r,累加 dp[i][l] 的值到 dp[j][m] 上,其中 j 为 right[r] 中的每个位置
- 将 dp[i] 的所有值累加到答案 ans 上
- 将当前位置 i 加入到 left[m] 中
3. 最终返回 ans 即可
时间复杂度:
O(n^2)
空间复杂度:
O(n)
代码细节讲解
🦆
在动态规划的过程中,为何选择从右向左遍历数组?反向遍历对解题有何影响或优势?
▷🦆
解题中提到了动态规划数组dp[i][j],这里的j代表什么?是否公差?如何根据题目中的数组元素值和索引更新dp数组?
▷🦆
在生成可能的等差数列的两个数l和r时,为什么需要同时考虑从left和right字典生成数对?这种方法有什么优势?
▷🦆
算法实现中使用了两个字典left和right,这两个字典具体是如何在算法中使用和更新的?
▷相关问题
等差数列划分
如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。
- 例如,
[1,3,5,7,9]
、[7,7,7,7]
和[3,-1,-5,-9]
都是等差数列。
给你一个整数数组 nums
,返回数组 nums
中所有为等差数组的 子数组 个数。
子数组 是数组中的一个连续序列。
示例 1:
输入:nums = [1,2,3,4] 输出:3 解释:nums 中有三个子等差数组:[1, 2, 3]、[2, 3, 4] 和 [1,2,3,4] 自身。
示例 2:
输入:nums = [1] 输出:0
提示:
1 <= nums.length <= 5000
-1000 <= nums[i] <= 1000