数组求和 / 最大值 / 最小值 一行代码拿到数组的和 最大元素最小元素

本文介绍了如何使用JavaScript的reduce方法一行代码实现数组的求和、找出数组中的最大值和最小值,对比了传统循环实现的方式,展示了更简洁的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一行代码数组求和 取出最大值和最小值

求和:

在我们对数组求和的时候通常都是用循环来实现

示例:

let arr = [1,2,3,4,5];
// 求和
let getSum = 0;
arr.forEach(item => {
	getSum += item;
	return getSum
}) 
console.log(getSum)
// 打印的结果是 15

这里我们可以使用 reduce 方法来更简便的实现 上方代码的功能 只需要一行代码就可以实现哦!

console.log(arr.reduce((a,b) => a + b))   // 打印的结果也是 15

获取数组中的最大值和最小值

获取最大值也需要用循环来实现 我们先看一下循环的代码

示例

// 最大值
	let newArr = [3,2,1,5,4];
	let max = newArr[0];
	newArr.forEach(item => {
		if(max < item){
			max = item
		}
		return max
	})
	console.log(max)  // 打印的结果是  5

我们在用 reduce 来看一下简洁的写法

// reduce 最大值
	console.log(newArr.reduce((a,b) => a > b ? a : b))
	// 打印的结果 是 5
	
// reduce 获取最小值
	console.log(newArr.reduce((a,b) => a < b ? a : b))
	// 打印的结果是  1

这样对比起来是不是 觉得 reduce 方法 更好用呢 赶快试起来把!!

<think>好的,我现在需要解决用户的问题:如何用C++双端队列(deque)来计算字符串中所有长度为k的连续子串的陡峭值之。首先,我得理解什么是陡峭值。根据问题描述,陡峭值可能是指子串中相邻字符的绝对差之。例如,子串“abc”的陡峭值是|a-b| + |b-c|。但用户没有明确定义,所以我需要假设这一点,或者可能是指其他定义。但通常这类问题中的陡峭值确实是相邻字符差的绝对值,所以先假设这个定义。 接下来,我需要找出所有长度为k的连续子串,计算每个子串的陡峭值,然后将它们加起来。直接的方法是遍历每个子串,逐个计算,但这样的话时间复杂度会是O(nk),当k较大时可能不够高效。用户提到要使用双端队列,可能希望优化时间复杂度,所以需要考虑如何利用双端队列来减少重复计算。 首先,考虑直接法:对于每个起始位置i,从i到i+k-1的字符,计算相邻差的绝对值之。例如,对于子串s[i...i+k-1],陡峭值是Σ_{j=i}^{i+k-2} |s[j] - s[j+1]|。每个子串需要计算k-1个差的绝对值,然后求和。总共有n-k+1个子串,所以总时间是O(nk),这可能在k接近n时变为O(n&sup2;),效率不高。 为了优化,可能需要找到相邻子串之间的重叠部分,利用之前的计算结果。例如,子串从i开始从i+1开始,它们共享中间的k-2个差值。例如,子串i的陡峭值是|s[i]-s[i+1]| + |s[i+1]-s[i+2]| + ... + |s[i+k-2]-s[i+k-1]|,而子串i+1的陡峭值则是|s[i+1]-s[i+2]| + ... + |s[i+k-1]-s[i+k]|。所以,子串i+1的陡峭值等于子串i的陡峭值减去|s[i]-s[i+1]|,再加上|s[i+k-1]-s[i+k]|。这样,每个子串的陡峭值可以在O(1)时间内计算出来,前提是已经知道前一个子串的值。这样,总时间可以优化到O(n),因为只需要遍历一次,每个步骤处理常数时间。 那么,如何应用双端队列呢?双端队列通常用于维护一个窗口内的元素,例如在滑动窗口最大值问题中。但这里的计算似乎不需要双端队列的典型应用场景。可能用户的意图是使用双端队列来维护当前窗口中的差值,或者某种结构来帮助快速计算陡峭值。 或者,可能用户误以为双端队列是必要的,但其实这里可以通过滑动窗口的差值累加来优化,而不必使用双端队列。例如,维护一个当前陡峭值总,当窗口滑动时,减去左边界的差值,加上右边界的差值。这样,每个窗口的陡峭值总可以在O(1)时间内计算,而初始计算第一个窗口需要O(k)时间,总时间为O(n)。 假设这样,那么步骤如下: 1. 计算初始窗口的陡峭值总:遍历第一个窗口的k-1个相邻差,求和2. 对于后续每个窗口,总 = 前一个总 - 左边界的差值(即第一个元素的差值) + 右边新加入的差值(即新窗口最后一个元素的差值)。 3. 将所有窗口的总累加起来。 这样,不需要双端队列,只需要维护当前总即可。但用户明确要求使用双端队列,所以可能需要考虑其他方式。 另一种可能性是,当窗口滑动时,维护窗口中每个差值,并且用双端队列来跟踪这些差值,以便在窗口移动时快速调整总。例如,每次窗口滑动,左边移出一个差值,右边移入一个新的差值,总相应变化。这种情况下,双端队列可能用来存储窗口内的差值序列,每次左边弹出,右边压入。但这样其实直接使用一个数组或列表存储差值的效果类似,而双端队列的优点是可以在两端高效操作。 所以,可能的步骤是: - 预处理整个字符串,计算所有相邻字符的绝对差值,得到一个数组diff,其中diff[i] = |s[i] - s[i+1]|,i从0到n-2。 - 每个长度为k的子串对应k-1个连续的diff元素。例如,子串从i开始的窗口对应diff[i]到diff[i + k - 2]。 - 因此,问题转化为在diff数组中找到所有长度为k-1的连续子数组的总。 - 如果k=1的话,可能每个子串的陡峭值为0,但题目中k应该是至少2才有意义。需要处理k=1的特殊情况? 假设k>=2,那么问题转化为计算所有长度为(k-1)的连续子数组的总。这可以用滑动窗口求和的方法:初始窗口为sum(diff[0..k-2]),之后每次滑动窗口,减去diff[left],加上diff[right],其中left从0开始,right每次递增。总的总即为所有子串的陡峭值之。 这时候,这个过程不需要双端队列,只需要一个滑动窗口的即可。但用户要求使用双端队列,所以可能需要将diff数组中的元素存储在双端队列中,每次窗口滑动时,从队尾移除旧元素,加入新元素。但这样可能并没有带来时间上的优势,反而增加复杂度。 或者,可能用户希望用双端队列来维护窗口中的某些信息,例如最大值或其他,但问题中的陡峭值之是所有差值的,所以总只依赖于总,不需要其他信息。因此,可能用户的意图是使用滑动窗口的,而双端队列可能并不必要,但用户可能有特定需求。 或者,可能用户的问题中存在其他条件,例如陡峭值的定义不同,或者有其他的约束,比如需要处理某些特定操作。例如,如果陡峭值不是相邻差的,而是其他需要动态维护的结构,这时候可能需要双端队列。例如,如果陡峭值指的是窗口内的最大差减去最小差,这时候可能需要维护窗口的最大值最小值,这种情况下双端队列可能有用。但根据用户的问题描述,可能并非如此。 回到问题,用户可能混淆了滑动窗口双端队列的应用场景。例如,在滑动窗口求最大值时,双端队列用来维护可能的最大值候选。但在这个问题中,求的是总,不需要这样的结构。因此,可能用户希望用双端队列来实现滑动窗口,但实际上可能不需要。 综上,可能用户的意图是希望用滑动窗口的方法来优化计算,而双端队列可能并不是必须的。或者,可能用户误解了双端队列的作用。此时,正确的做法是使用滑动窗口来维护当前窗口的陡峭值之,从而在O(n)时间内解决问题。 但用户明确要求使用双端队列编写C++代码,所以需要想如何将双端队列应用到这里。可能的思路是,将当前窗口的差值存储在双端队列中,当窗口滑动时,从队列前端移除旧的差值,后端加入新的差值,同时维护总。例如,初始时,队列中保存前k-1个差值,总为它们的。每次滑动窗口,弹出队列前端的差值,减去总,然后从后端压入新的差值,加到总中。同时,将每个窗口的总累加到总结果中。这样,双端队列的作用是维护当前窗口的差值序列,允许前端后端的快速操作。 这可能是一个可行的方案。例如: 步骤: 1. 预处理得到diff数组,每个diff[i]是相邻字符的绝对差。 2. 如果k==1,则每个子串的陡峭值为0,总为0。 3. 否则,窗口长度是k-1,在diff数组中需要取所有长度为k-1的连续子数组4. 使用双端队列来保存当前窗口内的diff元素5. 初始化时,将前k-1个diff元素加入队列,并计算初始sum。 6. 然后,滑动窗口,每次移动一步: a. 移除队列前端的元素,sum -= 该元素。 b. 将下一个diff元素加入队列后端,sum += 该元素。 c. 将当前sum累加到总中。 7. 总共有 (n -k +1)个子串,每个对应一个窗口,所以滑动次数是 (n-1) - (k-1) +1 = n -k +1次。但初始窗口之后,需要滑动 (n -k)次,每次滑动得到一个新的窗口。例如,初始窗口是0到k-2,滑动一次得到1到k-1,依此类推,直到最后窗口是 (n-1 - (k-1)) ) 到 n-2,也就是窗口数目是 (n -1 - (k-1) +1 ) = n -k +1个。 所以,总共有n -k +1个窗口,每个对应一个子串。在滑动过程中,每个窗口的会被累加到总结果中。 使用双端队列来保存当前窗口的diff元素,这允许在滑动时快速从前面删除元素,后面添加元素。但实际上,我们并不需要存储所有元素,因为sum已经维护了当前的。双端队列在这里可能只是用于跟踪窗口中的元素,但实际计算时并不需要,因为sum已经足够。因此,这可能是一种冗余的做法,但为了满足用户的要求,必须使用双端队列。 综上,代码的大致结构是: - 计算diff数组。 - 处理k=1的特殊情况。 - 否则,初始化双端队列,将前k-1个diff元素入队,计算sum。 - 总结果初始化为sum。 - 然后,对于每个可能的滑动步骤(从i=1到i = n -k),执行: - 弹出队列前端的元素,sum -= 该元素。 - 将diff[i + k -2]加入队列后端,sum +=该元素。 - 总结果 += sum。 - 返回总结果。 但需要仔细验证索引是否正确。例如,初始窗口是diff[0]到diff[k-2],共有k-1个元素。然后,每次滑动,窗口右移一位,即新窗口是diff[i]到diff[i + k -2],其中i从1开始,直到i +k -2 <=n-2 → i <=n -k. 例如,当i从0到 (n -k +1 -1) →i最大为n -k。例如,当i是窗口的起始索引,则窗口的结束索引是i +k-2。因此,当i的取值范围是0到 (n -1) - (k-1) )= n -k。所以,总共有n -k +1个窗口。 例如,假设n=5,k=3,那么diff的长度是4(索引0~3),窗口长度k-1=2,所以初始窗口是0~1,然后1~22~3。总共有4-2+1=3个窗口,即i从0到2(当i=2,窗口是2~3)。 所以,在代码中,初始窗口是前k-1个元素,sum是它们的。总结果初始化为sum。然后,滑动次数是n -k次(因为总共有n -k +1个窗口,已经处理了一个初始的,剩下n -k次滑动)。 例如,当n=5,k=3,初始处理后,剩下2次滑动。总共有3个窗口。 因此,循环的次数应该是n -k次。例如,在代码中: 初始总结果 = sum. 然后,循环从i=1到i= (n -k) 次: 每次处理窗口i对应的diff数组的起始位置i,窗口的diff元素是i到i +k-2. 所以,对于每个滑动步骤,我们需要取出队列前端元素(即i-1处的diff元素),然后加入队列后端的新元素是i +k -1处的diff元素?或者可能是i +k-2? 这里可能容易出错。例如,初始窗口是0到k-2,窗口内的元素数目是k-1。滑动一次后,窗口是1到k-1(即增加了k-1的位置)。因此,每次滑动后,新窗口的结束位置是原来的结束位置+1。所以,在滑动时,新加入的diff元素是原来的结束位置+1,即对于初始窗口结束于k-2,滑动后加入的是k-1的diff元素。所以,在滑动时,每次需要移除队首元素(旧窗口的起始元素),然后添加新窗口的结束元素(即旧窗口的结束位置+1的diff元素)。 因此,在循环中,从i=1到i= (n -k): 每次窗口的起始位置是i,对应的diff数组的起始元素是i,结束元素是i +k-2。但每次滑动时,窗口的结束元素应该是 i +k-2。例如,初始窗口i=0,结束于k-2。下一次i=1,结束于k-1,直到i= (n-k),结束于 (n -k) +k-2 =n-2,刚好是diff数组的最后一个元素。 因此,在滑动过程中,新加入的diff元素的位置是 (i-1) +k-2 +1 = (i-1) +k-1 = i +k-2. 所以,每次滑动时,需要将diff[i +k-2 +1 -1]?或者可能是diff[i +k-1 -1]? 可能我在这里搞混了索引。需要仔细分析: 初始窗口是i=0的窗口,对应的diff元素是0到k-2,共有k-1个元素。总是sum(diff[0..k-2])。 当窗口滑动一次到i=1,对应的diff元素是1到k-1。总等于sum - diff[0] + diff[k-1]. 同理,当窗口滑动到i=2,总是sum - diff[1] + diff[k]. 因此,在每次滑动时,需要减去的是窗口的起始位置的diff[i-1],然后加上新的结束位置的diff[i +k-2]. 或者,更准确地说,当前窗口的起始位置是i,对应的diff数组中的起始索引是i,结束索引是i +k-2。当窗口滑动到i+1时,起始索引是i+1,结束索引是i+1 +k-2 = i +k-1。所以,需要减去diff[i],加上diff[i +k-1]. 因此,在滑动时,每次移动后,需要从队列中移除diff[i],然后添加diff[i +k-1]. 但这里,i的循环变量可能需要调整。例如,当初始窗口是i=0,处理完后,i从0开始循环到n -k次? 或者,初始窗口是0,然后滑动n -k次,得到n -k +1个窗口。例如: 初始sum是sum0,对应i=0。 然后,滑动次数为n -k次,对应i=1到i= n -k。 所以,在循环中,我们需要处理滑动次数为n -k次。 例如,当n=5(diff数组长度是4),k=3。初始窗口i=0,对应的sum是diff[0]+diff[1]。然后滑动两次: 第一次滑动,i=1,sum = sum -diff[0] + diff[2]. 第二次滑动,i=2,sum= sum_prev -diff[1] +diff[3]. 所以,总共有n-k=5-3=2次滑动,加上初始窗口,总共有3个窗口。 所以在代码中,总结果的初始值为sum。然后循环运行 (n -k)次,每次滑动添加新的diff元素。 现在的问题是,如何确保在滑动过程中,新的diff元素的索引是正确的。例如,当滑动第j次(从0到n-k-1次),那么新的diff元素的索引应该是初始窗口结束索引+1 +j?或者需要重新计算。 或者,当初始窗口的结束索引是k-2,每次滑动时,新的diff元素的位置是k-2 +1 + j ? 可能这个思路比较复杂。或许更直接的做法是,维护当前窗口的起始结束位置,每次滑动时,起始位置加1,结束位置加1。然后,每次移除起始位置-1的元素,加入结束位置的元素。 例如,初始时,start=0,end=k-2。然后,每次滑动后,start=1, end=k-1。直到 end超过diff数组最大索引。 但如何用双端队列来跟踪这些元素?可能需要队列中的元素是当前窗口的diff数组中的元素。例如,初始队列包含diff[0]到diff[k-2]。每次滑动时,队列弹出最前面的元素(即start=0的元素),然后将diff[end+1]加入队列,其中end初始是k-2,每次滑动后end是k-1等。 因此,在代码中,双端队列deque存储的是当前窗口内的所有diff元素。初始时,将这些元素全部入队,并计算sum。 之后,每次滑动窗口,弹出队首元素,sum减去该值,然后将下一个diff元素(即end+1)入队,sum加上该值,然后将sum累加到总结果中。 这样,总结果初始为第一个窗口的sum,然后在每次滑动后,加上新的sum。总共有n -k次滑动,每次得到一个新的sum,所以总结果 = 初始sum + sum滑动后的各次sum。例如,初始sum是窗口0的sum,之后每个滑动后的sum是新窗口的sum,共有n -k次这样的滑动,总共有n -k +1个sum,即初始sum加上n -k次sum。这可能对吗? 例如,在初始时,总结果 = sum。然后,每次滑动后,总结果 += sum(滑动后的sum)。例如,当k=3,n=5,初始sum是窗口0的,滑动两次,每次得到新sum,总结果是初始sum + sum1 + sum2。这样,总共有三个窗口的sum之。 但原问题中的要求是所有子串的陡峭值之,即每个窗口的sum是子串的陡峭值,所以总结果应该是所有这些sum的。初始窗口的sum是第一个子串的,然后每个滑动后的窗口sum是后续的子串的,所以总结果应该是所有窗口sum的总。 但根据上述步骤,初始总结果设为sum(第一个窗口的),然后在每次滑动后,sum是当前窗口的,加到总结果中。这样总结果是正确的。 例如,初始sum是第一个窗口的,总结果初始为sum。滑动一次后,sum更新为第二个窗口的,总结果 += sum。滑动第二次后,sum是第三个窗口的,总结果 += sum。这样,总结果就是三个窗口的。 这样是正确的。 所以,代码的大致结构是: 计算diff数组。 if k == 1: 返回0. 否则: sum_initial = sum of diff[0..k-2] total = sum_initial deque存储diff[0]到diff[k-2] 然后,循环 (n -k)次: removed = deque.front() deque.pop_front() sum_current -= removed new_diff = diff[...] // 需要确定新diff的位置 deque.push_back(new_diff) sum_current += new_diff total += sum_current 这里的问题是如何确定new_diff的位置。假设初始窗口结束于索引k-2,那么每次滑动后,新的diff元素是k-1, k, ...,直到n-2. 例如,初始窗口之后,第一次滑动需要添加diff[k-1],第二次滑动添加diff[k], 依此类推,直到添加diff[n-2]. 因此,在循环中,需要从i=1到i= (n -k),每次新的diff元素的索引是 (k-2 + i). 或者,更准确地说,初始窗口的结束索引是k-2。每次滑动,窗口的结束索引增加1。所以,在滑动第j次(j从1到n -k),新加入的diff元素的索引是k-2 + j. 例如,当j=1(第一次滑动),新加入的是k-2 +1 =k-1. 当j=2,k-2+2=k. 直到最后一次滑动,j =n -k →新加入的索引是k-2 + (n -k) =n-2. 所以,新加入的diff元素的索引是 (初始窗口结束索引) + j →j从1到n -k次滑动。初始窗口结束索引是k-2. 但如何跟踪这个索引? 可以维护一个变量,例如current_end =k-2,每次滑动时,current_end +=1,然后新加入的diff元素是diff[current_end+1]? 或者,维护一个变量current_pos,初始为k-2,每次滑动时,current_pos+1,取diff[current_pos+1]. 例如: 初始窗口结束后,current_end =k-2. 第一次滑动时,current_end +=1 →k-1,取diff[k-1]. 第二次滑动时,current_end =k →取diff[k]. 直到 current_end+1 <=n-2 →也就是current_end <=n-3. 但总共有n -k次滑动,所以初始窗口结束后,滑动次数是n -k次,此时current_end的初始是k-2,每次滑动current_end增加1,所以最后一次current_end= (k-2) + (n -k) )=n-2 -k +k =n-2. 这样,每个滑动步骤对应的新diff元素是current_end+1吗? 例如,当滑动第j次时,新加入的diff元素的索引是current_end_initial +j. 或者,可能更简单的方式是,维护一个变量 right,初始为 k-1,即初始窗口结束后,下一个要加入的diff元素是k-1. 在每次滑动时: 移除队列左边的元素(即旧的左边界),sum -=它. 将diff[right]加入队列,sum +=diff[right]. 然后,right +=1. 这样,循环次数为 (n -k)次,因为从right =k-1到 right= n-2,总共有 (n-2) - (k-1) +1 =n -k次步骤. 例如,当k=3,n=5: right初始是3-1=2. n-2=3. 从23,共两次步骤,即n -k=5-3=2次。 是的,这样正确。 所以,在代码中: 初始化sum_current为sum_initial =sum(diff[0]..diff[k-2]). total =sum_current. deque 填入diff[0]到diff[k-2]. 然后,设置right =k-1. 循环次数是n -k次: for(int i=0; i <n -k; i++){ int removed = deque.front(); deque.pop_front(); sum_current -= removed; int new_diff = diff[right]; deque.push_back(new_diff); sum_current += new_diff; total += sum_current; right++; } 这样,每次循环处理一个滑动步骤,将窗口右移一位,加入新的diff[right],并移除旧的左边元素。 这样,总结果计算正确。 现在,关于双端队列的使用,这里确实用到了双端队列的前端弹出后端压入的操作,因此符合用户的要求。 接下来,编写C++代码: 步骤: 1. 输入字符串s,整数k。 2. 计算diff数组: vector<int> diff; for(int i=0; i<s.size()-1; i++){ diff.push_back(abs(s[i] - s[i+1])); } 3. 处理特殊情况: if(k ==1){ 每个子串的陡峭值为0,所以总为0。 } else if (k > s.size()) { 没有长度为k的子串,总为0。 } else { 继续处理。 } 但k的有效范围是1<=k <=s.size(). 当k>s.size()时,没有子串,返回0。 当k==1,总为0。 否则: 计算diff数组,如果diff的长度(s.size()-1) < (k-1),则不可能有长度为k-1的窗口,所以当s.size()-1 >=k-1 ? 例如,k=3,s的长度至少为3,则s.size()-1=2 >=k-1=2 →成立。否则,当s.size()<k的话,无法形成任何子串,所以返回0. 所以,代码中需要处理当s.size()<k时返回0. 综上: int sumSteepness(string s, int k) { int n = s.size(); if(k ==1 || k >n) return 0; vector<int> diff; for(int i=0; i <n-1; i++){ diff.push_back(abs(s[i] - s[i+1])); } int m = diff.size(); if(k-1 >m) return 0; // 当k-1> m时,无法形成窗口 deque<int> dq; int sum =0; for(int i=0; i <k-1; i++){ dq.push_back(diff[i]); sum += diff[i]; } int total =sum; int right =k-1; for(int i=0; i < (n -k); i++){ // 循环次数是n -k次,因为总共有n -k +1个窗口,已处理第一个,剩下的n -k次 if(right >= diff.size()) break; // 防止越界,但在循环条件中已经确保right不会超过? int removed = dq.front(); dq.pop_front(); sum -= removed; int new_diff = diff[right]; dq.push_back(new_diff); sum += new_diff; total += sum; right++; } return total; } 但需要注意,当k-1 ==0时(即k=1),已经被前面的条件过滤掉了。 例如,当k=2,则k-1=1,窗口长度1。当s的长度是2,那么diff的长度是1,可以形成一个窗口。循环次数是n -k =2-2=0,所以直接返回sum=diff[0]. 这正确,因为所有子串的陡峭值之是diff[0]. 再例如,k=3,s的长度是5。则diff的长度是4。k-1=2,所以初始窗口是diff[0],diff[1]。然后循环n -k=5-3=2次: 第一次循环,right=2,加入diff[2]. sum变为 sum -diff[0]+diff[2]. total加上这个sum. 第二次循环,right=3,加入diff[3]. sum变为 sum_prev -diff[1] +diff[3]. total加上这个sum. 最终,总是初始sum(diff0+diff1) + (diff1+diff2) + (diff2+diff3). 即每个窗口的分别为: 窗口0-1 →sum0+1. 窗口1-2 →sum1+2. 窗口2-3 →sum2+3. 总是 (0+1)+(1+2)+(2+3) =3+3+5=11? 或者,原题中的每个子串是长度为k的连续子串,对应的陡峭值是该窗口内的diff之。例如,当s的长度是5,k=3,每个子串的长度是3,对应的diff数目是2,即每个窗口的陡峭值是两个diff之。总共有5-3+1=3个子串,每个的相加。 所以,代码中的计算是正确的。 综上,这样的代码应该能够正确计算总,并且使用了双端队列。因此,用户的请求得到满足。</think>要计算字符串中所有长度为 $k$ 的连续子串的陡峭值之,可以利用滑动窗口双端队列优化计算过程。陡峭值定义为子串相邻字符绝对差之,例如子串 $s[i..i+k-1]$ 的陡峭值为 $\sum_{j=i}^{i+k-2} |s[j] - s[j+1]|$。 ### 方法思路 1. **预处理差值数组**:先计算字符串中每对相邻字符的绝对差值,得到数组 $\text{diff}$。 2. **滑动窗口求和**:使用双端队列维护当前窗口内的差值。初始时,计算第一个窗口的,之后每次滑动窗口时,移除左边界差值并加入右边界新差值,更新当前窗口3. **总累加**:将所有窗口的累加,得到最终结果。 ### C++代码实现 ```cpp #include <string> #include <vector> #include <deque> #include <cmath> using namespace std; int calculateSteepnessSum(const string& s, int k) { int n = s.size(); if (k <= 0 || k > n) return 0; if (k == 1) return 0; // 陡峭值为0的情况 vector<int> diff; for (int i = 0; i < n - 1; ++i) { diff.push_back(abs(s[i] - s[i + 1])); } int m = diff.size(); if (k - 1 > m) return 0; // 无法形成任何子串 deque<int> dq; int current_sum = 0; // 初始化窗口 for (int i = 0; i < k - 1; ++i) { dq.push_back(diff[i]); current_sum += diff[i]; } int total = current_sum; int right = k - 1; // 下一个要加入的差值的索引 // 滑动窗口,处理剩余的子串 for (int i = 0; i < n - k; ++i) { if (right >= m) break; int removed = dq.front(); dq.pop_front(); current_sum -= removed; int new_diff = diff[right]; dq.push_back(new_diff); current_sum += new_diff; total += current_sum; ++right; } return total; } ``` ### 代码说明 1. **预处理差值数组**:遍历字符串生成相邻字符的绝对差值数组 $\text{diff}$,时间复杂度 $O(n)$。 2. **窗口初始化**:将前 $k-1$ 个差值存入双端队列并计算初始,时间复杂度 $O(k)$。 3. **滑动窗口**:每次滑动移除队首元素并加入新元素,更新当前并累加到总,时间复杂度 $O(n)$。 4. **总时间复杂度**:$O(n)$,空间复杂度 $O(n)$(存储差值数组)。 ### 相关问题 1. 如何处理 $k=0$ 或 $k>n$ 的边界情况? 2. 如果陡峭值定义为最大绝对差而非总,如何修改算法? 3. 如何优化空间复杂度以不显式存储差值数组?[^1] [^1]: 可以通过实时计算差值并维护窗口来优化空间,将空间复杂度降至 $O(k)$。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值