每日算法篇(二)之等差数列划分

783 阅读2分钟

这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战

今天一上班就开始摸鱼,惯例每日一题算法(平时不发是因为平时的题不会),今天力扣的每日一题是中等题,看着好像能做出来。

微信图片_20210707232446.jpg

题目

如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。

  • 例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。 给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。

子数组 是数组中的一个连续序列。

示例一

输入: nums = [1,2,3,4]
输出: 3
解释: nums 中有三个子等差数组:[1, 2, 3][2, 3, 4][1,2,3,4] 自身。

示例二

输入: nums = [1]
输出: 0

逻辑思路

  1. 等差数列:相邻的两个参数的差相等,公式:d = a(n) - a(n-1)
  2. 极端校验:数组长度小于3
  3. 看到这道题,第一想法是动态规划(薄弱的算法领域里面最熟悉的)
    • 单个:判断当前数据是否能与前面两个数据形成新的等差数列(最小单位:三个)
    • 整体数组:判断当前数据,与前面的等差数列能否形成大型的等差数列
    • 统计数据:new 一个数组,指针所向则为当前最多子数组个数

实现

class Solution {
     //判断一个数组是否等差,我们采用动态规划去做
	 public int numberOfArithmeticSlices(int[] nums) {
		 //dp[n]代表从零到n具有的等差数据个数
		 int len=nums.length;
		 if(len<3) return 0;
		 int[] dp=new int[len+1];
		 //确定初始值
		 if(nums[1]-nums[0]==nums[2]-nums[1]) dp[3]=1;
		 
		 for(int i=2;i<len-1;i++){
			 //如果有新的元素加进来,我们要做以下判断,如果可以和之前元素等差,那么结果加一,不然不进行改变
			 //同时要判断判断元素是否可以和以前的等差数组是否可以等差,可以的话继续加
			 if(nums[i+1]-nums[i]==nums[i]-nums[i-1]){
				 int count=1;
				 //在这里进行第二次for循环判断,得到新元素对于之前等差数列的影响
				 for(int j=i;j>1;j--){
					 if(nums[j]-nums[j-1]==nums[j-1]-nums[j-2]){
						 count++;
					 }
                     else break;
				 }
				 
				 dp[i+2]=dp[i+1]+count;
			 }
			 else dp[i+2]=dp[i+1];
		 }
		 
		 return dp[len];

	 }

优化

虽然说实现是实现了,但是相对来说时间复杂度太高,光是判断等差就需要两个for循环,O(n²)+初始值;优化的空间很大,特别是用动态规划的话,第二次for循环的判断和初始值可以修改优化

class Solution {
    public int numberOfArithmeticSlices(int[] nums) {
        int length = nums.length;
        if (length<3){
            return 0;
        }
        int d = nums[1]-nums[0];
        int t =0,ans =0;
        for (int i = 2;i<length;++i){
            if (nums[i]-nums[i-1] == d){
                ++t;
            }else {
                d= nums[i]-nums[i-1];
                t =0;
            }
            ans +=t;
        }
        return ans;
    }
}

复杂度分析

  • 时间复杂度:O(n)O(n),其中 nn 是数组 nums 的长度。
  • 空间复杂度:O(1)O(1)。