LeetCode算法题 (除自身以外数组的乘积)Day14!!!C/C++

https://leetcode.cn/problems/product-of-array-except-self/description/

一、题目分析

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内。

请 不要使用除法在 O(n) 时间复杂度内完成此题。

二、示例分析

示例 1:

输入: nums =[1,2,3,4]
输出:[24,12,8,6]

示例 2:

输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

        结合题目以及示例,我们不难看出今天这道题目的需要完成的操作就是求出除自身以外的乘积,并存放到一个数组中,最后返回数组。

三、解题思路&代码实现

        在拿到任何一道题目的时候,我们首先要做的就是认真审题,读懂题目要求以后,在心里或者草稿纸上写出模拟过程的伪代码,之后再做进一步的优化。今天这道题目也一样,我们什么算法都先不要考虑,就用最暴力的方法来做。

1、暴力解法(复杂度为O(n^2))

1、核心思路:对于每一个nums[i],遍历整个数组,跳过nums[i]并计算其余元素的乘积

 2、关键步骤:

         1、初始化ans数组,该数组的长度于nums数组相同
         2、双重循环计算乘积:

                外层循环:遍历每个nums[i],准备计算ans[i]。

                内层循环:遍历nums所有元素,遇到 i == j时跳出此次循环(排除自身),其余元素累乘到sum。

        3、存储结果:

                将计算好的sum存入到ans[i]中。

vector<int> productExceptSelf(vector<int>& nums) {vector<int> ans(nums.size());  // 定义结果数组,长度与 nums 相同// 遍历计算每个位置 ans[i] 的值for (int i = 0; i < nums.size(); i++) {long long sum = 1;  // 初始化乘积为 1(因为 1 不影响乘法结果)// 计算 nums 中除 nums[i] 外所有元素的乘积for (int j = 0; j < nums.size(); j++) {if (j == i) continue;  // 跳过当前元素 nums[i],不参与乘积计算sum *= nums[j];  // 累乘其他元素}ans[i] = sum;  // 将计算结果存入 ans[i]}return ans;  // 返回最终结果
}

        但是本题暴力解法是并不能通过所有的测试用例,题目的数据范围给到了1e5,如果是双重循环的话就是1e10。(PS:C/C++ 1秒能跑的数据大概是在1e7~1e8左右)。

        那么现在就要想办法优化把这段程序优化至O(n);        

2、分类讨论(数学分类法)

        数学分类法的核心思路:

        首先要统计出数组中是否有零,如果有的话零有多少个,如果有且仅有一个的话,那么ans数组中的元素就应该是除nums数组元素中为0的那一个元素应该为其余元素的乘积,其他元素则全部为零。

        如果nums数组中0的个数>1,那么ans数组中的所有元素都应为0;

        除以上两种情况外 也就是nums数组中没有零。

  1. 单零情况:若数组中仅含一个零,那么结果数组中,零所在位置的元素为其余非零元素的乘积,其余位置元素均为零。例如,对于数组 [1, 0, 2, 3],结果数组为 [0, 6, 0, 0],因为 1*2*3=6,零位置填充该值,其余位置补零。
  2. 多零情况:当数组中零的数量大于 1 时,无论如何计算,乘积必然为零,因此结果数组的所有元素均为零。
  3. 无零情况:若数组中不存在零,结果数组的每个元素等于数组所有元素的乘积除以对应位置的元素。例如,对于数组 [1, 2, 3, 4],结果数组为 [24, 12, 8, 6] ,因为 1*2*3*4=24,分别除以 1234 得到对应位置结果。
class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {// 初始化结果数组,大小与输入数组相同vector<int> ans(nums.size());// sum: 所有元素的乘积(初始为1)// cnt_0: 统计数组中0的个数int sum = 1, cnt_0 = 0;// 第一次遍历:计算所有元素的乘积,并统计0的个数for (auto i : nums) {sum *= i;           // 累乘所有元素if (i == 0)         // 遇到0时计数cnt_0++;}// 情况1:数组中恰好有1个0if (cnt_0 == 1) {int sum = 1;  // 重新计算非0元素的乘积(避免之前sum=0的影响)// 计算所有非0元素的乘积for (int i = 0; i < nums.size(); i++) {if (nums[i] != 0)sum *= nums[i];}// 填充结果数组:// - 非0位置的结果为0(因为总乘积含0)// - 0位置的结果为非0元素的乘积for (int i = 0; i < nums.size(); i++) {if (nums[i] != 0)ans[i] = 0;elseans[i] = sum;}return ans;}// 情况2:数组中有超过1个0// 所有位置的结果都是0(因为任何位置都至少包含一个0)if (cnt_0 > 1) {return ans;  // ans已初始化为全0}// 情况3:数组中没有0// 直接计算:ans[i] = 总乘积 / nums[i]for (int i = 0; i < nums.size(); i++) {ans[i] = sum / nums[i];}return ans;}
};

        以上代码是优化了时间复杂度,但是题目中也是有明确要求不能使用除法的,所以尽管我们这段代码的时间复杂度已经优化至O(n)。但还是需要改进。

3、前缀和&后缀和思想(正解

        核心思想:

        此方法的核心思想就是空间换时间,利用前缀和的思想的对ans数组进行预处理,这样的好处就是每次取一个结果所需的时间复杂度为常数级,也就是O(1)。

        其次通过将目标乘积拆分为两部分(左部分、右部分)。第一次看到这段代码时候,应该会想为什么能把nums[i]排除呢?

  • 左边乘积ans[i])不包含 nums[i](因为只乘到 nums[i-1])。

  • 右边乘积right)不包含 nums[i](因为先乘 right,再更新 right)。

  • 最终结果ans[i] = 左边乘积 × 右边乘积,自然排除了 nums[i]

class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {// 初始化结果数组,所有元素初始值为1(乘法单位元)vector<int> ans(nums.size(), 1);// 第一次遍历:计算每个元素左边所有元素的乘积(前缀积)// ans[i] 表示 nums[0] × nums[1] × ... × nums[i-1]for (int i = 1; i < nums.size(); i++) {ans[i] = ans[i - 1] * nums[i - 1];  // 递推计算前缀积}// 初始化右边乘积为1(最右边元素的右边没有元素)int right = 1;// 第二次遍历(从右往左):计算右边乘积并合并到结果中// 此时 ans[i] = 左边乘积 × 右边乘积for (int i = nums.size() - 1; i >= 0; i--) {ans[i] *= right;   // 将当前元素的右边乘积乘到结果上right *= nums[i];  // 更新右边乘积(包含当前元素)}return ans;}
};

        至此,上述代码均满足题目的所有要求!!!完结撒花🌸🌸🌸

四、题目总结

        本题要求在不使用除法且时间复杂度为 O(n) 的条件下,计算数组中除自身元素之外其余各元素的乘积。解题过程需结合题目要求与数据限制,通过逐步优化算法来实现目标。

        在暴力解法中,采用双重循环遍历数组,对每个元素计算其余元素的乘积,虽然逻辑直观,但时间复杂度高达 O(n^2),无法满足题目数据范围的要求。

        数学分类法通过统计数组中零的数量进行分类讨论,优化了时间复杂度至 O(n)。当数组中有一个零,结果数组中零位置为其余非零元素乘积,其余位置为零;若有多个零,结果数组全为零;若无零,则用所有元素乘积除以对应位置元素得到结果。然而,该方法使用了除法运算,不符合题目要求。

        最终的前缀和与后缀和思想是本题正解。利用空间换时间,通过两次遍历分别计算前缀积和后缀积,将目标乘积拆分为左右两部分。先从前向后计算前缀积存入结果数组,再从后向前更新后缀积并与前缀积合并,既避免了除法运算,又满足了 O(n) 的时间复杂度要求,高效且准确地解决了问题 。这种解题过程体现了在算法设计中平衡时间复杂度、空间复杂度与题目限制条件的重要性。

        算法之美在于其严谨的逻辑与精巧的设计。希望读者能通过本题,掌握空间换时间的核心思想,在日后的开发中灵活运用这种预处理技巧。谢谢大家!!!荆轲刺秦!

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

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

相关文章

如何写好Verilog状态机

还记得之前软件的同事说过的一句话。怎么凸显自己的工作量&#xff0c;就是自己给自己写BUG。 看过夏宇闻老师书的都知道&#xff0c;verilog的FSM有moore和mealy,然后有一段&#xff0c;二段&#xff0c;三段式。记得我还是学生的时候&#xff0c;看到这里的时候&#xff0c;感…

晶振频率/稳定度/精度/温度特性的深度解析与测量技巧

在电子设备的精密世界里&#xff0c;晶振如同跳动的心脏&#xff0c;为各类系统提供稳定的时钟信号。晶振的频率、稳定度、精度以及温度特性&#xff0c;这些关键参数不仅决定了设备的性能&#xff0c;更在不同的应用场景中发挥着至关重要的作用。 一、频率选择的本质&#xff…

Kafka-可视化工具-Offset Explorer

安装&#xff1a; 下载地址&#xff1a;Offset Explorer 安装好后如图&#xff1a; 1、下载安装完毕&#xff0c;进行新增连接&#xff0c;启动offsetexplorer.exe&#xff0c;在Add Cluster窗口Properties 选项下填写Cluster name 和 kafka Cluster Version Cluster name (集…

LabVIEW模板之温度监测应用

这是一个温度监测应用程序&#xff0c;基于 Continuous Measurement and Logging 示例项目构建&#xff0c;用于读取模拟温度值&#xff0c;当温度超出给定范围时发出警报 。 这个。 详细说明 运行操作&#xff1a;直接运行该 VI 程序。点击 “Start” 按钮&#xff0c;即可开…

后端[特殊字符][特殊字符]看前端之Row与Col

是的&#xff0c;在 Ant Design 的栅格布局系统中&#xff0c;每个 <Row> 组件确实对应页面上的一个独立行。以下是更详细的解释&#xff1a; 核心概念 组件作用类比现实场景<Row>横向容器&#xff0c;定义一行内容类似 Excel 表格中的一行<Col>纵向分割&am…

[特殊字符] SpringCloud项目中使用OpenFeign进行微服务远程调用详解(含连接池与日志配置)

&#x1f4da; 目录 为什么要用OpenFeign&#xff1f; 在cart-service中整合OpenFeign 2.1 引入依赖 2.2 启用OpenFeign 2.3 编写Feign客户端 2.4 调用Feign接口 开启连接池&#xff0c;优化Feign性能 3.1 引入OkHttp 3.2 配置启用OkHttp连接池 3.3 验证连接池生效 Feign最佳…

VARIAN安捷伦真空泵维修清洁保养操作SOP换油操作流程内部转子图文并茂内部培训手侧

VARIAN安捷伦真空泵维修清洁保养操作SOP换油操作流程内部转子图文并茂内部培训手侧

【android bluetooth 案例分析 03】【PTS 测试 】【PBAP/PCE/SSM/BV-10-C】

1. PBAP/PCE/SSM/BV-10-C [PCE Does not share PbapSupportedFeatures bits] 这个 PTS 测试用例 PBAP/PCE/SSM/BV-10-C 的核心目的是验证 PBAP 客户端&#xff08;PCE&#xff09;在与旧版服务器通信时&#xff0c;不会发送 PbapSupportedFeatures 特性位&#xff0c;以确保兼…

批量删除OpenStack实例

在Linux终端实现批量删除OpenStack实例&#xff0c;支持并发删除、安全确认、重试机制、优先清理运行中实例 #!/bin/bash # # 增强版 OpenStack 删除实例脚本 # 功能&#xff1a;支持并发删除、安全确认、重试机制、优先清理运行中实例 # 更新&#xff1a;2025年4月30日 # ##…

# 基于 Python 和 jieba 的中文文本自动摘要工具

基于 Python 和 jieba 的中文文本自动摘要工具 在信息爆炸的时代&#xff0c;快速准确地提取文本核心内容变得至关重要。今天&#xff0c;我将介绍一个基于 Python 和 jieba 的中文文本自动摘要工具&#xff0c;帮助你高效地从长文本中提取关键信息。 一、背景与需求 在处理…

Seaborn数据可视化库

一、Seaborn介绍&#xff1a;基于Matplotlib的Python数据可视化库&#xff0c;专注绘制统计图形&#xff0c;简化可视化过程&#xff0c;提供高级接口和美观默认主题。 二、安装与导入 1.安装&#xff1a;可使用pip install seaborn或conda install seaborn&#xff0c;也可使…

机器视觉2D码垛和机器视觉3D码垛的区别

机器视觉3D码垛是一种结合3D视觉技术和工业机器人的自动化系统,主要用于在复杂环境中精准识别、定位并堆叠(码垛)各种形状、尺寸的物体。它通过3D传感器(如激光雷达、结构光相机、双目视觉等)获取物体的三维空间信息,并结合算法规划机器人的抓取路径和码放策略,实现高效…

Python魔法函数深度解析

一、魔法函数是什么&#xff1f; 魔法函数&#xff08;Magic Methods&#xff09;是Python中以双下划线&#xff08;__xx__&#xff09;包裹的特殊方法&#xff0c;它们为类提供了一种与Python内置语法深度集成的能力。这些方法由解释器自动调用&#xff0c;无需显式调用&…

C++负载均衡远程调用学习之自定义内存池管理

目录 1.内存管理_io_buf的结构分析 2.Lars_内存管理_io_buf内存块的实现 3.buf总结 4.buf_pool连接池的单例模式设计和基本属性 5.buf_pool的初始化构造内存池 6.buf_pool的申请内存和重置内存实现 7.课前回顾 1.内存管理_io_buf的结构分析 ## 3) Lars系统总体架构 ​ …

流水线问题(算法设计)C++

目录 一、需求分析 1.1 问题描述 1.2 数据需求 1.3 功能需求 1.4 开发环境 二、概要设计 2.1 抽象数据类型 ADT 的定义 2.2 系统的主要功能模块 2.3 功能模块联系图 三、详细设计 3.1 数据结构设计 3.2 主要算法 四、系统运行及结果分析 1. 用户界面 2. 程序运行…

从实列中学习linux shell4: shell 脚本中 $0 $1 $2 $3 >> 以及 awk 都是干啥的?

在 Linux Shell 脚本中&#xff0c;这些符号和工具的功能如下&#xff1a; 一、位置参数 $0 $1 $2 $3 符号功能说明示例$0脚本自身的文件名若执行 ./test.sh&#xff0c;则 $0 值为 ./test.sh$1第一个参数执行 ./test.sh apple 时&#xff0c;$1 值为 "apple"$2第二…

TM1668芯片学习心得三

一、键扫数据储存地址如下所示&#xff0c;先发读键命令后&#xff0c;开始读取按键数据BYTE1-BYTE5字节&#xff0c;读数据从低位开始输出&#xff0c;其中B6和B7位为无效位&#xff0c;此时芯片输出为0。芯片K和KS引脚对应的按键按下时&#xff0c;相对应的字节内的 BIT位为1…

MySQL 基本查询(一)

文章目录 Create(insert)指定列的单行插入和全列插入多行全列插入和指定列的多行插入如果主键存在&#xff0c;要插入替换存在的值replace 基本select全列查询指定列查询where子句where子句案例语文成绩在 [80, 90] 分的同学及语文成绩数学成绩是 58 或者 59 或者 98 或者 99 分…

LeetCode路径总和系列问题解析:I、II、III的解决方案与优化

文章目录 引言一、路径总和 I&#xff08;LeetCode 112&#xff09;问题描述方法思路Java代码实现复杂度分析 二、路径总和 II&#xff08;LeetCode 113&#xff09;问题描述方法思路Java代码实现复杂度分析 三、路径总和 III&#xff08;LeetCode 437&#xff09;问题描述方法…

NFC 碰一碰发视频贴牌技术,音频功能的开发实践与技术解析

在数字化营销与信息交互场景中&#xff0c;NFC 碰一碰技术凭借其便捷性和高效性&#xff0c;成为快速传递多媒体内容的新选择。通过 NFC 实现视频音频的快速传输&#xff0c;不仅能提升用户体验&#xff0c;还能为各类场景带来创新应用。本文将深入探讨该功能开发过程中的关键技…