面试金典--面试题 16.18. 模式匹配 (前缀和+哈希表)

题目描述

给定一个放有字母和数字的数组,找到最长的子数组,且包含的字母和数字的个数相同。
返回该子数组,若存在多个最长子数组,返回左端点下标值最小的子数组。若不存在这样的数组,返回一个空数组。

示例 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```

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深度不学习!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值