题目:
给出一个n个数字的序列,求所有长度大于等于k的连续子段中,子段数字和最大可以是多少。
连续子段指的是序列中一段连续的数字。子段数字和指的是子段中所有数字相加的和。
关键:求长度大于等于k的最大连续子段数字和
方法一:双指针
左指针和右指针都置于起点,序列中的每个数字都可以作为子段的起点,当第一个数字作为起点,右指针向右移动,保存子段和直到子段长度大于等于k时,开始维护子段和的最大值,当右指针指向末尾时,寻找以第一个数字作为起点的子段结束,左指针右移,重置右指针和sum,开始寻找以下一个数字作为起点的子段,重复以上步骤,直到遍历完整个序列
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param n int整型 * @param k int整型 * @param a int整型一维数组 * @return long长整型 */ public long solve (int n, int k, int[] a) { // write code here int l=0,r=0; long sum=0; long res=Integer.MIN_VALUE; //每个数字都可以作为起点 while(l<n&&r<n){ //计算子段数字和 sum+=a[r]; //当长度大于等于k时,更新最大值 if(r-l+1>=k) res=Math.max(res,sum); r++; //下一个数字作为起点,重置子段和为0 if(r==n){l++;r=l;sum=0;} }return res; } }
复杂度:
时间复杂度:一层循环,线性时间复杂度
空间复杂度:只使用了几个额外的辅助变量,额外空间为常数级,
方法二:动态规划
表示以结尾的最大子序列和
- 子段长度最小为k,因此先计算前k个数字的和初始化
- 状态转移方程:
- 找出即为最大子段和
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param n int整型 * @param k int整型 * @param a int整型一维数组 * @return long长整型 */ public long solve (int n, int k, int[] a) { // write code here long[]dp=new long[n-k+1];//dp[i]表示以a[i+k-1]结尾的子段和最大值 long sum=0; for(int i=0;i<k;i++)sum+=a[i];//计算以a[k-1]结尾的子段和,初始化dp[0] dp[0]=sum; long res=dp[0]; for(int i=1;i<dp.length;i++){ //长度大于k的第一个子段和需要特殊处理,在是否减去a[0]之间取最大值 if(i==1)dp[i]=Math.max(dp[i-1]+a[i+k-1],dp[i-1]+a[i+k-1]-a[0]); else//如果子段长度最小值是1,则在本身与本身加上dp[i-1]之间取最大值,否则为上一个数字结尾的最大子段和加上本身 dp[i]=(k==1)?Math.max(a[i+k-1],dp[i-1]+a[i+k-1]):dp[i-1]+a[i+k-1]; res=Math.max(res,dp[i]);//维护最大值 } return res; } }
复杂度:
时间复杂度:最多遍历序列一次,时间复杂度为
空间复杂度:数组大小不超过n,空间复杂度为