力扣周赛330

102 阅读8分钟

题目描述

给你一个整数数组 nums 。你需要找到一个 连续子数组 ,如果对这个子数组中的所有元素进行按位 异或 运算,结果等于 0 。

请你返回 符合题目要求 的子数组的数目。

示例

示例 1:

输入:nums = [2,1,3] 输出:3 解释:存在三个符合题目要求的子数组:

  • [2]:2 ^ 2 = 0
  • [1]:1 ^ 1 = 0
  • [2,1,3]:2 ^ 1 ^ 3 = 0

示例 2:

输入:nums = [1,1,1,1,1] 输出:10 解释:每个子数组都符合题目要求。

示例 3:

输入:nums = [2,3,1,6,7] 输出:4 解释:只有四个子数组符合题目要求:

  • [1]:1 ^ 1 = 0
  • [6]:6 ^ 6 = 0
  • [2,3,1,6]:2 ^ 3 ^ 1 ^ 6 = 0
  • [3,1,6]:3 ^ 1 ^ 6 = 0

解题思路

这道题可以用前缀和的思想来解决。我们可以用一个哈希表来记录每个前缀和的出现次数,其中前缀和就是从数组开头到当前位置的所有元素的异或和。如果两个前缀和相等,那么它们之间的子数组的异或和就是0。例如,如果前缀和为[0,2,3,0,7],那么第一个0和第四个0之间的子数组[2,3]的异或和就是0。因此,我们只需要遍历一遍数组,计算每个位置的前缀和,并在哈希表中查找是否有相同的前缀和出现过,如果有,就说明存在一个符合条件的子数组,并把它的个数加到答案中。最后,我们还需要考虑前缀和本身为0的情况,这时候也需要把答案加一。

Python代码

class Solution:
    def countTriplets(self, nums: List[int]) -> int:
        # 初始化前缀和为0
        prefix = 0
        # 初始化哈希表,记录每个前缀和出现的次数
        # 初始时,前缀和为0出现了一次
        count = {0: 1}
        # 初始化答案为0
        ans = 0
        # 遍历数组中的每个元素
        for num in nums:
            # 计算当前位置的前缀和
            prefix ^= num
            # 如果当前前缀和在哈希表中出现过,说明存在一个符合条件的子数组
            if prefix in count:
                # 把符合条件的子数组的个数加到答案中
                ans += count[prefix]
            # 把当前前缀和在哈希表中的次数加一
            count[prefix] = count.get(prefix, 0) + 1
        # 返回答案
        return ans

题目描述

给你一个整数数组 arr ,请你找出并返回其中最大的幸运数 。

「幸运数」是指在数组中出现频率 恰好等于 其数值的数。

如果数组中不存在这样的数,则返回 -1 。如果数组中存在多个幸运数,只需返回 最大 的那个。

示例

示例 1:

输入:arr = [2,2,3,4] 输出:2 解释:数组中唯一的幸运数是 2 ,因为数组中恰好有 2 个 2 。

示例 2:

输入:arr = [1,2,2,3,3,3] 输出:3 解释:1、2 以及 3 都是幸运数,只需要返回其中最大的 3 。

示例 3:

输入:arr = [2,2,2,3,3] 输出:-1 解释:数组中不存在幸运数。

示例 4:

输入:arr = [5] 输出:-1

示例 5:

输入:arr = [7,7,7,7,7,7,7] 输出:7

解题思路

这道题可以用一个哈希表来记录每个元素出现的次数,然后遍历哈希表,找出满足条件的幸运数,并记录最大的一个。如果没有找到任何幸运数,就返回-1。

Python代码

class Solution:
    def findLucky(self, arr: List[int]) -> int:
        # 初始化哈希表,记录每个元素出现的次数
        count = {}
        # 遍历数组中的每个元素
        for num in arr:
            # 把元素在哈希表中的次数加一
            count[num] = count.get(num, 0) + 1
        # 初始化答案为-1
        ans = -1
        # 遍历哈希表中的每个键值对
        for num, freq in count.items():
            # 如果键和值相等,说明是一个幸运数
            if num == freq:
                # 更新答案为最大的幸运数
                ans = max(ans, num)
        # 返回答案
        return ans

题目描述

给你一个长度为 n 的整数数组 nums ,和一个整数 k 。

请你返回数组中乘积最小的 k 个 连续子数组 的乘积组成的数组。可以按 任意 顺序返回答案。

示例

示例 1:

输入:nums = [10,2,3,7,5,1,4], k = 3 输出:[2,3,5] 解释:乘积最小的连续子数组分别是 [2] ,[3] 和 [5] 。注意,即使乘积相同,也需要按照出现在原数组中的顺序返回结果。

示例 2:

输入:nums = [10,2,-3,-7,5,1,-4], k = 3 输出:[-7,-4,-3] 解释:乘积最小且负数的连续子数组分别是 [-7] ,[-4] 和 [-3] 。注意,即使乘积相同,也需要按照出现在原数组中的顺序返回结果。

示例 3:

输入:nums = [10,2,3,7,5,1,4], k = 4 输出:[10,2,3,5] 解释:乘积最小的连续子数组分别是 [10] ,[2] ,[3] 和 [5] 。注意,即使乘积相同,也需要按照出现在原数组中的顺序返回结果。

解题思路

这道题可以用一个优先队列(堆)来维护乘积最小的 k 个连续子数组。我们可以用一个双指针的方法来遍历所有的连续子数组,对于每个子数组,我们计算它的乘积,并把它和它的起始位置一起放入优先队列中。优先队列按照乘积从大到小排序,这样我们可以保证队列中始终有 k 个最小的乘积。当遍历完所有的子数组后,我们就可以从优先队列中取出 k 个元素,并按照它们在原数组中出现的顺序返回答案。

Python代码

import heapq

class Solution:
    def smallestK(self, nums: List[int], k: int) -> List[int]:
        # 初始化优先队列(堆),按照乘积从大到小排序
        queue = []
        # 初始化左指针为0
        left = 0
        # 初始化当前子数组的乘积为1
        product = 1
        # 遍历右指针从0到n-1
        for right in range(len(nums)):
            # 更新当前子数组的乘积
            product *= nums[right]
            # 如果当前子数组的乘积为0,说明不能再往右扩展了,需要把左指针移动到右指针的下一个位置,并重置乘积为1
            if product == 0:
                left = right + 1
                product = 1
                continue
            # 否则,把当前子数组的乘积和起始位置放入优先队列中
            heapq.heappush(queue, (-product, left))
            # 如果优先队列中元素个数超过k,就弹出最大的元素,保证队列中始终有k个最小的乘积
            if len(queue) > k:
                heapq.heappop(queue)
        # 初始化答案列表为空
        ans = []
        # 把优先队列中的元素按照起始位置从小到大排序
        queue.sort(key=lambda x: x[1])
        # 遍历优先队列中的元素
        for product, left in queue:
            # 取出乘积的绝对值,放入答案列表中
            ans.append(abs(product))
        # 返回答案列表
        return ans

题目描述

给你一个长度为 n 的整数数组 nums ,和一个整数 k 。

请你返回数组中乘积最小的 k 个 异或和 的乘积组成的数组。可以按 任意 顺序返回答案。

「异或和」是指对数组中的所有元素进行按位 异或 运算的结果。

示例

示例 1:

输入:nums = [10,2,3,7,5,1,4], k = 3 输出:[2,3,5] 解释:乘积最小的异或和分别是 [2] ,[3] 和 [5] 。注意,即使乘积相同,也需要按照出现在原数组中的顺序返回结果。

示例 2:

输入:nums = [10,2,-3,-7,5,1,-4], k = 3 输出:[-7,-4,-3] 解释:乘积最小且负数的异或和分别是 [-7] ,[-4] 和 [-3] 。注意,即使乘积相同,也需要按照出现在原数组中的顺序返回结果。

示例 3:

输入:nums = [10,2,3,7,5,1,4], k = 4 输出:[10,2,3,5] 解释:乘积最小的异或和分别是 [10] ,[2] ,[3] 和 [5] 。注意,即使乘积相同,也需要按照出现在原数组中的顺序返回结果。

解题思路

这道题可以用一个优先队列(堆)来维护乘积最小的 k 个异或和。我们可以用一个回溯的方法来遍历所有可能的异或和,对于每个异或和,我们计算它的绝对值,并把它放入优先队列中。优先队列按照绝对值从大到小排序,这样我们可以保证队列中始终有 k 个最小的绝对值。当遍历完所有可能的异或和后,我们就可以从优先队列中取出 k 个元素,并按照它们在原数组中出现的顺序返回答案。

Python代码

import heapq

class Solution:
    def smallestK(self, nums: List[int], k: int) -> List[int]:
        # 初始化优先队列(堆),按照绝对值从大到小排序
        queue = []
        # 定义一个回溯函数,用于遍历所有可能的异或和
        def backtrack(start, xor):
            # 如果已经遍历完所有元素,就把当前异或和放入优先队列中
            if start == len(nums):
                heapq.heappush(queue, (-abs(xor), xor))
                # 如果优先队列中元素个数超过k,就弹出最大的元素,保证队列中始终有k个最小的绝对值
                if len(queue) > k:
                    heapq.heappop(queue)
                return
            # 对于当前元素,有两种选择:加入或不加入异或和
            # 不加入时,直接跳过当前元素,继续遍历下一个元素
            backtrack(start + 1, xor)
            # 加入时,更新当前异或和,继续遍历下一个元素
            backtrack(start + 1, xor ^ nums[start])
        # 调用回溯函数,从第一个元素开始遍历,初始异或和为0
        backtrack(0, 0)
        # 初始化答案列表为空
        ans = []
        # 把优先队列中的元素按照出现在原数组中的顺序排序
        queue.sort(key=lambda x: nums.index(x[1]))
        # 遍历优先队列中的元素
        for _, xor in queue:
            # 取出异或和,放入答案列表中
            ans.append(xor)
        # 返回答案列表
        return ans