leetcode分类刷题:哈希表(Hash Table)(四、前缀和 处理连续子数组)

这篇具有很好参考价值的文章主要介绍了leetcode分类刷题:哈希表(Hash Table)(四、前缀和 处理连续子数组)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、leetcode题目里对于元素加和的考察可谓是屡见不鲜,包括 简单的限定一个有效答案的两个或多个元素求和leetcode分类刷题:哈希表(Hash Table)(一、简单的两数之和)、在有序数组内对加和等于target的三元组、四元组等的求解leetcode分类刷题:基于数组的双指针(三、有序数组的元素求和)以及连续子数组加和leetcode分类刷题:滑动窗口(一、基本子数组类型)
2、本文总结的题型同样为对连续子数组加和进行考察,区别于leetcode分类刷题:滑动窗口(一、基本子数组类型)的是,数组元素为整数,不是正整数了,因此需要按照 前缀和(按照闭区间形式,当前索引位置的值也算进去好理解)+哈希表 的思路进行解决,最后会发现这种题型就是leetcode分类刷题:哈希表(Hash Table)(一、简单的两数之和)的扩展,在解题模板上会有点类似

724. 寻找数组的中心下标

1、该题为典型的使用前缀和算法解决的问题,只需要两次遍历即可:第一次遍历求数组的和;第二次遍历求数组的前缀和,并判断对应位置是否为 中心下标
2、和1991. 找到数组的中间位置是完全一样的题目

from typing import List
'''
724. 寻找数组的中心下标
题目描述:给你一个整数数组nums ,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。
示例 1:
    输入:nums = [1, 7, 3, 6, 5, 6]
    输出:3
    解释:
    中心下标是 3 。
    左侧数之和 sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11 ,
    右侧数之和 sum = nums[4] + nums[5] = 5 + 6 = 11 ,二者相等。
题眼:左侧右侧数组的和
思路1、三次遍历:第一次遍历建立从左到右的加和数组,第二次遍历建立从右到左的加和数组,第三次遍历对加和数组的对应位置判断相等情况
思路2、前缀和(按照闭区间形式,当前索引位置的值也算进去好理解):第一次遍历:求数组的和;第二次遍历:求数组的前缀和,并判断对应位置是否为 中心下标
'''


class Solution:
    def pivotIndex(self, nums: List[int]) -> int:
        # 思路1、三次遍历
        # leftSum = [0] * len(nums)
        # s = 0
        # for i in range(len(nums)):
        #     s += nums[i]
        #     leftSum[i] = s
        # rightSum = [0] * len(nums)
        # s = 0
        # for i in range(len(nums) - 1, -1, -1):
        #     s += nums[i]
        #     rightSum[i] = s
        # for i in range(len(leftSum)):
        #     if leftSum[i] == rightSum[i]:
        #         return i
        # return -1

        # 思路2、前缀和
        # 第一次遍历:求数组的和
        total = 0
        for n in nums:
            total += n
        # 第二次遍历:求数组的前缀和,并判断对应位置是否为 中心下标
        prefixSum = 0
        for i in range(len(nums)):
            prefixSum += nums[i]
            if prefixSum * 2 - nums[i] == total:  # 这个条件的判断没有想到!!
                return i
        return -1


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            nums = [int(n) for n in in_line[1].split('[')[1].split(']')[0].split(',')]
            print(obj.pivotIndex(nums))
        except EOFError:
            break

560. 和为 K 的子数组

1、通过题眼连续子数组来判断,该题很像是滑动窗口的解法,但数组元素为整数,不是正整数,不满足滑窗右边界增大元素之和递增、左指针增大元素之和递减
2、要用前缀和(按照闭区间形式,当前索引位置的值也算进去好理解)+哈希表的思路!
3、通过这道题也认识到,如果“1. 两数之和”不是限定了样例只存在一个答案,其哈希表更新的逻辑有缺陷

from typing import List
'''
560. 和为 K 的子数组
题目描述:给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 。
示例 1:
    输入:nums = [1,1,1], k = 2
    输出:2
题眼:连续子数组,很像是滑动窗口的解法,但数组元素为整数,不是正整数,不满足滑窗右边界增大元素之和递增、左指针增大元素之和递减 了
思路:无法用滑动窗口了;要用前缀和(按照闭区间形式,当前索引位置的值也算进去好理解)+哈希表的思路!
“1. 两数之和”的扩展:通过这道题也认识到,如果“1. 两数之和”不是限定了样例只存在一个答案,其哈希表更新的逻辑有缺陷
'''


class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        result = 0
        hashTable = {0: 1}  # 这里保证了对 包含起始元素的连续子数组 的判断
        prefixSum = 0
        for n in nums:  # 查找 以当前遍历元素n对应的索引位置为 右边界的连续子数组
            prefixSum += n   # 前缀和(按照闭区间形式,当前索引位置的值也算进去好理解)
            # 1、先找 以当前遍历元素n对应的索引位置 之前的前缀和是否存在满足条件的
            if prefixSum - k in hashTable:
                result += hashTable[prefixSum - k]
            # 2、再将当前遍历元素n对应的索引位置 的前缀和添加到hashDict
            if prefixSum not in hashTable:
                hashTable[prefixSum] = 1
            else:
                hashTable[prefixSum] += 1
        return result


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            nums = [int(n) for n in in_line[1].split('[')[1].split(']')[0].split(',')]
            k = int(in_line[2].strip())
            print(obj.subarraySum(nums, k))
        except EOFError:
            break

974. 和可被 K 整除的子数组

1、“560. 和为 K 的子数组”的衍生题,思路为完全一致的前缀和(按照闭区间形式,当前索引位置的值也算进去好理解)+哈希表
2、这道题比较难想的是使用 同余定理:两个除以k余数相等的数字,其差一定可以整除k,即 (preSumJ - preSumI)%K = 0 等价于 preSumJ%K == preSumI%K文章来源地址https://www.toymoban.com/news/detail-686842.html

from typing import List
'''
974. 和可被 K 整除的子数组
题目描述:给定一个整数数组 nums 和一个整数 k ,返回其中元素之和可被 k 整除的(连续、非空) 子数组 的数目。
子数组 是数组的 连续 部分。
示例 1:
    输入:nums = [4,5,0,-2,-3,1], k = 5  
    输出:7
    解释:
    有 7 个子数组满足其元素之和可被 k = 5 整除:  
    [4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]
题眼:连续子数组;“560. 和为 K 的子数组”的衍生题
思路:要用前缀和(按照闭区间形式,当前索引位置的值也算进去好理解)+哈希表的思路
同时,需要使用 同余定理 (preSumJ - preSumI)%K = 0 等价于 preSumJ%K == preSumI%K
'''


class Solution:
    def subarraysDivByK(self, nums: List[int], k: int) -> int:
        # 需要用到 同余定理,两个除以k余数相等的数字,其差一定可以整除k
        result = 0
        hashTable = {0: 1}  # 这里保证了对 包含起始元素的连续子数组 的判断
        prefixSum = 0
        for n in nums:  # 查找 以当前遍历元素n对应索引位置为边界的连续子数组
            prefixSum += n  # 前缀和(按照闭区间形式,当前索引位置的值也算进去好理解)
            if prefixSum % k in hashTable:
                result += hashTable[prefixSum % k]
                hashTable[prefixSum % k] += 1
            else:
                hashTable[prefixSum % k] = 1
        return result


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            nums = [int(n) for n in in_line[1].split('[')[1].split(']')[0].split(',')]
            k = int(in_line[2].strip())
            print(obj.subarraysDivByK(nums, k))
        except EOFError:
            break

到了这里,关于leetcode分类刷题:哈希表(Hash Table)(四、前缀和 处理连续子数组)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【CMU 15-445】Extendible Hash Table 可扩展哈希详细理解

    最近在学习CMU的15-445 DB课程,在做Project1的Extendible Hash Table的时候,由于是先看了课程,过了一个多星期才做的Lab,对extendible hash table只能说是知道大体的意思,并没有透彻的了解它,尤其是bucket指针和数据重分配这一部分,涉及到比较tricky的位运算,在一知半解的情况下实

    2024年02月09日
    浏览(34)
  • Java学数据结构(4)——散列表Hash table & 散列函数 & 哈希冲突

    1.散列表,key,散列函数; 2.哈希冲突的解决; 3.string中的hashCode; 查找树ADT,它允许对元素的集合进行各种操作。本章讨论散列表(hash table)ADT,不过它只支持二叉查找树所允许的一部分操作。散列表的实现常常叫作散列(hashing)。散列是一种用于以常数平均时间执行插入、删除和

    2024年02月10日
    浏览(55)
  • LeetCode刷题 --- 哈希表

    1. 两数之和 解题思路: 利用哈希表,key存数组当前值,value存数组下标 两数之和等于target,可以看做是两个数是配对 遍历数组,看哈希表中有没有值和这个当前值配对,如果没有,就存入哈希表 如果有,当前数,和配对的数,就是所求值。 3. 无重复字符的最长子串 解题

    2024年02月07日
    浏览(47)
  • 字母串哈希模板题题解:哈希+前缀和+进制转换+预处理指数函数

    841. 字符串哈希 给定一个 长度为 n n 的字符串,再给定 m m 个询问 , 每个询问包含四个整数 l1,r1,l2,r2 l1,r1,l2,r2,请你判断 [l1,r1][l1,r1] 和 [l2,r2][l2,r2]  这两个区间所包含的字符串子串是否完全相同 。 字符串中只包含大小写英文字母和数字 。 输入格式 第一行包含整数 

    2024年02月14日
    浏览(53)
  • LeetCode 刷题 数据结构 数组 485 最大连续1的个数

    给定一个二进制数组  nums  , 计算其中最大连续  1  的个数。 示例 1: 示例 2: 提示: 1 = nums.length = 105 nums[i]  不是  0  就是  1.   参看bilibli视频-up主 爱学习的饲养员,讲解的很清晰。 手把手带你刷Leetcode力扣|各个击破数据结构和算法|大厂面试必备技能【已完结】-

    2024年02月15日
    浏览(51)
  • Day.1 LeetCode刷题练习(最长公共前缀 C/C++两种解法)

    题目: 例子: 分析题目: 主要目的:求出各个字符串的公共前缀 思路(本人解法): 用所给实例来看,不难看出我们可以直接以竖着对应来查看是否是公共前缀 ,  这样就有了一定的思路 , 然后接着想如何让他找到最长的公共前缀后就 停止下来呢  这样就能想到,从最

    2024年02月11日
    浏览(38)
  • 代码随想录刷题第6天|哈希表 LeetCode242、LeetCode349、LeetCode202、LeetCode1

    1、LeetCode242 有效的字母异位词 题目链接:242、有效的字母异位词 用哈希表,record[s[i]-\\\'a\\\']++,record[t[i]-\\\'a\\\']--,最后判断record里是否有元素不为0。 2、LeetCode349、两个数组的交集 题目链接:349、两个数组的交集 题目如果没有限制数值的大小,就无法使用数组来做哈希表。如果哈

    2024年02月06日
    浏览(60)
  • leetcode分类刷题:矩阵顺时针模拟

    1、这种题目是对代码熟练度考察, 模拟顺时针 建立或访问矩阵,需要注意矩阵是否为方阵 2、具体思路: 以圈数为循环条件 ,每一圈都坚持 左闭右开 的区间规则;当小的行列值为 奇数 ,最后一圈为一行或一列或一个数字的不完整圈 3、细节:把 起始圈的上下左右边界 和

    2024年02月11日
    浏览(38)
  • 【leetcode 力扣刷题】数学题之除法:哈希表解决商的循环节➕快速乘求解商

    题目链接:166. 分数到小数 题目内容: 题目是要我们把一个分数变成一个小数,并以字符串的形式返回。按道理,直接将分子numerator除以分母denominator就得到了小数,转换成string返回就好。题目要求里指出了特殊情况—— 小数部分如果有循环,就把循环节括在括号里 。 那么

    2024年02月10日
    浏览(40)
  • leetcode分类刷题:队列(Queue)(一、单调队列)

    单调队列,看起来是与单调栈对应起来的一样;但是做题的时候感觉单调队列不像单调栈一样,能根据题意自然形成 单调队列的基本实现 ,感觉单调队列更像是和某个队列对应起来的一样 1、 单调队列的经典题型 :使用双向队列维护窗口,窗口移动的元素增删与队列的先进

    2024年02月09日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包