560. 和为 K 的子数组

题目描述

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

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

解题

简单直接, 但时间复杂度最高 O(n3)

class Solution {func subarraySum(_ nums: [Int], _ k: Int) -> Int {var total = 0, p = 0for index in 0...(nums.count - 1) {p = indexwhile p < nums.count {if nums[index...p].reduce(0, +) == k {total += 1}p += 1}}return total}
}

优化 nums[index...p].reduce(0, +) 的时间复杂度为 O(1)

整体时间复杂度优化为 O(n2)

class Solution {func subarraySum(_ nums: [Int], _ k: Int) -> Int {var total = 0, p = 0, sum = 0for index in 0...(nums.count - 1) {p = indexsum = 0while p < nums.count {sum += nums[p]if sum == k {total += 1}p += 1}}return total}
}

前缀和 + 哈希表优化

func subarraySum(_ nums: [Int], _ k: Int) -> Int {var prefixSumCount: [Int: Int] = [0: 1]var prefixSum = 0var count = 0for num in nums {prefixSum += numif let prefixCount = prefixSumCount[prefixSum - k] {count += prefixCount}prefixSumCount[prefixSum, default: 0] += 1}return count
}

知识拓展 - “前缀和”的使用和理解

前缀和(Prefix Sum)是一种常用的算法技巧,主要用于高效地处理一系列连续子数组或区间求和的问题。前缀和通过预处理数组来减少后续查询的时间复杂度,使得处理某些类型的问题变得更加高效。

前缀和的定义

前缀和数组是原始数组的一个扩展数组,其中的每个元素表示原始数组中从第一个元素到当前元素的累积和。具体来说,给定一个数组 nums,其前缀和数组 prefix 定义如下:

[ \text{prefix}[i] = \sum_{j=0}^{i-1} \text{nums}[j] ]

例如,考虑数组 nums = [1, 2, 3, 4],其前缀和数组 prefix 为:

[ \text{prefix} = [0, 1, 3, 6, 10] ]

前缀和的构建

构建前缀和数组的时间复杂度为 (O(n)),其中 (n) 是原始数组的长度。下面是一个简单的 Swift 实现:

func buildPrefixSum(nums: [Int]) -> [Int] {var prefix = [0]for num in nums {prefix.append(prefix.last! + num)}return prefix
}let nums = [1, 2, 3, 4]
let prefix = buildPrefixSum(nums: nums)
print(prefix)  // 输出: [0, 1, 3, 6, 10]

前缀和的应用

前缀和可以用于快速计算任意子数组的和。假设我们要计算数组 nums 中从索引 i 到索引 j 的子数组的和,可以通过以下公式实现:

[ \text{sum}(i, j) = \text{prefix}[j+1] - \text{prefix}[i] ]

例如,要计算 nums = [1, 2, 3, 4] 中从索引 1 到索引 3 的子数组 [2, 3, 4] 的和,可以通过 prefix[4] - prefix[1] 得到结果 9。

func subarraySum(prefix: [Int], i: Int, j: Int) -> Int {return prefix[j + 1] - prefix[i]
}let sum = subarraySum(prefix: prefix, i: 1, j: 3)
print(sum)  // 输出: 9

示例问题

示例 1:求一个数组中所有子数组的和

给定一个数组,求出所有子数组的和。利用前缀和可以高效地解决这个问题。

func allSubarraySums(nums: [Int]) -> [Int] {let prefix = buildPrefixSum(nums: nums)var result = [Int]()for i in 0..<nums.count {for j in i..<nums.count {result.append(subarraySum(prefix: prefix, i: i, j: j))}}return result
}let sums = allSubarraySums(nums: nums)
print(sums)  // 输出: [1, 3, 6, 10, 2, 5, 9, 3, 7, 4]
示例 2:连续子数组的最大和

可以利用前缀和数组来求解最大子数组和问题(Kadane’s Algorithm 的另一种实现方式)。

func maxSubArraySum(nums: [Int]) -> Int {let prefix = buildPrefixSum(nums: nums)var maxSum = Int.minvar minPrefix = 0for i in 1..<prefix.count {maxSum = max(maxSum, prefix[i] - minPrefix)minPrefix = min(minPrefix, prefix[i])}return maxSum
}let maxSum = maxSubArraySum(nums: nums)
print(maxSum)  // 输出: 10

小结

前缀和是一种强大的工具,特别适用于处理涉及区间和的算法问题。通过预处理数组,前缀和可以将许多问题的时间复杂度从 (O(n^2)) 降低到 (O(n)),大大提高了效率。在实际应用中,前缀和常用于解决诸如区间求和、连续子数组问题和二维矩阵问题等。


重点说明 - 前缀和数组 prefix 初始化为 [0] 的重要性

前缀和数组 prefix 初始化为 [0] 是非常重要的,这一点在前缀和算法中起到了关键作用。以下是具体原因:

1. 边界条件处理

初始化 prefix[0],能够很好地处理前缀和的边界条件。例如,当计算从数组起点到某一位置的和时,这样的初始化可以确保正确计算。假设我们需要计算数组 nums 从索引 0i 的和:

[ \text{prefix}[i+1] = \sum_{j=0}^{i} \text{nums}[j] ]

若不初始化为 [0],在计算 prefix 时将出现索引越界或错误的累计结果。

2. 子数组和的计算

使用前缀和数组时,通常通过以下公式计算任意子数组的和:

[ \text{sum}(i, j) = \text{prefix}[j+1] - \text{prefix}[i] ]

在这种情况下,prefix 数组的第一个元素为 0 可以确保在计算子数组和时不丢失任何信息,并且可以处理 i=0 的情况,即计算从数组开始到 j 的子数组的和。

例如:

let nums = [1, 2, 3, 4]
let prefix = [0, 1, 3, 6, 10]func subarraySum(prefix: [Int], i: Int, j: Int) -> Int {return prefix[j + 1] - prefix[i]
}// 计算从索引0到3的子数组和:[1, 2, 3, 4]
let sum = subarraySum(prefix: prefix, i: 0, j: 3)
print(sum)  // 输出: 10

若未初始化 prefix[0],则上述公式在计算从索引 0 开始的子数组和时会出错。

3. 代码简洁性和一致性

初始化为 [0] 使得前缀和数组的构建和使用更加简洁和一致,不需要在构建和查询过程中做额外的边界处理。这有助于避免边界条件相关的错误,并使代码更易读。

例如:

func buildPrefixSum(nums: [Int]) -> [Int] {var prefix = [0]for num in nums {prefix.append(prefix.last! + num)}return prefix
}let nums = [1, 2, 3, 4]
let prefix = buildPrefixSum(nums: nums)
print(prefix)  // 输出: [0, 1, 3, 6, 10]

通过以上代码可以看到,初始化为 [0] 后,prefix 的构建逻辑变得非常简单而直接。

小结

初始化前缀和数组 prefix[0] 是前缀和算法的一个关键步骤。它不仅能有效处理边界条件,还能确保子数组和计算的正确性,同时保持代码的简洁和一致性。这个初始化步骤在实际应用中非常重要,能够帮助我们避免许多常见的错误。

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

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

相关文章

华三中小企业组网

一、组网需求 在中小园区中&#xff0c;S5130系列或S5130S系列以太网交换机通常部署在网络的接入层&#xff0c;S5560X系列或 S6520X系列以太网交换机通常部署在网络的核心&#xff0c;出口路由器一般选用MSR系列路由器。 核心交换机配置VRRP保证网络可靠性。园区网中不同的…

哪些AI生图软件值得推荐,有需要的建议收藏!

人工智能(AI)已经渗透到我们生活的方方面面&#xff0c;AI生图软件就是其中的一种&#xff0c;它们能够帮助我们快速生成高质量的图片&#xff0c;无论是社交媒体的配图&#xff0c;还是设计作品的素材&#xff0c;都能够得到极大的帮助。那么哪些AI生图软件值得推荐呢? 首先&…

自定义APT插件导致IDEA调试时StreamTrace(跟踪当前流链)报internal error(内部错误)

IDEA里面debug的时候&#xff0c;针对stream流提供了流追踪调试功能&#xff0c;方便大家调试stream流代码。 最近改其他人代码&#xff0c;需要用到这个&#xff0c;发现提示内部错误。 然后百度一圈发现没啥解决方案&#xff0c;就自己看IDEA的日志&#xff0c;看看是什么引…

Centos安装redis(附:图形化管理工具)

第一步&#xff1a;下载redis wget http://download.redis.io/releases/redis-6.2.7.tar.gz 第二步&#xff1a;解压 tar zxvf redis-6.2.7.tar.gz 第三步&#xff1a;安装依赖环境 yum -y install gcc-c第四步&#xff1a;安装依赖环境 make install第五步&#xff1a;修…

基于matlab的K-means聚类图像分割

1 原理 K-means聚类算法在图像分割中的应用是基于一种无监督的学习方法&#xff0c;它将图像中的像素点或特征区域划分为K个不同的簇或类别。以下是K-means聚类算法用于图像分割的原理&#xff0c;包括步骤和公式&#xff1a; 1.1 原理概述 选择簇的数量(K)&#xff1a; 首先…

如何科学减肥先从了解自己在到饮食运动

在这个以瘦为美的时代&#xff0c;许多人被肥胖所困扰着&#xff0c; 今天就来教大家如何科学减脂。 一、如何判断自己是否需要减脂&#xff1f; 第一步就是判断自己的体重指数&#xff08;BMI&#xff09;是否在正常标准。BMI是国际上衡量人体胖瘦程度及是否健康的一个常用指…

定位问题6.27 petal数据接口问题

petal接口响应结果 响应结果为空的数据&#xff0c;而我们需要的是正确的响应结果。 排查问题 确认接口是否正确 以下是爬虫的配置文件内容&#xff0c;我查看了PETAL_URL的接口&#xff0c;并询问接口开发人员&#xff0c;得知接口地址并未改变 确认接口请求体是否正确 我使…

开源“卖货主播”AI大模型——拳打李佳琦、脚踢小杨哥、人人都能当销冠?

开源“卖货主播”AI大模型——拳打李佳琦、脚踢小杨哥、人人都能当销冠&#xff1f; 刚刚在知名同性交友平台发现了一个或许能让你致富的开源项目——“Streamer-Sales 销冠”。 正如其名字所言&#xff0c;这是一个卖货主播LLM大模型&#xff0c;旨在让你成为销冠。 https:/…

d3dx9_42.dll找不到怎么正确处理?教学级修复d3dx9_42.dll的方法分享

d3dx9_42.dll找不到&#xff1f;别着急&#xff0c;这只是普普通通的dll文件找不到而已&#xff0c;它可能因为各种原因而导致丢失&#xff0c;我们只要直接对d3dx9_42.dll进行修复就可以了。下面我们一起来了解一下d3dx9_42.dll找不到的正确处理方法。 一.d3dx9_42.dll找不到是…

微信公众号写作时必备的AI提示词(也称为指令或Prompt)

猫头虎 &#x1f42f; 微信公众号写作时必备的AI提示词&#xff08;也称为指令或Prompt&#xff09; &#x1f389; 大家好&#xff0c;我是猫头虎&#xff0c;科技自媒体博主。今天&#xff0c;我们来聊聊如何利用AI提示词&#xff0c;打造出爆款的微信公众号文章。&#x1…

OnlyOffice:为现代工作方式而生的办公套件

ONLYOFFICE官网链接&#xff1a;https://www.onlyoffice.com/zh/office-suite.aspx https://www.onlyoffice.com/zh/pdf-editor.aspx OnlyOffice 是一款开源的办公套件&#xff0c;它提供了一系列的办公工具&#xff0c;包括文档编辑器、表格编辑器和演示文稿编辑器。这些工具…

靶机渗透之DC-7

一、信息收集 扫描网段&#xff0c;发现靶机ip为192.168.145.235。 nmap -sP 192.168.145.* 进一步对端口&#xff0c;靶机系统等信息进行一个收集。可以看到开放了22端口&#xff0c;80端口&#xff0c;主机系统为linux等信息。 nmap -sT -T4 -O -sV -sC -p1-65535 192.16…

零知识证明基础:对称加密与非对称加密

1、绪论 在密码学体系中&#xff0c;对称加密、非对称加密、单向散列函数、消息认证码、数字签名和伪随机数生成器被统称为密码学家的工具箱。其中&#xff0c;对称加密和非对称加密主要是用来保证机密性&#xff1b;单向散列函数用来保证消息的完整性&#xff1b;消息认证码的…

工具篇:鸿蒙DevEco Studio5.0版本下载及安装

1、下载中心地址 下载中心 | 华为开发者联盟-HarmonyOS开发者官网&#xff0c;共建鸿蒙生态 2、安装 DevEco Studio支持Windows和macOS系统&#xff0c;下面将针对两种操作系统的软件安装方式分别进行介绍。 Windows环境 运行环境要求 为保证DevEco Studio正常运行&#…

人工智能AI风口已开:如何赋予UI设计与视频剪辑新生命

随着科技的浪潮不断向前推进&#xff0c;人工智能&#xff08;AI&#xff09;正以惊人的速度重塑着我们的世界&#xff0c;特别是在创意产业的核心领域——UI设计与视频剪辑中&#xff0c;AI正逐步成为驱动行业创新与变革的关键力量。在这个AI技术全面开花的新时代&#xff0c;…

将产品制作成3D模型在网站上展示需要多少费用?

将产品制作成3D模型并在网站上展示的费用会因多种因素而异&#xff0c;包括模型的复杂度、所需的细节程度、制作3D模型的软件和工具、以及是否需要专业设计师的服务等。此外&#xff0c;不同的3D模型制作服务提供商可能会有不同的定价标准。 如果能自己制作3D模型&#xff0c;…

高性能并行计算华为云实验三:蒙特卡罗算法实验

目录 一、实验目的 二、实验说明 三、实验过程 3.1 创建蒙特卡罗算法源码 3.2 Makefile的创建与编译 3.3 主机文件配置与运行监测​​​​​​​ 四、实验结果与分析 4.1 原教程对应的实验结果 4.2 改进后的实验结果 五、实验思考与总结 5.1 实验思考 5.2 实验总结…

JAVA编程题期末题库【中】

8.计算邮资 程序代码: public static void main(String[] args) {// 计算邮资//if多分支语句//创建对象java.util.Scanner inputnew java.util.Scanner(System.in); //提示输入用户&#xff0c;输入邮件的重量System.out.println("邮件的重量&#xff1a;");int wei…

智能疏散指示系统为什么是验收的必然考核标准?哪些厂家具备资质

智能疏散系统需要什么&#xff1f;现阶段&#xff0c;随着我国经济不断发展趋势的加快&#xff0c;住宅建筑具有复杂的特点。近年来&#xff0c;我国高层住宅、大中型建筑、综合性公共建筑越来越多。随着这座现代建筑的进步&#xff0c;我发现这种类型的建筑在发生火灾或事故时…

Spring系统学习 - FactoryBean和基于XML的自动装配

Factory Bean Spring的FactoryBean是一个特殊的Bean&#xff0c;用于创建其他Bean实例。FactoryBean接口定义了一个工厂Bean&#xff0c;该Bean可以用来生成其他Bean的实例。通过实现FactoryBean接口&#xff0c;开发人员可以自定义Bean的创建逻辑&#xff0c;实现更灵活的Bea…