当前位置: 首页 > ds >正文

字节跳动2025年校招笔试手撕真题教程(二)

一、题目

题目内容

小基有一个数组,他想知道有多少连续子数组的和同时是 3 和 5 的倍数,但不是 4 的倍数。

输入描述

第一行输入一个整数 n(1≤n≤105)n(1\le n\le 10^5)n(1≤n≤105) 表示数组长度。

第二行输入 nnn 个整数表示数组 ai(1≤ai≤109)a_i(1\le a_i\le 10^9)ai​(1≤ai​≤109)。

输出描述

一个整数。

样例1

输入:

1

2

3

13 17 30

输出:

1

2

二、分析

这个问题其实是要计算符合条件的连续子数组的数量。这个条件是比较严格的,既要满足是3和5的倍数,又不能是4的倍数,所以需要仔细地分析和对比。

首先,我得明确一下问题的基本概念。连续子数组就是原数组中连续元素组成的一个子序列。比如原数组是 [1,2,3],那么它的连续子数组包括 [1], [2], [3], [1,2], [2,3], [1,2,3] 这些。这些子数组的和分别是1,2,3,3,5,6。现在我们要找的是其中和满足同时是3和5的倍数,但又不是4的倍数的那些子数组。那么如何高效地计算这些子数组呢?这时候我想到了前缀和这个概念。前缀和数组S[i] 表示的是从开头到第i个元素的和。这样,子数组从j到i的和就可以表示为 S[i] - S[j]。这个转换很重要,因为它把求子数组和的问题转化成了求两个前缀和之差的问题。

接下来,我考虑如何通过模运算来判断条件。因为我们要找的是和同时是3和5的倍数,但不是4的倍数,所以可以先分别计算前缀和对3、5和4取模后的结果。假设子数组的和是H,那么H %3 ==0,H%5==0,同时H%4 !=0。但直接计算每个子数组的和再判断的话,时间复杂度会很高,对于大的数组来说不可行。于是我想到了利用前缀和的性质来优化这个过程。具体来说,就是统计前缀和对3和5的模结果相同的出现次数,同时排除那些对4的模结果相同的次数。

我可以用三个数组或者哈希表分别来记录前缀和对3、5、4取模后的结果出现的次数。在这之后,遍历前缀和数组,对于每个位置i,我需要计算在i之前,有多少个前缀和满足模3和模5的结果与当前前缀和相同,但模4的结果不同,这样才能保证子数组的和满足条件。这个过程的关键在于如何高效地统计这些符合条件的前缀和的数量。通过哈希表,可以在常数时间内查询到某个模结果出现的次数,从而快速计算出满足条件的子数组数量。

总的来说,这个解法的时间复杂度是O(n),因为只需要遍历数组几次,每次遍历的操作都是常数时间的。空间复杂度也是O(n),因为需要存储前缀和以及相关的哈希表数据。这样的效率对于题目中的数据范围(数组长度可达到1e5)是完全可行的。需要注意的一点是,初始时前缀和为0的情况也需要考虑进去,因为子数组可能从第一个元素开始,这时候对应的前缀和是0,这个也需要在哈希表中进行初始化。

三、代码

这个算法的时间复杂度是O(n),因为我们需要遍历数组一次来计算前缀和,然后再遍历一次来统计满足条件的子数组数量。空间复杂度是O(n),因为我们需要存储前缀和以及三个哈希表。

n = int(input())
a = list(map(int, input().split()))prefix_sum = [0] * (n + 1)
for i in range(n):prefix_sum[i + 1] = prefix_sum[i] + a[i]mod3 = [0] * (n + 1)
mod5 = [0] * (n + 1)
mod4 = [0] * (n + 1)
for i in range(n + 1):mod3[i] = prefix_sum[i] % 3mod5[i] = prefix_sum[i] % 5mod4[i] = prefix_sum[i] % 4count_mod3 = {}
count_mod5 = {}
count_mod4 = {}
for i in range(n + 1):if mod3[i] not in count_mod3:count_mod3[mod3[i]] = 0if mod5[i] not in count_mod5:count_mod5[mod5[i]] = 0if mod4[i] not in count_mod4:count_mod4[mod4[i]] = 0count_mod3[mod3[i]] += 1count_mod5[mod5[i]] += 1count_mod4[mod4[i]] += 1result = 0
for i in range(n + 1):count_mod3[mod3[i]] -= 1count_mod5[mod5[i]] -= 1count_mod4[mod4[i]] -= 1result += count_mod3[mod3[i]] * count_mod5[mod5[i]] - count_mod3[mod3[i]] * count_mod4[mod4[i]]print(result)

这个代码首先计算前缀和以及每个前缀和的模值,然后使用哈希表统计每个模值出现的次数。最后,通过遍历前缀和数组,统计满足条件的子数组数量。

http://www.xdnf.cn/news/9001.html

相关文章:

  • Spyglass:目标文件(.spq)的结构
  • 汉诺塔超级计算机数据区结构和源代码详细设计
  • vue3组件--无限滚动效果
  • 算法题(155):线段覆盖
  • ADSY1100系统级模块(SOM)4 Tx/4 Rx, 0.1 GHz to 20 GHz
  • 【Java】多线程_创建线程的四种方式
  • 【测试】——AS/400快速入门
  • 可编程幻彩LED灯条的设计
  • Python文件操作完全指南
  • 【TypeScript】结构化类型系统与标明类型系统
  • Linux 内核学习(8) --- 字符设备操作函数
  • SpringBoot中消息转换器的选择
  • some java面试题
  • 第三方检测机构如何凭借专业公正保障软件质量?资质有哪些?
  • ELF文件的作用详解
  • STL 标准模板库全面解析:容器、算法与迭代器的核心应用
  • Eigen 库实现最小二乘算法(Least Squares)
  • 如何用AI实现需求分析
  • Newtonsoft Json序列化数据不序列化默认数据
  • LeetCode 1345 跳跃游戏 IV
  • CentOS7更新 GLIBC 2.25
  • 基于亚博K210开发板——六轴姿态传感器水平测试板验证
  • Java集合使用中的常见错误与最佳实践
  • Oracle 如何实现AI自然语言查询
  • MySQL索引深度解析:从原理到实践
  • STM32的内部FLASH
  • JVM相关
  • 【MPC控制 - 从ACC到自动驾驶】4 MPC的“实战演练”:ACC Simulink仿真与结果深度解读
  • 【Linux】磁盘空间不足
  • vite+vue2安装步骤