413.等差數列劃分
題目:
如果一個數列 至少有三個元素 ,並且任意兩個相鄰元素之差相同,則稱該數列爲等差數列。
例如,[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) dp[i]的定義;(2)狀態;(3)選擇;
dp[i]的定義:表示第i個元素包括第i個元素之前的所有等差數列。
狀態:選擇了這個元素,可以組成更長的等差數組。或者選擇了這個元素,不能組成更長的等差數組。
選擇:只能選擇下一個。
所以動態規劃的方程爲:
dp[i] = dp[i-1]+1 //如果能組成更長的等差數組
dp[i] = 0 //如果組不成更長的等差數組
如果能組成更長的等差數組:那麼num[i]-num[i-1] == num[i-1]-num[i-2]
否則的話不能組成。所以動態規劃方程就出來了。
需要注意的是,一般情況下,在開始動態規劃的時候,需要定義初始狀態,這道題中初始狀態都是0,所以可以直接去掉。具體看代碼提示。
代碼
class Solution {
public int numberOfArithmeticSlices(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
//這裏應該有初始狀態.即dp[0]=dp[1]=dp[2] = 0,可以不用羅列,具體原因:
//在定義數組的時候,基本類型的數組初始化爲零值.int的話爲0,boolean的話是false。
for (int i = 2; i < n; i++) {
if (nums[i]-nums[i-1] == nums[i-1]-nums[i-2]){
dp[i] = dp[i-1]+1;
}else {
dp[i] = 0;
}
}
return Arrays.stream(dp).sum();
}
}
解法二:查分+計數
leetcode的官方題解。
感覺講的太複雜了,代碼其實挺簡單的。
public int numberOfArithmeticSlices(int[] nums) {
int n = nums.length;
if (n == 1) {
return 0;
}
int d = nums[0] - nums[1], t = 0;
int ans = 0;
//因爲等差數列的長度至少爲3,所以可以從i=2開始枚舉
for (int i = 2; i < n; i++) {
if (nums[i-1] - nums[i] == d){
++t;
}else{
d = nums[i-1] - nums[i];
t= 0;
}
ans+=t;
}
return ans;
}
就是在循環數組中的每個數,多設置一個重置位,當不滿足等差定義的時候,將重置位置爲0,否則的話重置位++,每次循環把重置位和ans相加即可。