題目來源:力扣
題目介紹
如果一個數列至少有三個元素,並且任意兩個相鄰元素之差相同,則稱該數列爲等差數列。
========================================================
示例:
A = [1, 2, 3, 4]
返回: 3, A 中有三個子等差數組: [1, 2, 3], [2, 3, 4] 以及自身 [1, 2, 3, 4]。
=======================================================
審題:
對於這道題, 我們首先提供一種易於理解, 但時間複雜度較高的方法.
我們可以計算出所有子序列S[i, j]是否是等差數列, 然後累計其中爲等差數列的個數. 如果我們已知子序列S[i, j]是否是等差數列, 則不能判斷子序列S[i, j+1]是否是等差數列. 因此, 我們可以先計算所有長度爲3的子序列是否是等差數列, 然後一次計算所有長度爲4, …5, n的子序列是否是等差數列.
class Solution {
public int numberOfArithmeticSlices(int[] A) {
boolean[][] S = new boolean[A.length][A.length];
int total = 0;
//basecase , 判斷長度爲3的數列是否是等差數列
for(int i = 0; i < A.length-2; i++){
if(A[i+1]-A[i] == A[i+2]-A[i+1]){
S[i][i+2] = true;
total++;
}
}
for(int len = 4; len <= A.length; len++){
for(int i = 0; i <= A.length-len; i++){
int j = i + len -1;
if(S[i][j-1] && A[j]-A[j-1] == A[j-1]-A[j-2]){
S[i][j] = true;
total++;
}
else
S[i][j] = false;
}
}
return total;
}
}
複雜度分析
不難看出, 該方法時間複雜度與空間複雜度均爲.
實際上, 爲了計算所有等差數列的個數, 我們可以優化上述代碼, 將空間複雜度由降爲. 如果當前A[i, j]爲等差數列, 則我們可以往下判斷A[i, j+1]是否是等差數列, 如果A[i, j]不是等差數列, 則A[i, j+1], …A[i, n]都不是等差數列.
class Solution {
public int numberOfArithmeticSlices(int[] A) {
int total = 0;
for(int i = 0; i < A.length-2; i++){
for(int len = 2; len < A.length-i; len++){
if(A[i+len]-A[i+len-1] == A[i+len-1] - A[i+len-2])
total++;
else
break;
}
}
return total;
}
}
動態規劃算法
考慮, 如果我們已知以A[i]結尾的等差數列的個數, 我們能否推導出以A[i+1]結尾的等差數列的個數. 事實上非常容易, 如果A[i+1] - A[i] = A[i]-A[i-1], 那麼所有以A[i+1]結尾的等差數列此時在增加了一個元素A[i+1]後仍然是等差數列, 而A[i-1], A[i], A[i+1]此時也構長一個等差數列, 因此以A[i+1]結尾的等差數列的個數等於以A[i]結尾的等差數列的個數+1. 而如果A[i+1]-A[i] != A[i]-A[i-1], 則以A[i+1]結尾的等差數列個數爲1.
我們不難寫出該動態規劃算法的實現:
class Solution {
public int numberOfArithmeticSlices(int[] A) {
//S[j]表示以j結尾的等差序列個數
//如果A[j+1] - A[j] = A[j] - A[j-1] , S[j+1] = S[j] + 1
//else S[j+1] = 0;
if(A.length < 3)
return 0;
int total = 0;
int[] S = new int[A.length];
if(A[2]-A[1] == A[1]-A[0]){
S[2] = 1;
total += S[2];
}
for(int i = 3; i < A.length; i++){
if(A[i] - A[i-1] == A[i-1] - A[i-2]){
S[i] = S[i-1] + 1;
total += S[i];
}
}
return total;
}
}
不難分析發現, 該算法的時間複雜度與空間複雜度均爲.由於以A[i+1]結尾的等差數列個數只有以A[i]結尾的等差數列個數相關, 因此我們可以考慮進行狀態壓縮, 將空間複雜度降爲
class Solution {
public int numberOfArithmeticSlices(int[] A) {
if(A.length < 3)
return 0;
int total = 0;
int prev = 0;
if(A[2]-A[1] == A[1]-A[0]){
prev = 1;
total += prev;
}
for(int i = 3; i < A.length; i++){
if(A[i] - A[i-1] == A[i-1] - A[i-2]){
prev = prev + 1;
total += prev;
}
else
prev = 0;
}
return total;
}
}