题目
题目会给出一串数字序列,我们的任务是获取其中满足等差数列的子串。因为要满足等差数列,所以子串长度至少为3。
我的思路
我的想法是,既然要看是不是等差数列,那么差值肯定是必须的啦。所以先计算差值得diff数组。
得到diff数组之后,我们可以清楚看到,有5个连续的-1。样例中,我们可以手工算出,长度为3的有4个,长度为4的有3个,长度为5的有2个,长度为6的有1个。诶,是不是很像累加呢?其实就可以用累加解决,得出5个连续相同差值,我们就累加到4,即得出n,累加到n-1。
这样我们的思路就很清晰了:
- 由输入数组得到差值数组diff
- 从差值数组中找到大于等于两个的连续相同差值,保存栈中(其实无所谓什么容器,只要能不覆盖存入即可,我只是用着方便)
- 从栈中读取所有的数值,减一后进行累加操作,然后合并结果
代码实现(Java)
public int numberOfArithmeticSlices(int[] A) {
int numOfAS = 0;
if(A.length != 0) {
int diff[] = getDifference(A);
Stack<Integer> stack = getConsecutiveNum(diff);
while(!stack.empty()) {
int consecutiveNum = stack.pop();
numOfAS += accumulate(consecutiveNum-1);
}
}
return numOfAS;
}
/**
* 获取连续相同的差值
* @param diff
* @return
*/
public Stack<Integer> getConsecutiveNum(int[] diff){
Stack<Integer> stack = new Stack<Integer>();
int count = 1;
for(int i = 0; i < diff.length - 1; i++) {
if( diff[i] == diff[i+1] ) {
count++;
} else {
if(count >= 2) {
stack.push(count);
count = 1;
}
}
}
//运行到最后时还需判断一次
if(count >= 2) {
stack.push(count);
}
return stack;
}
/**
* 获取公差
* @param A
* @return
*/
public int[] getDifference(int[] A) {
int[] diff = new int[A.length-1];
for(int i = 0; i < diff.length; i++) {
diff[i] = A[i] - A[i+1];
}
return diff;
}
/**
* 累加计算
* @param n
* @return
*/
public int accumulate(int n) {
int result = 0;
while(n != 0) {
result += n;
n--;
}
// System.out.println("result:" + result);
return result;
}
思考
我的方法其实是有点基于观察的,时间复杂度是O(n),但是可以看出系数应该是很大的。空间复杂度的话,讲道理还是开辟了不少空间,也是O(n)。
同时,这个方法还容易有坑,我调试了两次才过。第一次,是因为判断连续差值那边,运行到最后时漏了一个判断;第二次,没有考虑空数据集。
最后看了题解,大佬用了动态规划ac,贴上代码膜一下:
public class Solution {
public int numberOfArithmeticSlices(int[] A) {
int dp = 0;
int sum = 0;
for (int i = 2; i < A.length; i++) {
if (A[i] - A[i - 1] == A[i - 1] - A[i - 2]) {
dp = 1 + dp;
sum += dp;
} else
dp = 0;
}
return sum;
}
}
其他也还有不少不错的解法,大家也可以去Solution上看看。