青训营X豆包MarsCode 技术训练营第二课 | 豆包MarsCode AI 刷题

56 阅读3分钟

这篇文章,我在豆包MarsCode AI刷题(代码练习)题库中位运算分类下选取简单题、中等题、困难题各一道进行解析。

简单题

说实话,简单题中,只要不是题目出错,你教给MarsCode AI,它基本上都能给你解决。

找单独的数

问题描述

在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。

要求:

  1. 设计一个算法,使其时间复杂度为 O(n),其中 n 是班级的人数。
  2. 尽量减少额外空间的使用,以体现你的算法优化能力。
约束条件
  • 1 ≤ cards.length ≤ 1001
  • 0 ≤ cards[i] ≤ 1000
  • 班级人数为奇数
  • 除了一个数字卡片只出现一次外,其余每个数字卡片都恰好出现两次
思路

最简单的一个思路,统计每个数组出现多少次,然后遍历查找出现1次的数字。

当然,题目要求题目要求尽量减少额外空间的使用,以体现我们的算法优化能力。

这里我们还可以使用位运算,我们知道 a ^ a = 0 所以,我们很快就能得出,将所有数字进行异或操作能马上得出结果。

代码
def solution(inp):
    result = 0
    for i in inp:
        result ^= i
    return result

中等题

判断子数组能否被5整除的问题

问题描述

小R有一个二进制数组 nums,其中的下标从 0 开始。我们定义 xi 为从最高有效位到最低有效位的子数组 nums[0..i] 所表示的二进制数。例如,如果 nums = [1, 0, 1],那么 x0 = 1x1 = 2x2 = 5

小R想知道,对于每个 xi,它能否被 5 整除。你需要返回一个布尔值列表 answer,当 xi 能够被 5 整除时,answer[i] 为 true,否则为 false

思路

这题其实是一道简单题,我们只需要依次累左移,再加上当前的数字。

代码
def solution(nums: list) -> list:
    now = 0
    result = []
    for i in nums:
        now <<= 1
        now += i
        if now % 5 == 0:
            result.append(bool(1))
        else:
            result.append(bool(0))

困难题

小k的区间与值和

问题描述

小K有一个数组,她定义数组的权值为数组中任选两个数的按位与的值之和。具体来说,对于数组中的每个连续子数组,我们可以计算所有可能的两个元素的按位与值之和,并将这些值相加。小K想知道该数组中所有可能的连续子数组的权值和是多少,最后结果对10^9 + 7取模。

思路

这题我们可以采用数学归纳法来做,我们看下面这个数组 xxxxaxxxxbxxxx,我们怎么求a & b 在每个连续子区间内出现多少次,首先 axxxxb是一定会出现的,对于这个数组左边可能会出现 "", "x", "xx", "xxx", "xxxx" 这几个,对于右边来说,可能是 "", "x", "xx", "xxx", "xxxx" 这几个,我们只要把两边数字相成就能得到哪些连续子区间内出现 a & b。所以,我们就能得到一个公式 (a & b) * pos(a) * (n - pos(b))

代码
def solution(n: int, a: list) -> int:
    mod = 1e9 + 7
    result = 0
    for i in range(0, n - 1):
        for j in range(i + 1, n):
            result = (result + (a[i] & a[j]) * (i + 1) * (n - j)) % mod 
    return result