【java实现】leetcode_413.等差数列划分--LinkedList公式计数和差分+计数(动态规划)

题目描述

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

例如,[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

来源:力扣(LeetCode)

题目大意

给定一个数组找到这个数组中的等差数列

等差数列:三个或以上元素之间差值相同的数列

思路描述

LinkedList公式计数法:

时间复杂度:O(n), 空间复杂度O(n)

思想:遍历一次数组,找到数组中的所有最长等差数列,再使用 等差数列中的子等差数列遵循的规律可得出答案。

具体做法

  1. 找到数组中最长的等差数列list
  2. list存放到LinkedList中
  3. list的长度为标准找到这个等差数列可以获得的所有子等差数列
  4. 将所有子等差数列计数到ans

注:一个等差数列中的子等差数列个数应为
s u m = ∑ i = 0 n − 2 i sum=\sum_{i=0}^{n-2}i sum=i=0n2i
( 其中n为等差数列长度,sum为子等差数列个数)

差分+计数(动态规划)

时间复杂度:O(n), 空间复杂度O(1)

思想:使用动态规划解决这个问题可以将空间复杂度降为O(1)此时nums变为dp数组

我们观察上述等差数列子等差数列的个数变化规律可以发现子等差数列个数为也是等差数列情况且d=1

dp数组中的每一项为当前项的数值增加量
例如:nums=[1,2,3,4]的dp=[0,0,1,2];1和2为子等差数列增加量

故状态转移方程为: dp[i] = dp[i-1]+1 if nums[i]-nums[i-1]==nums[i-1]-nums[i-2] else 0

具体做法:

  1. 创建计数值ans,当前数的等差数列增加量addNum
  2. 从下标为2开始遍历判断状态转移方程
  3. 如果有不符合状态转移方程的就重新开始计数增加量addNum
  4. 重复2和3操作直到得到整个dp数组
  5. ans计数所有的dp值

代码

LinkedList公式计数

class Solution {
	    public int numberOfArithmeticSlices(int[] nums) {
	    	
	    	
	    	int ans=0;
	    	//1:找到数组中最长的等差数列list
	    	for(int i=0;i<nums.length-2;i++){
	    		if(nums[i]-nums[i+1]==nums[i+1]-nums[i+2]){
	    			//2:将list存放到LinkedList中
	    			LinkedList<Integer> list=new LinkedList<Integer>();
	    			for(;;){
	    				list.add(nums[i]);
	    				if(i>=nums.length-2||nums[i]-nums[i+1]!=nums[i+1]-nums[i+2]){
	    					list.add(nums[i+1]);
	    					break;
	    				}
	    				i++;
	    			}
	    			//3:以list的长度为标准找到这个等差数列可以获得的所有子等差数列
	    			for(int j=1;j<=list.size()-2;j++){
	    				//4:将所有子等差数列计数到ans中
	    				ans+=j;
	    			}
	    			
	    		}
	    	}
	    	return ans;

	    }
	}

运行结果:
在这里插入图片描述

差分+计数(动态规划)

class Solution {
	    public int numberOfArithmeticSlices(int[] nums) {
	    	//1>创建计数值ans,当前数的等差数列增加量addNum
	        int ans=0,addNum=0;
	        // 2. 从下标为2开始遍历判断状态转移方程
	        for(int i=2;i<nums.length;i++){
	           if(nums[i-2]-nums[i-1]==nums[i-1]-nums[i]){
	           	   //4. ans计数所有的dp值
	        	   ans+=++addNum;
	           }
	           // 3. 如果有不符合状态转移方程的就重新开始计数增加量addNum
	           else{
	        	   addNum=0;
	           }
	        }
	        return ans;

	    }
	}

运行结果
在这里插入图片描述

写在最后

今日感受

如果感觉写的还不错的话不妨分享给其他人,以求共同进步!

文章如有错误之处请指出,我会听取并改正!

特别说明:引用部分只用于学习无商业用途
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值