给定一个放有字母和数字的数组,找到最长的子数组,且包含的字母和数字的个数相同。
返回该子数组,若存在多个最长子数组,返回左端点下标值最小的子数组。若不存在这样的数组,返回一个空数组。
示例 1:
输入: [“A”,“1”,“B”,“C”,“D”,“2”,“3”,“4”,“E”,“5”,“F”,“G”,“6”,“7”,“H”,“I”,“J”,“K”,“L”,“M”]
输出: [“A”,“1”,“B”,“C”,“D”,“2”,“3”,“4”,“E”,“5”,“F”,“G”,“6”,“7”]
示例 2:
输入: [“A”,“A”]
输出: []
将字母看成‘1’,数字看成‘-1’。
比如: [“A”,“1”,“B”,“C”,“D”,“2”,“3”,“4”,“E”,“5”,“F”,“G”,“6”,“7”,“H”,“I”,“J”,“K”,“L”,“M”]
转化为[1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1]
紧接着计算前缀和数组:[1, 0, 1, 2, 3, 2, 1, 0, 1, 0, 1, 2, 1, 0, 1, 2, 3, 4, 5, 6]。
将前缀和前面添加一个0,变成[0,1, 0, 1, 2, 3, 2, 1, 0, 1, 0, 1, 2, 1, 0, 1, 2, 3, 4, 5, 6]。
为啥要加0?毕竟是前缀和嘛,前缀和下标为1的时候表示array数组前面1个数值的和,区间为[0,1) 左闭右开,刚好符合代码编写习惯。
在前缀和数组中可以发现一个点,前缀和数组里相同的数字代表–在这两个相同数字区间内的数出现字母和数字的次数是相同的。
比如看这2个1:[0,1
, 0,1, 2, 3, 2, 1
, 0, 1, 0, 1, 2, 1, 0, 1, 2, 3, 4, 5, 6]
说明这2个1的下标所构成的区间内的数字和为0,也就是说,无论你怎么折腾,开始为1代表有1个字母,中间折腾了无数次,最后结果也是1代表有1个字母,说明你中间有相同个数的字母和数字使得开始有1个字母,最后也是剩下1个字母。
这时候就找相同数字间隔最远的哪一个子数组就行了。
直接拿哈希表来做。
哈希表key为数字,value为该数字的下标。
哈希表中只记录数字第一次出现的数值。
若其非第一次出现,则计算当前下标和数字第一次出现时的下标的差值,找到最大的哪一个差值即可。
class Solution:
def findLongestSubarray(self, array: List[str]) -> List[str]:
temp = []
# 转为数字为-1,字母为1
for i in range(len(array)):
try:
s = int(array[i])
temp.append(-1)
except:
temp.append(1)
start = 0
ans = [0]
# 计算前缀和
for i in range(len(temp)):
start+=temp[i]
ans.append(start)
res = []
max_length = 0
hs = {}
# 哈希表找最长子串
for i in range(len(ans)):
if ans[i] not in hs:
hs[ans[i]] = i
else:
if i-hs[ans[i]]>max_length:
res = array[hs[ans[i]]:i]
max_length = i-hs[ans[i]]
return res```