【LeetCode刷题笔记(11-1)】【Python】【和为 K 的子数组】【前缀和】【中等】

文章目录

  • 引言
  • 和为 K 的子数组
    • 题目描述
    • 提示
  • 解决方案1:【暴力枚举】
  • 解决方案2:【前缀和】
  • 结束语

和为 K 的子数组


引言

编写通过所有测试案例的代码并不简单,通常需要深思熟虑理性分析。虽然这些代码能够通过所有的测试案例,但如果不了解代码背后的思考过程,那么这些代码可能并不容易被理解和接受。我编写刷题笔记的初衷,是希望能够与读者们分享一个完整的代码是如何在逐步的理性思考下形成的。我非常欢迎读者的批评和指正,因为我知道我的观点可能并不完全正确,您的反馈将帮助我不断进步。如果我的笔记能给您带来哪怕是一点点的启示,我也会感到非常荣幸。同时,我也希望我的分享能够激发您的灵感和思考,让我们一起在编程的道路上不断前行~


和为 K 的子数组

题目描述

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。

  • 子数组:是数组中元素的连续非空序列。

示例 1:

  • 输入:nums = [1,1,1], k = 2
  • 输出:2

示例 2:

  • 输入:nums = [1,2,3], k = 3
  • 输出:2

提示

  • 1 <= nums.length <= 2 * 104
  • 1000 <= nums[i] <= 1000
  • 107<= k <= 107

解决方案1:【暴力枚举】

根据题意,我们需要统计数组nums和为k的子数组的个数。为了做到这一点,一种直接方法是遍历所有子数组,然后检查每个子数组的和是否等于k

完整代码如下

class Solution:  def subarraySum(self, nums: List[int], k: int) -> int:  # 初始化计数器为0  count = 0  # 获取数组的长度  n = len(nums)  # 遍历数组  for i in range(n):  # 初始化tmp_sum为0  tmp_sum = 0  # 遍历当前元素之后的数组  for j in range(i, n):  # 累加当前元素到tmp_sum  tmp_sum += nums[j]  # 如果tmp_sum等于k,则计数器加1  if tmp_sum == k:   count += 1  # 返回最终的计数结果  return count

运行结果
在这里插入图片描述

虽然这种方法很直接,但它的效率并不高,因为它涉及到两层循环的暴力枚举,时间复杂度为O(n2), 不能通过所有的测试用例。

问题1:从运行结果来看,暴力枚举算法应该存在巨大的优化空间,代码哪些部分可以进一步优化呢?

暴力枚举算法简单粗暴,如果能够优化,一定是在两层遍历中找到优化点! ⇒ 拆解for循环,尝试找到优化点

我们将sum(i --> j)定义为子数组nums[i: j+1]的和(即包括位置j)

  • i=0时,tmp_sum可以动态记录sum(0 --> j),其中j0 —> n-1
  • i为区间[1, n-1]的任意值时,tmp_sum可以动态记录sum(i --> j),其中 ji —> n-1。 对于任意的jsum(i --> j) 等价于 sum(0 --> j) - sum(0 --> i-1),更关键的是,sum(0 --> j)sum(0 --> i-1)已经在i=0时就已经计算出来了 ⇒ 只需要知道所有的sum(0 --> j) ,其中j0 —> n-1,就可以算出任意区间[i, j]的子数组和sum(i --> j)!!!

问题2:通过拆解for循环,我们知道用好sum(0 --> j)是进一步优化算法的关键,那么基于sum(0 --> j)的算法有没有约定俗成的名称?

有,[sum(0 --> j), for j in range(n)]实际上就是数组nums前缀和数组!

解决方案2:【前缀和】

问题3:现在我们已知前缀和数组[sum(0 --> j), for j in range(n)],如何找到满足和为k的所有子数组呢?

首先,明确核心目标:找到所有满足和为k的所有子数组的个数

当遍历到nums的第i个元素时,我们已知

  1. sum(0 --> j), j从0 --> i的所有情况 ;
  2. 区间[0, i]内的任意以i为终止位置的子区间[j ,i]的和都可以通过sum(0 --> i) - sum(0 --> j)获取;

那么对于以i为终止位置的任意子区间[j ,i],只要sum(0 --> i) - sum(0 --> j) = k成立,那么都是我们要找的子数组。如果我们提前用字典数据结构pre_sum_dict存储所有出现过的前缀和,以为键,以和出现的次数为值 ⇒ 查找sum(0 --> i) - k 是否存在于 pre_sum_dict, 若存在,且pre_sum_dict[sum(0 --> i) - k]的值为N ⇒ 找到了N个i为终止位置的子区间[j ,i],满足sum(0 --> i) - sum(0 --> j) = k

通过一次for循环,i从0取到n-1,我们就可以得到每个循环下所有以i为终止位置且满足和为k的子数组个数,用count作为计数器进行计数即可得到满足和为k的所有子数组的个数。

完整代码如下

class Solution:  def subarraySum(self, nums: List[int], k: int) -> int:  # 初始化计数器为0  count = 0  # 获取数组的长度  n = len(nums)  # 创建一个字典用于存储前缀和及其出现的次数  pre_sum_dict = {}  # 初始化前缀和为0的次数为1  pre_sum_dict[0] = 1  # 初始化前缀和为0  cur_pre_sum = 0  # 遍历数组  for i in range(n):  cur_pre_sum += nums[i] # 以i为结束位置的数组nums[:i+1]的和# 如果前缀和减去目标值在之前的前缀和中出现过  if cur_pre_sum - k in pre_sum_dict:  # 将出现次数加入计数器  count += pre_sum_dict[cur_pre_sum - k]  # 如果前缀和不在之前的前缀和中出现过  if cur_pre_sum not in pre_sum_dict:  # 将前缀和加入字典并设置出现次数为1  pre_sum_dict[cur_pre_sum] = 1  else:  # 否则将前缀和的出现次数加1  pre_sum_dict[cur_pre_sum] += 1  return count

运行结果
在这里插入图片描述

复杂度分析

  • 时间复杂度:O(n), n为数组nums的元素个数。
  • 空间复杂度:O(n),哈希字典需要存放n个前缀和。

结束语

  • 亲爱的读者,感谢您花时间阅读我们的博客。我们非常重视您的反馈和意见,因此在这里鼓励您对我们的博客进行评论。
  • 您的建议和看法对我们来说非常重要,这有助于我们更好地了解您的需求,并提供更高质量的内容和服务。
  • 无论您是喜欢我们的博客还是对其有任何疑问或建议,我们都非常期待您的留言。让我们一起互动,共同进步!谢谢您的支持和参与!
  • 我会坚持不懈地创作,并持续优化博文质量,为您提供更好的阅读体验。
  • 谢谢您的阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/236682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL进阶理论篇(十七):数据库主从同步的原理

文章目录 简介为什么需要主从同步主从同步的原理总结参考文献 简介 以MySQL数据库为例&#xff0c;在实际生产中&#xff0c;我们会如何对MySQL数据库进行性能优化呢&#xff1f; 比如说配合上Redis做缓存。Redis是一种高性能的内存数据库&#xff0c;而MySQL是一种基于磁盘文…

docker-compose安装Rocketmq总结,以及如何更换mq端口

默认你已经装好了docker哈 安装docker-compose sudo curl -L https://github.com/docker/compose/releases/download/1.25.1-rc1/docker-compose-uname -s-uname -m -o /usr/local/bin/docker-composechmod x /usr/local/bin/docker-composedocker-compose --version成功打印…

LLVM学习笔记(65)

4.4.3.4. X86FrameLowering子对象 X86Subtarget成员FrameLowering的类型是X86FrameLowering&#xff0c;它派生自TargetFrameLowering。它记录了目标机器上栈布局的信息。比如栈的生长方向&#xff0c;每个函数入口已知的栈对齐边界&#xff0c;以及局部变量区相对函数入口处栈…

截断霍夫曼编码

截断霍夫曼编码是一种数据压缩技术&#xff0c;它基于霍夫曼编码的原理&#xff0c;通过截断霍夫曼树&#xff0c;减少编码中的冗余信息&#xff0c;实现更高效的数据压缩。在本文中&#xff0c;我们将详细探讨截断霍夫曼编码的原理、应用及其优势。 一、霍夫曼编码简介 霍夫曼…

Kubernetes集群内创建具有kubectl命令行工具的容器

Kubernetes 集群中创建一个包含 kubectl 命令的 Pod 通常用于管理和调试集群本身。这种 Pod 通常被称为“调试 Pod”或“管理 Pod”&#xff0c;它们的主要作用是允许从集群内部执行 Kubernetes 操作和管理任务。这可以在多种情况下非常有用&#xff1a; 集群管理和维护 内部…

12.21 汇编点亮STM32MP157小灯

.text .global _start _start: 时钟使能pb6 pf6 pe9LDR r0,0x50000A28LDR r1,[r0]ORR r1,r1,#(0x1<<4)ORR r1,r1,#(0x1<<5)ORR r1,r1,#(0x1<<1)STR r1,[r0]配置GPIO模式LDR r0,0x50006000LDR r1,[r0]BIC r1,r1,#(0x2<<20)ORR r1,r1,#(0x1<<20)B…

kubernetes集群应用 service进阶

kubernetes集群应用 Service进阶 一、场景 使用kubernetes集群运行工作负载时&#xff0c;由于Pod经常处于用后即焚状态&#xff0c;Pod对应的IP地址也会经常变化&#xff0c;因此我们不能直接访问Pod&#xff0c;可以通过Service对应的端点列表&#xff08;Endpoints&#x…

PaddleOCR Docker 容器快捷调用,快捷调用OCR API

文章目录 搞环境命令行测试Python调用测试转fastapi服务打包成镜像服务PaddleOCR 服务端模型总结&#xff0c;直接启动OCR服务 paddleOCR迎来大更新&#xff0c;搞一把新的api接口&#xff0c;直接用起来。 搞环境 搞容器&#xff1a; FROM nvidia/cuda:11.8.0-cudnn8-devel…

openlayers 截图

openlayers 截图 OK&#xff0c;我承认&#xff0c;这篇博文是一个水文。 最新做了一个功能&#xff0c;就是 openlayers 展示二维 GIS 数据后&#xff0c;可以把当前的视角导出图片。 直接写代码吧&#xff0c;没啥好说的&#xff1a; // 截图toImg() {if (this.map) {let ca…

【笔记】网络流算法模板

文章目录 EK求最大流题目描述输入格式输出格式数据范围 算法步骤算法时间复杂度 O ( n m 2 ) O(nm^2) O(nm2) AC CodeDinic/ISAP求最大流题目描述输入格式输出格式数据范围 算法步骤算法时间复杂度 O ( n 2 m ) O(n^2m) O(n2m) AC CodeDinic/ISAP求最小割EK求费用流题目描述输…

Python importlib模块详细教程

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com importlib模块是Python标准库中用于动态导入模块的工具。它提供了一系列函数&#xff0c;允许以编程方式加载、检查和操作模块。本文将深入探讨importlib的各种用法&#xff0c;并通过丰富的示例代码帮助你更好地…

华清作业day46

.text .global _start _start: led1 设置时钟使能 ldr r0,0x50000A28 ldr r1,[r0] orr r1,r1,#(0x1<<4) str r1,[r0]设置输出模式 ldr r0,0x50006000 ldr r1,[r0] bic r1,r1,#(0x3<<20) orr r1,r1,#(0x01<<20) str r1,[r0]设置推挽输出 ldr r0,0x5000600…

如何在Go中发起HTTP请求

引言 当一个程序需要与另一个程序通信时,许多开发人员会使用HTTP。Go的优势之一是其标准库的广度,HTTP也不例外。Go net/http包不仅支持[创建HTTP服务器],而且它还可以作为客户端进行HTTP请求。 在本教程中,您将创建一个程序,向HTTP服务器发出几种类型的HTTP请求。首先,…

在QT Creator下用CMake编译GEOS库

最近&#xff0c;想要在C下编一个可用GDAL模块的地图管理系统&#xff0c;找来找去&#xff0c;找到了GEOS。GEOS&#xff08;Geometry Engine-Open Source&#xff09;开源几何引擎 是一个用于计算几何的JTS库的 C/C实现&#xff0c;专注于地理信息系统 &#xff08;GIS&#…

obsidian + cloudreve 搭建个人云盘

obsidian 是什么&#xff1f;obsidian 是一款好用的笔记软件&#xff0c;拥有强大的第三方库&#xff0c;最重要的是支持WebDAV&#xff0c;可以自动同步笔记到云端服务器 cloudreve 是什么&#xff1f;cloudreve 是一款私人网盘系统&#xff0c;部署简单、界面简洁&#xff0…

11、Qt:创建/删除文件夹、拷贝文件

一、创建文件夹 声明&#xff1a; bool createPath(QString strPath); 定义&#xff1a; /** * brief MainWindow::CreatePath 创建文件夹 * param strPath 要创建的文件夹路径 * return 创建成功返回true&#xff0c;失败返回false */ bool MainWindow::createPath(QString s…

一篇文章概括!状态码分别是什么意思?

hello,我是小索奇&#xff0c;HTTP状态码被分为几个类别&#xff0c;每个类别代表着不同类型的响应。这里是100到500之间的状态码的大致含义&#xff1a; 1xx (信息性状态码) 100 Continue: 客户端应继续其请求。101 Switching Protocols: 请求者已要求服务器切换协议&#x…

速通Python基础语法--语句篇

缩进和代码块 一 条件语句if/elif if的基本语法 示例 条件语句嵌套 练习1 练习2 二 空语句 三 while循环 示例 打印1-10 求1-100的和 求5! 求1-5的阶乘之和 四 for循环 for的基本语法 1~range[ ,) 五 continue/break continue:结束当前循环,继续下一次循环 break:结束整个循…

《每天一分钟学习C语言·四》文本读写操作及二进制读写

fopen(参数1,参数2)&#xff0c;第一个参数是要打开的文件名&#xff0c;文件名字符串&#xff0c;第二个参数用于制定文件打开模式的一个字符串。 注&#xff1a;如果要打开某个盘的文本如F盘test文件夹下的test.txt文本&#xff0c;则fopen(“F:\test\test.txt”,”r”); 程序…

AcWing算法进阶课-1.1.2Dinic/ISAP求最大流

算法进阶课整理 CSDN个人主页&#xff1a;更好的阅读体验 原题链接 题目描述 给定一个包含 n n n 个点 m m m 条边的有向图&#xff0c;并给定每条边的容量&#xff0c;边的容量非负。 图中可能存在重边和自环。求从点 S S S 到点 T T T 的最大流。 输入格式 第一行包…