题目
给定一个由 0
和 1
组成的数组 arr
,将数组分成 3 个非空的部分 ,使得所有这些部分表示相同的二进制值。
如果可以做到,请返回任何 [i, j]
,其中 i+1 < j
,这样一来:
arr[0], arr[1], ..., arr[i]
为第一部分;arr[i + 1], arr[i + 2], ..., arr[j - 1]
为第二部分;arr[j], arr[j + 1], ..., arr[arr.length - 1]
为第三部分。- 这三个部分所表示的二进制值相等。
如果无法做到,就返回 [-1, -1]
。
注意,在考虑每个部分所表示的二进制时,应当将其看作一个整体。例如,[1,1,0]
表示十进制中的 6
,而不会是 3
。此外,前导零也是被允许的,所以 [0,1,1]
和 [1,1]
表示相同的值。
示例 1:
输入:arr = [1,0,1,0,1]
输出:[0,3]
示例 2:
输入:arr = [1,1,0,1,1]
输出:[-1,-1]
示例 3:
输入:arr = [1,1,0,0,1]
输出:[0,2]
提示:
3 <= arr.length <= 3 * 104
arr[i]
是0
或1
题解1
思路
- 三指针,固定一个指针
i
,遍历数组,使得arr[:i]
=arr[i:j]
=arr[j:]
- 题目对全零的情况未做特殊解释,定义为
n-1
代码
class Solution:
def threeEqualParts(self, arr: List[int]) -> List[int]:
def allZero():
for n in arr:
if n != 0: return False
return True
if allZero(): return [0, len(arr)-1]
left = 0
i = 0
ret = [-1, -1]
while i < len(arr):
left <<= 1
left |= arr[i]
mid = 0
j = i+1
ret[0] = i
while j < len(arr) and mid != left:
mid <<= 1
mid |= arr[j]
j += 1
ret[1] = j
right = 0
while j < len(arr):
right <<= 1
right |= arr[j]
j += 1
if left == mid == right:
return ret
i += 1
return [-1, -1]
复杂度
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)
- 空间复杂度: O ( 1 ) O(1) O(1)
题解2
思路
- 注意到若三个数都要相等则其中的
1
的个数必须相等 - 在除去前导
0
的前提下,最后一组中的1
到结尾即为目标值 - 所以只需要判断前两组
1
开头到下一组的开头是否都相等,相等则直接返回第一个1+长度,否则返回[-1,-1]
代码
class Solution:
def threeEqualParts(self, arr: List[int]) -> List[int]:
oneCount = sum(arr)
if oneCount % 3:
return [-1, -1]
if oneCount == 0:
return [0, 2]
first = second = third = count = 0
for i, n in enumerate(arr):
if n == 1:
if count == 0:
first = i
elif count == oneCount // 3:
second = i
elif count == 2 * oneCount // 3:
third = i
count += 1
length = len(arr) - third
if first + length <= second and second + length <= third:
i = 0
while third + i < len(arr):
if arr[first + i] != arr[second + i] or arr[first + i] != arr[third + i]:
return [-1, -1]
i += 1
return [first + length - 1, second + length]
return [-1, -1]
复杂度
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)