leetcode分類試験問題:ハッシュテーブル(4.連続部分配列のプレフィックス和処理)

1.有効な答えを制限する2 つ以上の要素の単純な合計を含む、リートコードの質問で要素の合計を調べることは珍しいことではありません。リートコードの分類の質問: ハッシュ テーブル (1. 単純な 2 つの数値) (合計) 、トリプルを解く、4 倍など、合計が順序付けされた配列のターゲットに等しいleetcode の分類問題: 配列ベースのダブル ポインター (3. 順序付けされた配列の要素の合計)および連続部分配列 leetcode の分類問題の合計: スライディング ウィンドウ (1. 基本的な部分配列) type) 2. この記事でまとめた質問タイプは、連続部分配列の合計も調べます。これは、leetcode 分類質問とは異なります。スライディング ウィンドウ (1. 基本的な部分配列タイプ) タイプ) は、配列要素が正の整数ではなく整数であることです。したがって、プレフィックス合計(閉区間形式によると、理解しやすいように現在のインデックス位置の値も含まれています)+ハッシュテーブルの考え方に従って解決する必要があり、最終的にこれが見つかります最初のタイプの質問は、leetcode 分類テストです。これは、ハッシュ テーブル (1. 2 つの数値の単純な合計) の拡張であり、問​​題解決テンプレートではある程度似ています。

724. 配列の中心インデックスを見つける

1. この問題は、プレフィックス合計アルゴリズムを使用して解決される典型的な問題です。必要なトラバーサルは 2 回のみです。最初のトラバーサルでは配列の合計が求められ、2 番目のトラバースでは配列のプレフィックスの合計が求められ、対応する位置が配列の下にあるかどうかが判断されます。配列の中間位置を見つけることも
まったく同じ問題です。

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. 2 つの数値の合計」によってサンプルの答えが 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 で割ったときの余りが等しい 2 つの数値、その差は k で割り切れなければなりません、つまり、(preSumJ - preSumI)%K = 0 は次と同等です。 preSumJ%K == preSumI%K

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

おすすめ

転載: blog.csdn.net/qq_39975984/article/details/132608161