黑白翻转-差分数组

943 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述

有n个黑白棋子,它们的一面是黑色,一面是白色。它们被排成一行,位置可以用标号1-n来表示。一开始,所有棋子都是黑色向上,有q次操作,每次操作将位置标号在区间 [L,R] 内的所有棋子翻转(原来黑色变白色,原来白色变黑色)。请在每次操作后,求这n个棋子中,黑色向上的棋子个数。

输入:

[[1,30],[21,40]]  //每次棋子翻转的区间
100               //棋子总数

输出:

70

二、思路分析

本题可以使用差分数组进行求解

对原数组相邻两项(j-1,j)作差即可得到原数组所对应的差分数组例如数组 [1,2,3,4,5] 对应的差分数组为 [1,1,1,1,1] ,想要从差分数组还原原数组,对差分数组求前缀和即可。

差分数组的性质:若想要对差分数组对应的原数组的某一区间施加一个增量,例如对区间 [l,r] 施加增量 inc ,则在差分数组中仅需对 d[l]+inc,对d[r+1]-inc。这样就可以将对于区间的修改转换为对数组两个位置的修改,并且这样的修改可以叠加。修改差分数组的时间复杂度为 O(1)。

本题中我们可以先定义一个大小为 n 的数组作为差分数组,遍历每次棋子翻转的区间,并对差分数组进行修改对d[l]+1,对d[r+1]-1,由于这种修改是可以叠加的,所以我们只需按照棋子翻转的区间依次修改差分数组即可。变换后对差分数组求前缀和即可得到由每个棋子被翻转的次数做组成的数组,并对数组中的每一项对2取余若为零则为黑色,否则为白色。

注意:

变换差分数组时改变的是d[l]和d[r+1]

三、代码

func BlackWhiteShift(shift [][]int, n int) int {
	d := make([]int, n+1)
	for _, v := range shift {
		d[v[0]-1] += 1
		d[v[1]] = 1
	}
	temp := make([]int, n)
	temp[0] = d[0]
	res := 0
	for i := 1; i < n; i++ {
		temp[i] = temp[i-1] + d[i]
	}
	for i := 0; i < n; i++ {
		if temp[i]%2 == 0 {
			res++
		}
	}
	return res
}

四、总结

本题使用差分数组对问题进行了简化,将修改数组的复杂度由 O(n) 降低为 O(1),并且也降低了时间复杂度。对差分数组求前缀和后,当数组中的元素为2的倍数时即此棋子翻转了偶数次所以还是黑色向上,当不是2的倍数时说明此棋子翻转了奇数次所以是白色向上。