力扣热题100——普通数组(不普通)

普通数组但一点不普通!

  • 最大子数组和
  • 合并区间
  • 轮转数组
  • 除自身以外数组的乘积
  • 缺失的第一个正数

最大子数组和

在这里插入图片描述
在这里插入图片描述

这道题是非常经典的适用动态规划解决题目,但同时这里给出两种解法
动态规划分治法
那么动态规划方法大家可以在我的另外一篇博客总结中看到,因此直接给出代码,着重讲第二道题

动态规划:

//使用动态规划方法
class Solution {
public:int ans = INT_MIN;//动态规划方法:令A[i]表示以i结尾的连续子数组的和int maxSubArray(vector<int>& nums) {int n = nums.size();int A[n];for(int i = 0;i<n;i++){if(!i){A[0] = nums[0];ans = nums[0];continue;}A[i] = max(A[i-1]+nums[i],nums[i]);ans = max(A[i],ans);}return ans;}
};

使用分治法
分治法就可以片面的理解为递归 若只是应对公司的笔试 不必分的那么清 咱又不写教科书:
分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。
1.我们来定义get(a,l,r)表示查询a序列 [l,r] 区间内的最大子段和,那么最终的答案就是get(nums,0,num.size()-1)。则实现分治法应该将区间进行划分:
对于一个区间[l,r],取m = [(l+r)/2],对区间[l,m]和[m+1,r]分治分解。当递归逐层深入直到区间长度缩小为1的时候,递归开始回升。
2. 对于一个区间[l,r] 我们可以维护四个量:
lSum表示[l,r]内以l为左端点的最大子段和;
rSum表示[l,r]内以r为右端点的最大子段和
msum表示[l,r]内的最大子段和
iSum表示[l,r]的区间和
以下简称[l,m]为[l,r]的左子区间,[m+1,r]为[l,r]的右子区间。且对于长度为1的区间[i,j],四个量的值都和nums[i]相等。

对于长度为1的区间:

  • 首先最好维护的是isum,区间[l,r]的iSum就等于[左子区间]的iSum加上[右子区间]的iSum。
  • 对于[l,r]的lSum,存在两种可能,要么等于左子区间的lSum,要么等于左子区间的iSum加上右子区间的lSum,二者取大。
  • 对于[l,r]的rSum,同理,要么等于右子区间的rSum,要么等于右子区间的iSum加上左子区间的rSum,二者取大。
  • 当计算好上面的三个量之后,就很好计算[l,r]的mSum了。可以考虑[l,r]的mSum对应的区间是否跨越m——它可能不跨越m,,也就是[l,r]的mSum可能是左子区间的mSum和右子区间的mSum中的一个;它也可能跨越m,可能是左子区间的rSum和右子区间的lSum求和。三者取大。
    下面给出代码:
class Solution{
public:struct Status{int lSum,rSum,mSum,iSum;};Status pushUp(Status l,Status r){int iSum = l.iSum + r.iSum;int lSum = max(l.lSum,l.iSum + r.lSum);int rSum = max(r.rSum,r.iSum+l.rSum);int mSum = max(max(l.mSum,r.mSum),l.rSum+r.lSum);return (Status) {lSum,rSum,mSum,iSum};};Status get(vector<int> &a,int l,int r){if(l==r){return (Status) {a[l],a[l],a[l],a[l]};}int m = (l+r)/2;Status lSub = get(a,l,m);Status rSub = get(a,m+1,r);return pushUp(lSub,rSub);}int maxSubArray(vector<int>& nums){return get(nums,0,nums.size()-1).mSum;}
};

合并区间

在这里插入图片描述
在这里插入图片描述

这道题的解题思路就是先将intervals内的区间按照左端点进行排序,再定义一个新的vector<vector<int>>数组merged,且如果下一个遍历到的区间的左端点如果比 比merged最后一个区间的右端点还要大,则两个区间就没有交集了,否则就将merged最后一个区间的右端点设置为merged最后一个区间的右端点与intervals中的当前区间中右端点这两者之间的最大值,以此循环即可。最后得到的merged数组便是最终的结果 。

下面给出代码:

class Solution{
public:vector<vector<int>> merge(vector<vector<int>>& intervals){if(intervals.size()==0) return {};//这里默认排序是左端点递增 左端点相同的话则按照右端点递增的顺序进行排序sort(intervals.begin(),intervals.end());vector<vector<int>> merged;for(int i=0;i<intervals.size();i++){int L = intervals[i][0], R = intervals[i][1];if(!merged.size()||merged.back()[1]<L){merged.push_back({L,R});}else{merged.back()[1] = max(merged.back()[1],R);}}return merged;}
}

轮转数组

在这里插入图片描述
在这里插入图片描述

这里给出使用额外数组和翻转数组的两种方法


1.使用额外数组与原数组元素的位置对应关系为:原数组下标为i的元素放至新数组下标为(i+k)%n的位置
下面给出代码:

class Solution{
public:void rotate(vector<int>& nums,int k){int n=nums.size();vector<int> newArr(n);//定义动态数组for(int i=0;i<n;i++){newArr[(i+k)%n] = nums[i];}nums.assign(newArr.begin(),newArr.end());//assign是STL的成员函数,用于替换容器中的元素,指定容器中的元素为新内容}
}

2.翻转数组:将原数组的末尾元素放至在数组的头部等价于是将整个数组进行翻转,然后将前[0,k-1]个元素翻转,再将[k,n-1]的元素进行翻转,示例如下:
在这里插入图片描述
下面给出代码:

class Solution{
public:void reverse(vector<int>& nums,int start,int end){swap(nums[start],nums[end]);start++;end--;}void rotate(vector<int>& nums,int k){k %= nums.size();reverse(nums,0,nums.size()-1);reverse(nums,0,(k-1));reverse(nums,k,nums.size()-1);}
}

除自身以外数组的乘积

在这里插入图片描述
在这里插入图片描述

这道题按照你以为的常规的方法做会超时,笔者已经试过了类似下面这样吧

        // int n = nums.size();// vector<int> answer(n);// for(int i=0;i<n;i++){//     int res=1;//     for(int j=0;j<n;j++){//         if(i!=j){//             res *=nums[j];//         }//     }//     answer[i] = res;// }// return answer;

这道题跟PAT算法题的"几个PTA"这道例题很像,这里应该采用活用递推的方法求解,即根据当前位置的数值应该是左边的乘积乘以右边数的乘积,对左右两边乘积可以用两个数组存放
于是有了下面的做法

class Solution{
public:vector<int> productExcepSelf(vector<int>& nums){int n = nums.size();vector<int> answer(n);vector<int> L(n,0),R(n,0); //L,R代表左右两侧的乘积列表L[0] = 1;//索引为‘0’的元素,因为左侧没有元素 因此L[0] = 1;for(int i = 1;i<n;i++){L[i] = nums[i-1]*L[i-1];}R[n-1]=1;//最后一个元素的右侧没有元素 for(int i=n-2;i>=0;i--){R[i] = nums[i+1]*R[i+1];}//以上便定义好了两个列表//对于索引i,除nums[i]之外其余各元素的乘积就是左侧所有元素的乘积乘以右侧所有元素的乘积for(int i=0;i<n;i++){answer[i] = L[i]*R[i];}return answer;}
}

此处为了降低空间的复杂度 先试用answer数组作为左侧乘积的列表,answer[i]代表的是i左侧乘积的列表。 不构造R数组,用一个遍历跟踪右侧乘积并更新数组answer[i] = answer[i] * R,然后更新R = R*nums[i],其中变量R表示的就是索引右侧数字的乘积。

class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {int length = nums.size();vector<int> answer(length);// answer[i] 表示索引 i 左侧所有元素的乘积// 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1answer[0] = 1;for (int i = 1; i < length; i++) {answer[i] = nums[i - 1] * answer[i - 1];}// R 为右侧所有元素的乘积// 刚开始右边没有元素,所以 R = 1int R = 1;for (int i = length - 1; i >= 0; i--) {// 对于索引 i,左边的乘积为 answer[i],右边的乘积为 Ranswer[i] = answer[i] * R;// R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上R *= nums[i];}return answer;}
};

缺失的第一个正数

在这里插入图片描述
在这里插入图片描述

这道题直接秒了:
先看我的做法:

class Solution {
public:int firstMissingPositive(vector<int>& nums) {sort(nums.begin(),nums.end());int j=1;for(int i =0;i<nums.size();i++){if(j==nums[i]) j++;if(j<nums[i]) return j;}return j;}
};

下面还是给一个更加规范的做法:
对于一个长度为 N 的数组,其中没有出现的最小正整数只能在 [1,N+1] 中。这是因为如果 [1,N] 都出现了,那么答案是 N+1,否则答案是 [1,N] 中没有出现的最小正整数。这样一来,我们将所有在 [1,N] 范围内的数放入哈希表,也可以得到最终的答案。而给定的数组恰好长度为 N,这让我们有了一种将数组设计成哈希表的思路:
对数组进行遍历,对于遍历到的数x,如果它在[1,N]的范围内,那么就将数组中的第x-1个位置打上[标记](数组下标从0开始)。在遍历结束之后,如果所有的位置都被打上了标记,那么答案是N+1,否则答案是最小的没有打上标记的位置+1。
但问题是应该如何标记 考虑到不在1-N内的话 就是N+1;则考虑将所有非整数都变为N+1;然后遍历数组中的每一个数x,他可能已经被打了标记,因此原本对应的数为|x|,其中| |为绝对值符号。如果|x|在[1,N],那么我们给数组中的第|x|-1个位置的数添加一个负号。
在这里插入图片描述

class Solution {
public:int firstMissingPositive(vector<int>& nums) {int n = nums.size();for (int& num: nums) {if (num <= 0) {num = n + 1;}}for (int i = 0; i < n; ++i) {int num = abs(nums[i]);if (num <= n) {nums[num - 1] = -abs(nums[num - 1]);}}for (int i = 0; i < n; ++i) {if (nums[i] > 0) {return i + 1;}}return n + 1;}
};

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

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

相关文章

矩阵基础+矩阵转置+矩阵乘法+行列式与逆矩阵

GPU渲染过程 矩阵 什么是矩阵&#xff08;Matrix&#xff09; 向量 &#xff08;3&#xff0c;9&#xff0c;88&#xff09; 点乘&#xff1a;计算向量夹角 叉乘&#xff1a;计算两个向量构成平面的法向量。 矩阵 矩阵有3行&#xff0c;2列&#xff0c;所以表示为M32 获取固…

MySQL之text字段详细分类说明

在 MySQL 中&#xff0c;TEXT 是用来存储大量文本数据的数据类型。TEXT 类型可以存储非常长的字符串&#xff0c;比 VARCHAR 类型更适合存储大块的文本数据。TEXT 数据类型分为以下几个子类型&#xff0c;每个子类型用于存储不同大小范围的文本数据&#xff1a; TINYTEXT: 可以…

超详细!Android 面试题大汇总与深度解析

一、Java 与 Kotlin 基础 1. Java 的多态是如何实现的&#xff1f; 多态是指在 Java 中&#xff0c;同一个行为具有多个不同表现形式或形态的能力。它主要通过方法重载&#xff08;Overloading&#xff09;和方法重写&#xff08;Overriding&#xff09;来实现。 方法重载&a…

如何提高webrtc操作跟手时间,降低延迟

第一次做webrtc项目&#xff0c;操作延迟&#xff0c;一直是个问题&#xff0c;多次调试都不能达到理想效果。偶尔发现提高jitterBuffer时间可以解决此问题。关键代码 const _setJitter (values: number) > { const receives peerConnection.getReceivers();receives.f…

语音合成(TTS)从零搭建一个完整的TTS系统-第一节-效果演示

一、概述 语音合成又叫文字转语音&#xff08;TTS-text to speech &#xff09;&#xff0c;本专题我们记录从零搭建一个完整的语音合成系统&#xff0c;包括文本前端、声学模型和声码器&#xff0c;从模型训练到系统的工程化实现&#xff0c;模型可以部署在手机等嵌入式设备上…

实验三 I/O地址译码

一、实验目的 掌握I/O地址译码电路的工作原理。 二、实验电路 实验电路如图1所示&#xff0c;其中74LS74为D触发器&#xff0c;可直接使用实验台上数字电路实验区的D触发器&#xff0c;74LS138为地址译码器&#xff0c; Y0&#xff1a;280H&#xff5e;287H&…

Linux 使用Nginx搭建简易网站模块

网站需求&#xff1a; 一、基于域名[www.openlab.com](http://www.openlab.com)可以访问网站内容为 welcome to openlab ​ 二、给该公司创建三个子界面分别显示学生信息&#xff0c;教学资料和缴费网站&#xff0c;基于[www.openlab.com/student](http://www.openlab.com/stud…

MyBatis 如何使用

1. 环境准备 添加依赖&#xff08;Maven&#xff09; 在 pom.xml 中添加 MyBatis 和数据库驱动依赖&#xff1a; <dependencies><!-- MyBatis 核心库 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId&g…

ArkTS组件的三个通用(通用事件、通用属性、通用手势)

文章目录 通用事件点击事件 onClick触摸事件 onTouch挂载、卸载事件拖拽事件按键事件 onKeyEvent焦点事件鼠标事件悬浮事件组件区域变化事件 onAreaChange组件尺寸变化事件组件可见区域变化事件组件快捷键事件自定义事件分发自定义事件拦截 通用属性尺寸设置位置设置布局约束边…

智慧城市像一张无形大网,如何紧密连接你我他?

智慧城市作为复杂巨系统&#xff0c;其核心在于通过技术创新构建无缝连接的网络&#xff0c;使物理空间与数字空间深度融合。这张"无形大网"由物联网感知层、城市数据中台、人工智能中枢、数字服务入口和安全信任机制五大支柱编织而成&#xff0c;正在重塑城市运行规…

【python】django sqlite版本过低怎么办

方法一&#xff1a;下载最新版本 复制上面的内容的链接 在服务器上进行操作 wget https://sqlite.org/2025/sqlite-autoconf-3490100.tar.gz tar -zxvf sqlite-autoconf-3490100.tar.gz cd sqlite-autoconf-3490100 ./configure --prefix/usr/local make && make in…

PyTorch - Tensor 学习笔记

上层链接&#xff1a;PyTorch 学习笔记-CSDN博客 Tensor 初始化Tensor import torch import numpy as np# 1、直接从数据创建张量。数据类型是自动推断的 data [[1, 2],[3, 4]] x_data torch.tensor(data)torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])输出&am…

【技术派后端篇】ElasticSearch 实战指南:环境搭建、API 操作与集成实践

1 ES介绍及基本概念 ElasticSearch是一个基于Lucene 的分布式、高扩展、高实时的基于RESTful 风格API的搜索与数据分析引擎。 RESTful 风格API的特点&#xff1a; 接受HTTP协议的请求&#xff0c;返回HTTP响应&#xff1b;请求的参数是JSON&#xff0c;返回响应的内容也是JSON…

从标准九九表打印解读单行表达式的书写修炼(Python)

解读单行表达式书写&#xff0c;了解修习单行捷径。 笔记模板由python脚本于2025-04-16 23:24:17创建&#xff0c;本篇笔记适合喜欢单行喜好python的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思考与经验&#xff0c;而不仅仅是知识的简单复述…

深入解析布尔注入:原理、实战与防御

目录 一、布尔注入的原理与核心逻辑 二、布尔注入的实战步骤 三、关键函数与绕过技巧 四、实战案例&#xff1a;获取数据库名称 五、防御策略与最佳实践 六、总结 一、布尔注入的原理与核心逻辑 布尔注入&#xff08;Boolean-Based Blind SQL Injection&#xff09;是一种…

OpenGL学习笔记(几何着色器、实例化、抗锯齿)

目录 几何着色器爆破物体法向量可视化 实例化&#xff08;偏移量存在uniform中&#xff09;实例化数组&#xff08;偏移量存在顶点属性中&#xff09;小行星带 抗锯齿SSAA&#xff08;Super Sample Anti-aliasing&#xff09;MSAA&#xff08;Multi-Sampling Anti-aliasing&…

idea报错java: 非法字符: ‘\ufeff‘解决方案

解决方案步骤以及说明 BOM是什么&#xff1f;1. BOM的作用2. 为什么会出现 \ufeff 错误&#xff1f;3. 如何解决 \ufeff 问题&#xff1f; 最后重新编译&#xff0c;即可运行&#xff01;&#xff01;&#xff01; BOM是什么&#xff1f; \ufeff 是 Unicode 中的 BOM&#xff0…

open webui 介绍 是一个可扩展、功能丰富且用户友好的本地部署 AI 平台,支持完全离线运行。

AI MCP 系列 AgentGPT-01-入门介绍 Browser-use 是连接你的AI代理与浏览器的最简单方式 AI MCP(大模型上下文)-01-入门介绍 AI MCP(大模型上下文)-02-awesome-mcp-servers 精选的 MCP 服务器 AI MCP(大模型上下文)-03-open webui 介绍 是一个可扩展、功能丰富且用户友好的…

Log4j2远程命令执行(CVE-2021-44228)复现

这里选择使用vulfocue的靶场来进行复现 描述: Apache Log4j2 是一个基于 Java 的日志记录工具。该工具重写了 Log4j 框架&#xff0c;并且引入了大量丰富的特性。该日志框架被大量用于业务系统开发&#xff0c;用来记录日志信息。 在大多数情况下&#xff0c;开发者可能会将用…

模型提示词

一 提示词 &#xff08;一&#xff09; 提示词&#xff08;Prompt&#xff09;是用户发送给大语言模型的问题、指令或请求&#xff0c;** 1 来明确地告诉模型用户想要解决的问题或完成的任务&#xff0c;是大语言模型理解用户需求并据此生成相关、准确回答或内容的基础。对于…