LeetCode 热题 100之普通数组

1.最大子数组和

在这里插入图片描述
思路分析:这个问题可以通过动态规划来解决,我们可以使用Kadane’s Algorithm(卡登算法)来找到具有最大和的连续子数组。

  • Kadane’s Algorithm 的核心思想是利用一个变量存储当前的累加和 currentSum,并通过每次与之前的最大子数组和 maxSum 比较,更新 maxSum。它在遍历过程中不断累加子数组的和,但一旦累加和变为负数时,放弃当前累加,从下一个元素重新开始累加。这样确保了子数组和始终是最大的。

  • 初始化:将 maxSum 和 currentSum 初始化为数组的第一个元素,即 nums[0]

  • 遍历数组

    • 从第二个元素开始,逐个元素检查累加currentSum;
      • currentSum = max(nums[i], currentSum + nums[i]):选择当前元素或当前累加和加上当前元素两者中的较大值。
      • 如果 currentSum 大于 maxSum,则更新 maxSum。
  • 返回结果:遍历完成后,maxSum 即为最大子数组的和。

具体实现代码(详解版):

class Solution {
public:int maxSubArray(std::vector<int>& nums) {int maxSum = nums[0];       // 初始化 maxSum 为数组第一个元素,用于存储最大子数组的和int currentSum = nums[0];    // 初始化 currentSum 为数组第一个元素,用于当前子数组的累加和// 遍历数组,从第二个元素开始(因为第一个元素已经初始化了)for (int i = 1; i < nums.size(); i++) {// 更新 currentSum,将当前元素和 currentSum + 当前元素 取较大值// 如果 currentSum + nums[i] 比 nums[i] 小,说明重新开始一个新的子数组会更大currentSum = max(nums[i], currentSum + nums[i]);// 更新 maxSum,存储最大子数组的和maxSum = max(maxSum, currentSum);}// 返回最大子数组的和return maxSum;}
};

2.合并区间

在这里插入图片描述
思路分析1(Acwing板子)
算法基础课-区间合并

具体实现代码(详解版):

class Solution {
public:vector<vector<int>> merge(vector<vector<int>>& intervals) {vector<vector<int>> res;  // 用于存放合并后的区间结果sort(intervals.begin(), intervals.end());  // 按区间起点升序排序// 初始化st和ed为一个极小的值,用于在第一次遍历时识别有效区间int st = -2e9, ed = -2e9;// 遍历所有区间for (int i = 0; i < intervals.size(); i++) {// 如果当前区间的起点大于当前的结束位置,则无重叠if (ed < intervals[i][0]) {// 如果是有效区间,将前一个区间加入结果中if (st != -2e9) res.push_back({st, ed});// 更新st和ed为当前区间的起点和终点st = intervals[i][0];ed = intervals[i][1];} else {// 当前区间与前一个区间重叠,合并区间ed = max(ed, intervals[i][1]);}}// 添加最后一个区间到结果中if (st != -2e9) res.push_back({st, ed});return res;}
};

思路分析2:直接遍历区间数组,判断是否有重叠。

具体实现代码(详解版):

class Solution {
public:vector<vector<int>> merge(vector<vector<int>>& intervals) {// 按区间的起始位置排序sort(intervals.begin(), intervals.end());// 用于存放合并后的结果vector<vector<int>> res;// 遍历区间数组for (const auto& interval : intervals) {// 如果结果数组为空或当前区间不与最后一个区间重叠,直接加入if (res.empty() || res.back()[1] < interval[0]) {res.push_back(interval);} else {// 否则,有重叠,更新最后一个区间的终点res.back()[1] = max(res.back()[1], interval[1]);}}return res;}
};

3.轮转数组

在这里插入图片描述
思路分析1:将后面k个元素和前面n-k个元素添加到res中即可。要注意k = k % n

具体实现代码(详解版):

class Solution {
public:void rotate(vector<int>& nums, int k) {int n = nums.size();k = k % n;  // 如果 k 大于数组长度,取余数来简化操作vector<int> res;// 将最后 k 个元素加入结果中for (int i = n - k; i < n; ++i) res.push_back(nums[i]);// 然后把前 n - k 个元素加在结果后面for (int i = 0; i < n - k; ++i) res.push_back(nums[i]);// 将旋转后的结果更新到原数组nums = res;}
};

思路分析2:直接进行反转,先整体反转,再将将前 k 个元素反转,再将剩余的 n-k 个元素反转
具体实现代码(详解版):

class Solution {
public:void rotate(vector<int>& nums, int k) {int n = nums.size();k = k % n;  // 计算实际旋转步数,防止 k 超出数组长度reverse(nums.begin(), nums.end());  // 1. 反转整个数组reverse(nums.begin(), nums.begin() + k);  // 2. 反转前 k 个元素reverse(nums.begin() + k, nums.end());  // 3. 反转剩余的 n-k 个元素}
};

在这里插入图片描述
很明显第二种方法更优!太快了!

4.除自身以外数组的乘积

在这里插入图片描述
思路分析:使用两个数组:一个数组存储每个元素左侧所有元素的乘积,另一个数组存储每个元素右侧所有元素的乘积。通过将这两个数组的对应元素相乘,得到每个位置的最终结果。

  • 初始化answer 数组初始化为 1,因为乘法的单位是 1
  • 左侧乘积
    • 我们使用一个变量 left_product 来存储当前元素左侧的乘积。
    • 对于每个元素 nums[i],我们将 left_product 的值赋给 answer[i],这表示在位置 i 的左侧乘积
    • 然后,更新 left_product,将 nums[i] 的值乘入,准备计算下一个位置。
  • 右侧乘积:我们继续使用之前的 answer 数组,它现在包含了每个元素左侧的乘积。接下来,我们将计算每个元素右侧的乘积。
    • 使用一个变量 right_product 来存储当前元素右侧的乘积,并将其初始化为 1。
    • 反向遍历
      • 对于每个元素 nums[i],将 right_product 的值乘入 answer[i],这样 answer[i] 就等于左侧乘积乘以右侧乘积
      • 更新 right_product,将 nums[i] 的值乘入,准备计算下一个位置。

具体实现代码(详解版):

class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {int n = nums.size();vector<int> answer(n, 1); // 初始化结果数组为 1// 1. 计算左侧的乘积int left_product = 1; // 初始化左侧乘积for (int i = 0; i < n; i++) {answer[i] = left_product; // 设置 answer[i] 为左侧乘积left_product *= nums[i];   // 更新左侧乘积}// 2. 计算右侧的乘积并更新结果int right_product = 1; // 初始化右侧乘积for (int i = n - 1; i >= 0; i--) {answer[i] *= right_product; // 将右侧乘积乘以之前的结果right_product *= nums[i];    // 更新右侧乘积}return answer; // 返回最终结果}
};

另一种写法:

class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {int n = nums.size();vector<int> answer(n, 1); // 初始化结果数组// 计算左侧乘积for (int i = 1; i < n; ++i) {answer[i] = answer[i - 1] * nums[i - 1];}// 计算右侧乘积并更新 answerint right_product = 1;for (int i = n - 1; i >= 0; --i) {answer[i] *= right_product; // 将右侧乘积乘入结果right_product *= nums[i];   // 更新右侧乘积}return answer;}
};

还有这种双指针的做法,也是大为简洁!值得借鉴!

std::vector<int> productExceptSelf2(std::vector<int>& nums) {std::vector<int> answer(nums.size(), 1); // 初始化输出数组int left = 0, right = nums.size() - 1; // 指针初始化int lp = 1, rp = 1; // 左侧乘积和右侧乘积// 双指针法while (right >= 0 && left < nums.size()) {answer[right] *= rp; // 更新右侧元素的乘积answer[left] *= lp; // 更新左侧元素的乘积lp *= nums[left++]; // 更新左侧乘积rp *= nums[right--]; // 更新右侧乘积}return answer; // 返回结果
}

5.缺失的第一个正数

在这里插入图片描述
思路分析:要在时间复杂度O(n) 和常数级空间复杂度下找到未排序数组 nums 中最小的缺失正整数,我们可以采用原地哈希(或称为置换排序)的方式。具体思路如下:

  • 目标:我们的目标是将每个正整数 x 放置在下标 x - 1 的位置上(例如,数字 1 应该放在下标 0 的位置,数字 2 应该放在下标 1,依此类推)。这样,如果数组中有数字 1, 2, …, n,它们都会出现在各自对应的位置上。
  • 交换过程
    • 遍历数组,如果nums[i]在[1,n]范围内,并且nums[i] != nums[nums[i] - 1],则将nums[i]放到其正确的位置num[i] -1。通过交换的方式来调整位置。
    • 不断重复交换,直至当前位置的数字被放到了正确的位置为止。此过程会在 O ( n ) O(n) O(n)时间内完成,因为每个元素最多只会被交换一次
  • 查找缺失的正整数
    • 再次遍历数组,找到第一个位置i,使得nums[i] != i + 1,此时i + 1就是我们要找的最小的缺失正整数
    • 如果所有位置都满足nums[i] == i + 1,那么数组中的所有正整数[1,n]都出现过,即最小缺失正整数为n + 1.

一个结论:不论数组 nums 是什么内容,数组长度为 N 时,最小缺失的正整数一定落在 [1, N+1]
这个范围内。这就是为什么算法中只需要关注 [1, N+1],而无需遍历其他更大的数字的原因。

具体实现代码(详解版):

class Solution {
public:int firstMissingPositive(vector<int>& nums) {int n = nums.size();//将每个数放到对应的位置for(int i = 0 ; i < n ; i ++){while(nums[i] > 0 && nums[i] <= n&& nums[i] != nums[nums[i] - 1] ){swap(nums[i],nums[nums[i] - 1]);}}//查找第一个位置i,使得nums[i] != i + 1for(int i = 0; i < n ; i ++){if(nums[i] != i + 1){return i + 1;}}//如果所有位置都正确,则返回 n + 1return n + 1;}
};

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

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

相关文章

MATLAB生物细胞瞬态滞后随机建模定量分析

&#x1f3af;要点 基于随机动态行为受化学主方程控制&#xff0c;定量分析单细胞瞬态效应。确定性常微分方程描述双稳态和滞后现象。通过随机性偏微分方程描述出暂时性滞后会逐渐达到平稳状态&#xff0c;并利用熵方法或截断方法计算平衡收敛速度的估计值。随机定量分析模型使…

python查询并安装项目所依赖的所有包

引言 如果需要进行代码的移植&#xff0c;肯定少不了在另一台pc或者服务器上进行环境的搭建&#xff0c;那么首先是要知道在已有的工程的代码中用到了哪些包&#xff0c;此时&#xff0c;如果是用人工去一个一个的代码文件中去查看调用了哪些包&#xff0c;这个工作甚是繁琐。…

C++《vector的模拟实现》

在之前《vector》章节当中我们学习了STL当中的vector基本的使用方法&#xff0c;了解了vector当中各个函数该如何使用&#xff0c;在学习当中我们发现了vector许多函数的使用是和我们之前学习过的string类的&#xff0c;但同时也发现vector当中一些函数以及接口是和string不同的…

H5实现PDF文件预览,使用pdf.js-dist进行加载

H5实现PDF文件预览&#xff0c;使用pdf.js-dist进行加载 一、应用场景 在H5平台上预览PDF文件是在原本已经开发完成的系统中新提出的需求&#xff0c;原来的系统业务部门是在PC端进行PDF的预览与展示&#xff0c;但是现在设备进行了切换&#xff0c;改成了安卓一体机进行文件…

基于neo4j的课程资源生成性知识图谱

你是不是还在为毕业设计苦恼&#xff1f;又或者想在课堂中进行知识的高效管理&#xff1f;今天给大家分享一个你一定会感兴趣的技术项目——基于Neo4j的课程资源生成性知识图谱&#xff01;&#x1f4a1; 这套系统通过知识图谱的形式&#xff0c;将课程资源、知识点和学习路径…

前端页面样式没效果?没应用上?

当我们在开发项目时会有很多个页面、相同的标签&#xff0c;也有可能有相同的class值。样式设置的多了&#xff0c;分不清哪个是当前应用的。我们可以使用网页的开发者工具。 在我们开发的网页中按下f12或&#xff1a; 在打开的工具中我们可以使用元素选择器&#xff0c;单击我…

渗透测试-百日筑基—SQL注入篇时间注入绕过HTTP数据编码绕过—下

day8-渗透测试sql注入篇&时间注入&绕过&HTTP数据编码绕过 一、时间注入 SQL注入时间注入&#xff08;也称为延时注入&#xff09;是SQL注入攻击的一种特殊形式&#xff0c;它属于盲注&#xff08;Blind SQL Injection&#xff09;的一种。在盲注中&#xff0c;攻击…

基于丑萌气质狗--C#的sqlserver学习

#region 常用取值 查询List<string> isName new List<string> { "第一", "第二", "第三", "第四" }; List<string> result isName.Where(m > m "第三").ToList();MyDBContext myDBnew MyDBContext(…

web3对象如何连接以太网络节点

实例化web3对象 当我们实例化web3对象&#xff0c;我们一般开始用本地址&#xff0c;如下 import Web3 from web3 var web3 new Web3(Web3.givenProvider || ws://localhost:5173)我们要和以太网进行交互&#xff0c;所以我们要将’ws://localhost:5173’的本地地址换成以太…

如何在短时间内入门并掌握深度学习?

如何在短时间内快速入门并掌握深度学习&#xff0c;是很多读者的困惑——晦涩难懂的数学 知识、复杂的算法、烦琐的编程……深度学习虽然让无数读者心怀向往&#xff0c;却也让不少人望而生畏&#xff0c;深感沮丧&#xff1a;时间没少花&#xff0c;却收效甚微。 如何才能更好…

python对文件的读写操作

任务:读取文件夹下的批量txt数据&#xff0c;并将其写入到对应的word文档中。 txt文件中包含&#xff1a;编号、报告内容和表格数据。写入到word当中&#xff1a;编号、报告内容、表格数据、人格雷达图以及对应的详细说明&#xff08;详细说明是根据表格中的标识那一列中的加号…

设计模式(二)工厂模式详解

设计模式&#xff08;二&#xff09;工厂模式详解 简单工厂模式指由一个工厂对象来创建实例,适用于工厂类负责创建对象较少的情况。例子&#xff1a;Spring 中的 BeanFactory 使用简单工厂模式&#xff0c;产生 Bean 对象。 工厂模式简介 定义&#xff1a;工厂模式是一种创建…

js构造函数和原型对象,ES6中的class,四种继承方式

一、构造函数 1.构造函数是一种特殊的函数&#xff0c;主要用来初始化对象 2.使用场景 常见的{...}语法允许创建一个对象。可以通过构造函数来快速创建多个类似的对象。 const Peppa {name: 佩奇,age: 6,sex: 女}const George {name: 乔治,age: 3,sex: 男}const Mum {nam…

pytorch的标签平滑介绍

什么是标签平滑(Label Smoothing)? 标签平滑(Label Smoothing)是一种正则化技术,旨在防止模型过度自信(即输出的概率分布过于“尖锐”)。在分类任务中,标准的目标标签是one-hot编码,也就是正确类别的概率为 1,其他类别的概率为 0。而标签平滑通过将正确类别的概率从…

小程序开发实战:PDF转换为图片工具开发

目录 一、开发思路 1.1 申请微信小程序 1.2 编写后端接口 1.3 后端接口部署 1.4 微信小程序前端页面开发 1.5 运行效果 1.6 小程序部署上线 今天给大家分享小程序开发系列&#xff0c;PDF转换为图片工具的开发实战&#xff0c;感兴趣的朋友可以一起来学习一下&#xff01…

基于Springboot无人驾驶车辆路径规划系统(源码+定制+开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

Hadoop:yarn的Rust API接口

今天头一次接触了yarn的Rust API接口&#xff0c;在本地搭建了集群&#xff0c;能够得到每个任务的详细信息。 (一)得到所有任务的所有信息命令&#xff1a; 默认是json格式&#xff0c;也可以指定xml的格式&#xff0c;如(curl --compressed -H "Accept: application/x…

【大模型理论篇】主流大模型的分词器选择及讨论(BPE/BBPE/WordPiece/Unigram)

1. 背景分析 分词是将输入和输出文本拆分成更小单位的过程&#xff0c;使得大模型能够处理。token可以是单词、字符、子词或符号&#xff0c;取决于模型的类型和大小。分词可以帮助模型处理不同的语言、词汇和格式&#xff0c;并降低计算和内存成本。分词还可以通过影响token的…

fmql之Linux RTC

模拟i2c&#xff0c;连接rtc芯片。 dts&#xff1a; /{ // 根节点i2c_gpio: i2c-gpio {#address-cells <1>;#size-cells <0>;compatible "i2c-gpio";// MIO56-SDA, MIO55-SCL // 引脚编号gpios <&portc 2 0&portc 1 0 >;i2c-gp…

Modbus TCP报错:Response length is only 0 bytes

问题描述&#xff1a; 使用modbus_tk库&#xff0c;通过Modbus tcp连接PLC时&#xff0c;python中的一个报错信息&#xff1a; Response length is only 0 bytes报错原因&#xff1a; 与Modbus TCP 服务端建立连接后没有断开&#xff0c;继续作为长连接使用&#xff0c;客户端…