如果数组的每一对相邻元素都是两个奇偶性不同的数字,则该数组被认为是一个 特殊数组 。
你有一个整数数组 nums
和一个二维整数矩阵 queries
,对于 queries[i] = [fromi, toi]
,请你帮助你检查
子数组
nums[fromi..toi]
是不是一个 特殊数组 。
返回布尔数组 answer
,如果 nums[fromi..toi]
是特殊数组,则 answer[i]
为 true
,否则,answer[i]
为 false
。
示例 1:
输入:nums = [3,4,1,2,6], queries = [[0,4]]
输出:[false]
解释:
子数组是 [3,4,1,2,6]
。2 和 6 都是偶数。
示例 2:
输入:nums = [4,3,1,6], queries = [[0,2],[2,3]]
输出:[false,true]
解释:
- 子数组是
[4,3,1]
。3 和 1 都是奇数。因此这个查询的答案是false
。 - 子数组是
[1,6]
。只有一对:(1,6)
,且包含了奇偶性不同的数字。因此这个查询的答案是true
。
提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^5
1 <= queries.length <= 10^5
queries[i].length == 2
0 <= queries[i][0] <= queries[i][1] <= nums.length - 1
第一种思路:
暴力解,对于每个 query,我们都遍历子数组来判断是否满足特殊数组的条件。
缺点:有点麻瓜,显然会超时。
时间复杂度:O(NQN)~ O(N^3)
空间复杂度:O(N)
第二种思路:
先找出所有连续的特殊数组,
比如对于示例1 nums = [3, 4, 1, 2, 6] ,我们可以得到 specials = [[0, 3], [4,4]]。
这样题目转化为,对于每一个 query 里的区间,是否存在一个特殊区间,使得 query 区间是特殊区间的子集。
特殊区间是按照升序遍历的,我们用二分查找即可找出有可能的特殊区间。
时间复杂度:O(NQlog(N) ~ O(N^2log(N))
空间复杂度:O(N)
class Solution:
def isArraySpecial(self, nums: List[int], queries: List[List[int]]) -> List[bool]:
specials = []
flag = nums[0] % 2
start = 0
res = []
for i, num in enumerate(nums):
if i:
if num % 2 == flag:
end = i - 1
specials.append([start, end])
start = i
else:
flag = num % 2
specials.append([start, len(nums) - 1])
for s, e in queries:
# in specials, find the first interval that interval[1] >= e
left, right = 0, len(specials) - 1
while left <= right:
mid = (left + right) // 2
if e > specials[mid][1]:
left = mid + 1
else:
right = mid - 1
interval = specials[left]
res.append(interval[0] <= s and e <= interval[1])
return res
第三种思路:
比较高级,利用到位运算的特征。
如果两个相邻元素的奇偶性不同,那么必有 nums[i - 1] ^ nums[i] & 1 == 1,即二进制的最后一位数字的异或值必为1。
因此我们可以用一个 dp 数组来记录原数组的连续奇偶性,如果两个相邻元素的奇偶性不同,就让dp 数组在前一位的基础上 + 1, 否则不变。
这样做的好处是,给定一个子数组 [s, e],我们可以简单地用 dp[e] - dp[s] == [e - s] 来判断它是不是特殊数组。因为如果它是,则 dp 数组应该是一个连续递增 + 1 的数组。
时间复杂度:O(N)
空间复杂度:O(N)
class Solution:
def isArraySpecial(self, nums: List[int], queries: List[List[int]]) -> List[bool]:
dp = [0] * len(nums)
for i, num in enumerate(nums):
if i:
dp[i] = dp[i - 1] + (((num ^ nums[i - 1]) & 1) == 1)
return [dp[e] - dp[s] == e - s for s, e in queries]