【优选算法必刷100题】第027~28题(前缀和算法):寻找数组的中心下标、除自身以外数组的乘积

【优选算法必刷100题】第027~28题(前缀和算法):寻找数组的中心下标、除自身以外数组的乘积

🔥艾莉丝努力练剑:个人主页

专栏传送门:《C语言》《数据结构与算法》C/C++干货分享&学习过程记录Linux操作系统编程详解笔试/面试常见算法:从基础到进阶

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平


🎬艾莉丝的简介:



🎬艾莉丝的算法专栏简介:


目录

​027  寻找数组的中心下标

 1.1  算法思路:前缀和

1.2  算法实现

1.2.1  C++实现

1.2.2  Java实现

1.3  博主手记

​028  除自身以外数组的乘积

2.1  算法思路

2.2  算法实现

2.2.1  C++实现

2.2.2  Java实现

2.3  博主手记

结尾


027  寻找数组的中心下标

力扣链接:724. 寻找数组的中心下标

力扣题解链接:前缀和优化法解决【寻找数组的中心下标】问题

题目描述:

 

1.1  算法思路:前缀和

我们根据中心下标的定义可知:除中心下标的元素外,该元素左边的前缀和】等于该元素右边的【后缀和】——

(1)因此,我们可以先预处理出来两个数组,一个表示前缀和,另一个表示后缀和。
(2)然后,我们可以用一个for循环枚举可能的中心下标,判断每一个位置的「前缀和」以及【后缀和】,如果二者相等,就返回当前下标。

1.2  算法实现

1.2.1  C++实现

代码演示如下——

class Solution { public: int pivotIndex(vector<int>& nums) { // 数组大小 int n = nums.size(); vector<int> f(n),g(n); // // 细节处理 // int f[0] = 0,g[n - 1] = 0; // 1、预处理前缀和数组和后缀和数组 for(int i = 1;i < n;i++) // f[0] = 0,如果i = 0开始会发生越界访问 f[i] = f[i - 1] + nums[i - 1]; for(int i = n - 2;i >= 0;i--) g[i] = g[i + 1] + nums[i + 1]; // 2、使用 for(int i = 0;i < n;i++) if(f[i] == g[i]) return i; return -1; } };
时间复杂度:O(n),空间复杂度:O(1)。

 

1.2.2  Java实现

代码演示如下——

class Solution { public int pivotIndex(int[] nums) { // lsum[i] 表示:[0, i - 1] 区间所有元素的和 // rsum[i] 表示:[i + 1, n - 1] 区间所有元素的和 int n = nums.length; int[] lsum = new int[n]; int[] rsum = new int[n]; // 预处理前缀和后缀和数组 for (int i = 1; i < n; i++) lsum[i] = lsum[i - 1] + nums[i - 1]; for (int i = n - 2; i >= 0; i--) rsum[i] = rsum[i + 1] + nums[i + 1]; // 判断 for (int i = 0; i < n; i++) if (lsum[i] == rsum[i]) return i; return -1; } }
时间复杂度:O(n),空间复杂度:O(1)。  

 

1.3  博主手记

本题整个的思路、算法原理、解题过程博主在纸上推导了一遍,大家可以参考一下手记的推导过程!最好做题的过程中自己也推导一遍!!!自己能够推导很重要!

 


​028  除自身以外数组的乘积

力扣链接:238. 除自身以外数组的乘积

力扣题解链接:前缀后缀乘积法解决【除自身以外数组的乘积】

题目描述:

 

2.1  算法思路

注意题目的要求,不能使用除法,并且要在O(N)的时间复杂度内完成该题。那么我们就不能使
用暴力的解法,以及求出整个数组的乘积,然后除以单个元素的方法。
继续分析,根据题意,对于每一个位置的最终结果ret[i],它是由两部分组成的:

(1)nums[0] * nums[1] * nums[2] *  ...  *nums[i - 1]
(2)nums[i + 1] * nums[i + 2] * ... * nums[n - 1]

于是,我们可以利用前缀和的思想,使用两个数组post和suf,分别处理出来两个信息:

(1)post表示:i位置之前的所有元素,即[0,i - 1]区间内所有元素的前缀乘积;
(2)suf表示:i位置之后的所有元素,即[i + 1,n - 1]区间内所有元素的后缀乘积然后再处理最终结果。

2.2  算法实现

2.2.1  C++实现

代码演示如下——

class Solution { public: vector<int> productExceptSelf(vector<int>& nums) { // lprod 表示:[0, i - 1] 区间内所有元素的乘积 // rprod 表示:[i + 1, n - 1] 区间内所有元素的乘积 int n = nums.size(); vector<int> lprod(n + 1), rprod(n + 1); lprod[0] = 1, rprod[n - 1] = 1; // 预处理前缀积以及后缀积 for (int i = 1; i < n; i++) lprod[i] = lprod[i - 1] * nums[i - 1]; for (int i = n - 2; i >= 0; i--) rprod[i] = rprod[i + 1] * nums[i + 1]; // 处理结果数组 vector<int> ret(n); for (int i = 0; i < n; i++) ret[i] = lprod[i] * rprod[i]; return ret; } };
时间复杂度:O(n),空间复杂度:O(1)。

2.2.2  Java实现

代码演示如下——

class Solution { public int[] productExceptSelf(int[] nums) { // lprod 表示:[0, i - 1] 区间内所有元素的乘积 // rprod 表示:[i + 1, n - 1] 区间内所有元素的乘积 int n = nums.length; int[] lprod = new int[n]; int[] rprod = new int[n]; lprod[0] = 1; rprod[n - 1] = 1; // 预处理前缀积以及后缀积 for (int i = 1; i < n; i++) lprod[i] = lprod[i - 1] * nums[i - 1]; for (int i = n - 2; i >= 0; i--) rprod[i] = rprod[i + 1] * nums[i + 1]; // 处理结果数组 int[] ret = new int[n]; for (int i = 0; i < n; i++) ret[i] = lprod[i] * rprod[i]; return ret; } }
时间复杂度:O(n),空间复杂度:O(1)。

2.3  博主手记

本题整个的思路、算法原理、解题过程博主在纸上推导了一遍,大家可以参考一下手记的推导过程!最好做题的过程中自己也推导一遍!!!自己能够推导很重要!


结尾

往期回顾:

【优选算法必刷100题】第025~26题(前缀和算法):【模版】前缀和、【模板】二维前缀和

结语:都看到这里啦!请大佬不要忘记给博主来个“一键四连”哦!

🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡

૮₍ ˶ ˊ ᴥ ˋ˶₎ა


Read more

【C++动态库】动态库隐式与显式加载 | 为什么要动态加载动态库 | LoadLibrary加载失败 | 参考开源操作系统ReactOS源码 | 用LoadLibraryEx替代LoadLibrary

【C++动态库】动态库隐式与显式加载 | 为什么要动态加载动态库 | LoadLibrary加载失败 | 参考开源操作系统ReactOS源码 | 用LoadLibraryEx替代LoadLibrary

目录 1、概述 2、dll动态库的隐式加载与动态加载 2.1、dll库的隐式加载 2.2、dll库的显式加载 3、为什么要使用动态加载dll动态库的方式?什么时候需要使用动态加载? 3.1、调用系统dll库中未公开的接口 3.2、调用控件库中的注册接口向系统中注册该控件 3.3、底层的业务模块做成动态启动方式,上层产品可以根据自己的业务需要选择想启动的业务模块 4、LoadLibrary动态加载dll动态库失败的场景 4.1、自制的安装包程序中遇到的LoadLibrary加载dll库失败问题 4.2、主程序底层模块调用LoadLibrary加载dll库失败问题 5、 LoadLibaray加载失败的可能原因 6、参考开源操作系统ReactOS中的regsvr32.exe程序的实现源码,找到了解决LoadLibrary加载dll库失败的办法 6.1、ReactOS开源操作系统简介 6.2、使用Source Insight打开ReactOS源码,找到regsvr32.exe程序的代码 7、到微软MSDN上查看LOAD_WITH_

By Ne0inhk

C++ 排序函数sort()

一、sort () 函数是什么 在 C++ 的标准库中,sort()函数是一个强大且常用的工具,定义于<algorithm>头文件中 ,它就像是一个高效的 “排序大师”,专门负责对容器(如vector、array等)或普通数组中的元素进行排序。无论是处理简单的整数数组,还是复杂的自定义结构体,sort()函数都能轻松应对,将杂乱无章的数据按照我们期望的顺序排列得井然有序,为后续的数据处理和分析工作提供了极大的便利,接下来我们就深入了解一下它的具体使用方法。 二、sort () 函数基本语法 2.1 函数原型 sort()函数有两种常见的原型,能够适应不同的排序需求。第一种原型如下: template<class RandomAccessIterator> void sort (RandomAccessIterator first, RandomAccessIterator last); 在这个原型中,first和last都是随机访问迭代器,first指向要排序范围的起始位置,

By Ne0inhk
个人整理的超全C++ 八股文(全是干货)

个人整理的超全C++ 八股文(全是干货)

目录 C++ 面向对象和面向过程 面向过程 面向对象 三大特性? C语言和C++的区别? C++编译过程 多态 是什么? 分类? 虚函数 是什么? 底层? 解决的问题? 构造函数不能设置为虚函数? 重载 重写 隐藏 引用 是什么? 好处 为什么不能初始化为空? 引用与指针的区别? 内存分区 堆和栈的区别? 指针常量和常量指针 NULL在C语言中是(void *)0在C++中是0? C++用nullptr代指空指针? 构造函数 是什么? 拷贝构造 调用时机 拷贝构造参数不是引用行吗? 深浅拷贝的区别? 析构函数 是什么? 内存分配和销毁用什么? new和malloc 区别? new delete malloc free?

By Ne0inhk
【C++】第二十一节—一文详解 | 红黑树实现(规则+效率+结构+插入+查找+验证)

【C++】第二十一节—一文详解 | 红黑树实现(规则+效率+结构+插入+查找+验证)

Hi,我是云边有个稻草人......who?me,be like——→ 《C++》本篇文章所属专栏—持续更新中—欢迎订阅 目录 一、红黑树的概念 1.1 红黑树的规则 1.2 思考⼀下,红黑树如何确保最长路径不超过最短路径的2倍的? 1.3 红黑树的效率 二、红黑树的实现 2.1 红黑树的结构 2.2 红⿊树的插⼊ 【红⿊树树插⼊⼀个值的⼤概过程】 【情况1:变⾊】 【情况2:单旋+变⾊】 【情况2:双旋+变⾊】 2.3 红黑树的插入代码实现 2.4

By Ne0inhk