LeetCode Hot100 - 普通数组篇

前言

        没能一个月刷完力扣hot100,但还是要继续刷下去,记录一下每题的思路~

        这次是普通数组相关的题目

(1)53. 最大子数组和

暴力求出每种子数组和,超时

动规,f(i+1)=max(nums[i]+f(i),nums[i])。

        设f(i)为以i结尾的子串最大和,即ans=最大的f(i),可得f(i+1)为nums[i+1]考虑加不加f(i),取更大的结果。

        滚动数组思想:用pre记录f(i-1),f(i)=max(pre+nums[i],nums[i]),并用maxAns记录pre最大值,即为最终结果

class Solution {public int maxSubArray(int[] nums) {// 设f(i)为,以i结尾的子串最大和,即ans=最大的f(i)// 并且f(i+1)考虑为nums[i+1]考虑加不加f(i),取更大的结果// 滚动数组思想:用pre记录f(i-1),f(i)=max(pre+nums[i],nums[i])int pre=0, maxAns=nums[0];for(int n:nums){pre=Math.max(pre+n,n);maxAns=Math.max(maxAns,pre);}return maxAns;}
}

前缀和。区间[l,r]和为preSum(r)-preSum[l]。

        对于每个位置i的前缀和,记录前面最小前缀和minPreSum,即得该位置的最大区间和pre(i)-minPreSum,每次取最大即为结果

class Solution {public int maxSubArray(int[] nums) {int ans = Integer.MIN_VALUE, minPreSum=0, preSum=0;for(int n:nums){preSum+=n; // 前缀和ans = Math.max(ans,preSum-minPreSum); // 最大区间minPreSum = Math.min(minPreSum,preSum); // 最小前缀和}return ans;}
}

分治法,类似线段树。

        对每个节点维护l(l为左端点)、r(r为右端点)、m(区间最大和)、i(区间总和)四个变量。

        深度遍历更新每个节点信息l=max(左l, 左i+右l),r=max(右r, 右i+左r),m=max(max(左m, 右m), 左r+右l),i=左i+右i,最后返回根的m。

        不仅可以解决区间 [0,n−1],还可以用于解决任意的子区间 [l,r] 的问题

class Solution {public class Status{public int lSum,rSum,mSum,iSum;public Status(int lSum,int rSum,int mSum,int iSum){this.lSum=lSum; // l为左端点this.rSum=rSum; // r为右端点this.mSum=mSum; // 最大和this.iSum=iSum; // 总和}}public int maxSubArray(int[] nums) {return getInfo(nums,0,nums.length-1).mSum;}public Status getInfo(int[] a,int l,int r){if(l==r)return new Status(a[l],a[l],a[l],a[l]); // 叶节点// 分治int m = (l+r)>>1;Status lSub = getInfo(a,l,m);Status rSub = getInfo(a,m+1,r);return pushUp(lSub,rSub); // 更新信息}public Status pushUp(Status l,Status r){int iSum = l.iSum + r.iSum; // 总和int lSum = Math.max(l.lSum, l.iSum+r.lSum); // 左l,左i加右lint rSum = Math.max(r.rSum, r.iSum+l.rSum); // 右r,右i加左rint mSum = Math.max(Math.max(l.mSum,r.mSum), l.rSum+r.lSum); // 左右m,左r加右lreturn new Status(lSum,rSum,mSum,iSum);}
}

(2)56. 合并区间

        排序合并。按左端点升序,用l、r记录当前处理区间;判断前后区间是否重合,重合则更新r,合并区间取右端点最大值;无重合就记录l、r并记录下一个区间。单独记录最后一种情况

class Solution {public int[][] merge(int[][] intervals) {List<int[]> res = new ArrayList<>();Arrays.sort(intervals,(a,b)->a[0]-b[0]); // 第一个元素升序int l=intervals[0][0], r=intervals[0][1];for(int i=1;i<intervals.length;i++){if(intervals[i][0]<=r)r=Math.max(r,intervals[i][1]); // 重合else{res.add(new int[]{l,r}); // 记录l=intervals[i][0];r=intervals[i][1];}}res.add(new int[]{l,r}); // 最后一种情况return res.toArray(new int[res.size()][]);}
}

(3)189. 轮转数组

额外数组。逐个将nums中i位置,复制到ans的(i+k)%n位置,最后将ans用System.arraycopy复制到nums中

class Solution {public void rotate(int[] nums, int k) {int n =nums.length;int[] ans = new int[n];for(int i=0;i<n;i++)ans[(i+k)%n]=nums[i]; // 逐个拷贝System.arraycopy(ans,0,nums,0,n);}
}

环形替换。使用temp记录下一个要替换的元素,会出现环形

        设走了a圈、处理了b个元素,即an=bk,为经过总元素为n、k的最小公倍数lcm=bk,遍历次数为n/b=nk/lcm=gcd最大公约数

        因此遍历gcd次,每次前后替换,直到回到起点,进行下一个环形

class Solution {public void rotate(int[] nums, int k) {int n=nums.length;k = k%n; // k小于n// 走了a圈、处理了b个元素,即an=bk,为经过总元素为n、k的最小公倍数lcm=bk// 遍历次数为n/b=nk/lcm=gcd最大公约数int count = gcd(k,n);for(int start=0; start<count; start++){int cur = start, pre = nums[start]; // 当前元素do{int next = (cur+k)%n, temp = nums[next]; // 下一个元素nums[next] = pre; // 更换pre = temp; // 更新precur = next; // 更新cur}while(start!=cur); // 若相等则回到起点}}// 最大公约数,欧几里得算法(辗转相除法)public int gcd(int x, int y){return y>0 ? gcd(y,x%y) : x;}
}

③如果理解不了最大公约数的,可以看看这个方法。环形替换,大致同上。

        count记录已处理元素,当count为n时结束。start从0开始,每次前后替换,直到回到起点,进行下一个环形

class Solution {public void rotate(int[] nums, int k) {int n=nums.length;k = k%n; // k小于nint count = 0; // 处理元素总数for(int start=0; start<n; start++){ // 遍历次数不定int cur = start, pre = nums[start]; // 当前元素do{int next = (cur+k)%n, temp = nums[next]; // 下一个元素nums[next] = pre; // 更换pre = temp; // 更新precur = next; // 更新curif(++count==n)return; // 每个元素处理完}while(start!=cur); // 若相等则回到起点}}// 最大公约数,欧几里得算法(辗转相除法)public int gcd(int x, int y){return y>0 ? gcd(y,x%y) : x;}
}

数组反转。先整体反转,再分别反转前k个和后n-k个,用双指针实现数组反转

class Solution {public void rotate(int[] nums, int k) {int n = nums.length;k %= n;reverse(nums,0,n-1); // 整体反转reverse(nums,0,k-1); // 前k个reverse(nums,k,n-1); // 后n-k个}public void reverse(int[] nums, int l, int r){ // 反转数组while(l<r){int temp = nums[l];nums[l++] = nums[r];nums[r--] = temp;}}
}

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

前后缀乘积,不包括自己,其余元素乘积即前后缀乘积的乘积

class Solution {public int[] productExceptSelf(int[] nums) {int n = nums.length;int[] ans = new int[n];int[] prefix = new int[n], suffix = new int[n]; // 前后缀乘积prefix[0]=1; suffix[n-1]=1; // 初始化for(int i=1;i<n;i++){ // 计算prefix[i]=prefix[i-1]*nums[i-1];suffix[n-i-1]=suffix[n-i]*nums[n-i];}for(int i=0;i<n;i++) ans[i]=prefix[i]*suffix[i]; // 元素前后缀乘积return ans;}
}

②前后缀乘积,仅使用结果数组,先用ans记录前缀乘积,不包括自己,用suffix变量记录后缀乘积,不包括自己,从后遍历ans*=suffix

class Solution {public int[] productExceptSelf(int[] nums) {int n = nums.length;int[] ans = new int[n];ans[0]=1; // 初始化for(int i=1;i<n;i++) ans[i]=ans[i-1]*nums[i-1]; // 计算前缀乘积int suffix=1; // 后缀乘积for(int i=n-1;i>=0;i--){ // 计算后缀乘积和结果ans[i]*=suffix;suffix*=nums[i];}return ans;}
}

(5)41. 缺失的第一个正数

排序,跳过非正数,target记录目标正数,一直往后匹配,注意跳过重复出现的数

class Solution {public int firstMissingPositive(int[] nums) {Arrays.sort(nums); // 排序int index = 0, target = 1, n = nums.length;while(index<n&&nums[index]<=0)index++; // 跳过非正数if(index==n) return 1;while(index<n&&nums[index]==target){ // 目标正数index++;while(index<n&&nums[index]==target)index++; // 跳过重复数target++;}return target;}
}

哈希,记录长度为n的flag数组

        nums中1-n+1至少有个数不存在。对于nums中值在1-n范围的数,将flag对应下标位置设为true;遍历flag第一个为false的位置没出现,如果flag全为true,则n+1一定没出现

class Solution {public int firstMissingPositive(int[] nums) {int n = nums.length;boolean[] flag = new boolean[n]; // 标志位,1-n+1一定会少一个for(int num:nums) if(num>0&&num<=n)flag[num-1]=true; // 出现就设truefor(int i=0;i<n;i++)if(!flag[i])return i+1; // 没出现该数,返回return n+1; // 1-n都出现,n+1不存在}
}

③哈希,同上。

        用nums作为flag,先将负数置为n+1;再将每个绝对值在0-n的数,对应的下标置为负数值,不改变绝对值;遍历nums,第一个为负数的值,对应下标的值为结果

class Solution {public int firstMissingPositive(int[] nums) {int n = nums.length;for(int i=0;i<n;i++) if(nums[i]<=0)nums[i]=n+1; // 负数置为n+1for(int num:nums) { // 将1-n范围的数,对应下标的值置为负数,标记该下标对应值出现num = Math.abs(num); // 之前可能被置为负数,要取绝对值if(num<=n)nums[num-1]=-Math.abs(nums[num-1]); // 只改为负数,不改变绝对值}for(int i=0;i<n;i++) if(nums[i]>0)return i+1;return n+1; // 1-n都出现,n+1不存在}
}

置换。对于每个位置i的值t,若t在1-n之间且t-1位置的值不为t,交换i与t-1位置的值,并循环判断i位置是否要继续交换,直到遍历完

class Solution {public int firstMissingPositive(int[] nums) {int n = nums.length;for(int i=0;i<n;i++){ // 对于每个数int t = nums[i];// t在1-n范围,且t-1位置值不为twhile(t>0&&t<=n&&nums[t-1]!=t){ nums[i] = nums[t-1];nums[t-1] = t;t = nums[i]; // 新nums[i]可能还要交换,更新t值}}for(int i=0;i<n;i++) if(nums[i]!=i+1)return i+1;return n+1;}
}

总结

        ①最大子数组和动规:以位置i结尾,比较是否加入以i−1结尾的最大子数组和,取最大值。前缀和:以i结尾的最大子数组和,为当前前缀和减去之前的最小前缀和,取最大值。线段树:用lrmi四个变量记录每个节点,下标从0-n-1深度遍历构建树,回溯得到最大子数组和。

        ②合并区间。区间左端点升序,合并重合区间

        ③轮转数组额外数组:逐个元素复制。环形替换:遍历次数为最大公约数,每次替换后一个元素,也可以判断元素替换个数为n时结束。反转数组:三次反转

        ④除自身以外数组的乘积。预处理前后缀乘积,可以先得出前缀乘积数组,再用变量记录后缀乘积,逐个计算结果

        ⑤缺失的第一个正数。1-n+1一定有个数不存在。排序:逐个判断,注意去重。哈希映射下标:用flag数组,也可以将原数组中绝对值在1-n范围的值t,对应下标t-1位置值置负,剩下值为正的下标位置为缺失值。置换:遍历每个位置i与值t对应位置t-1进行交换,循环判断

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

PDF电子发票信息转excel信息汇总

PDF电子发票信息提取&#xff0c;支持将pdf发票文件夹下的剩所有发票&#xff0c;转为excel格式的信息&#xff0c;对于发票量比较大&#xff0c;不好统计&#xff0c;需要一个一个去统计的情况&#xff0c;可节省2个点以上的时间&#xff0c;一次下载&#xff0c;终身有效。 使…

51c视觉~合集7

我自己的原文哦~ https://blog.51cto.com/whaosoft/11536996 #Arc2Face 身份条件化的人脸生成基础模型&#xff0c;高一致性高质量的AI人脸艺术风格照生成 将人脸特征映射到SD的CLIP的编码空间&#xff0c;通过微调SD实现文本编码器转换为专门为将ArcFace嵌入投影到CLIP潜在…

【西瓜书】机器学习的模型评估

来源于西瓜书、南瓜书等内容。 误差与偏差 学习器的实际预测输出与样本的真实输出之间的差异&#xff0c;称为”误差“&#xff08;error&#xff09;。学习器在训练集上的误差&#xff0c;称为”训练误差“&#xff08;training error&#xff09;或”经验误差“&#xff08;…

Mac安装Docker Desktop搭建K8s集群,解决镜像无法下载的问题

使用 Docker Desktop可以在本地方便地搭建出 K8s集群&#xff0c;但开启 K8s集群后往往会遇到 K8s 镜像拉取失败问题&#xff0c;本文旨在解决该问题&#xff0c;从而在本地搭建 K8s 集群。 安装Docker Desktop 安装 Docker Desktop 建议安装历史版本, 不建议安装最新版。因为…

【Leecode】Leecode刷题之路第54天之旋转矩阵

题目出处 54-螺旋矩阵-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 54-旋转矩阵-官方解法 方法1&#xff1a;模拟 思路&#xff1a; 代码示例&#xff1a;&#xff08;Java&#xff…

【YOLOv8】安卓端部署-1-项目介绍

【YOLOv8】安卓端部署-1-项目介绍 1 什么是YOLOv81.1 YOLOv8 的主要特性1.2 YOLOv8分割模型1.2.1 YOLACT实例分割算法之计算掩码1.2.1.1 YOLACT 的掩码原型与最终的掩码的关系1.2.1.2 插值时的目标检测中提取的物体特征1.2.1.3 coefficients&#xff08;系数&#xff09;作用1.…

Cesium教程01_实现Cartesian3 三维坐标操作

在 Vue 项目中使用 Cesium 实现 Cartesian3 三维坐标操作 目录 一、引言二、Cesium 与 Cartesian3 的优势三、示例应用&#xff1a;在地图上标注和计算距离 1. 项目结构2. 主要代码实现3. 运行与效果 四、代码讲解与扩展 1. Cartesian3 的基础操作2. 距离计算与中点标注 五、…

Qt5-雷达项目

界面: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QTimer> #include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);~Widget(); pr…

A040-基于springboot的智能停车计费系统设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

数据结构初识

目录 1.初识 2.时间复杂度 常见时间复杂度举例&#xff1a; 3.空间复杂度 4.包装类&简单认识泛型 4.1装箱和拆箱 5.泛型 6.泛型的上界 7.泛型方法 8.List接口 1.初识 1.多画图 2.多思考 3.多写代码 4.多做题 牛客网-题库/在线编程/剑指offer 算法篇&#xff1a…

CUDA HOME does not exist, unable to compile CUDA op(s),已解决

有一个服务器上没有/usr/loacl/cuda&#xff0c;我也没有权限在这个目录装cuda&#xff0c;使用pip装完torch&#xff0c;llama factory使用时出现&#xff1a; 应该是本地没有nvcc相关执行文件。 先使用了&#xff1a; conda install -c cudatoolkit-dev不管用&#xff0c; …

杰发科技AC7801——ADC定时器触发的简单使用

使用场景 在需要多次采样结果的情况下&#xff0c;比如1s需要10w次的采样结果&#xff0c;可以考虑使用定时器触发采样&#xff0c;定时器设置多少的时间就会多久采样转换一次。 再加上使用dma&#xff0c;采样的结果直接放在dma的数组里面。 实现了自动采样&#xff0c;自动…

【有啥问啥】基于文本的图像检索(Text-Based Image Retrieval, TBIR)技术详解

基于文本的图像检索&#xff08;Text-Based Image Retrieval, TBIR&#xff09;技术详解 1. 背景理论知识 1.1 什么是基于文本的图像检索&#xff08;TBIR&#xff09;&#xff1f; 基于文本的图像检索&#xff08;Text-Based Image Retrieval&#xff0c;简称TBIR&#xff…

探索PyMuPDF:Python中的强大PDF处理库

文章目录 **探索PyMuPDF&#xff1a;Python中的强大PDF处理库**第一部分&#xff1a;背景第二部分&#xff1a;PyMuPDF是什么&#xff1f;第三部分&#xff1a;如何安装这个库&#xff1f;第四部分&#xff1a;至少5个简单的库函数使用方法第五部分&#xff1a;结合至少3个场景…

HarmonyOS Next 关于页面渲染的性能优化方案

HarmonyOS Next 关于页面渲染的性能优化方案 HarmonyOS Next 应用开发中&#xff0c;用户的使用体验至关重要。其中用户启动APP到呈现页面主要包含三个步骤&#xff1a; 框架初始化页面加载布局渲染 从页面加载到布局渲染中&#xff0c;主要包含了6个环节&#xff1a; 执行页…

已解决centos7 yum报错:cannot find a valid baseurl for repo:base/7/x86_64的解决方案

出现cannot find a valid baseurl for repo:base/7/x86_64错误通常是由于YUM仓库源无法找到或无法访问&#xff0c;导致YUM无法正常工作。这种情况常见于CentOS 7系统。解决这个问题需要检查几个方面&#xff0c;如网络连接、DNS设置和YUM仓库源配置。 &#x1f9d1; 博主简介&…

架构图解析:如何构建高效的微服务系统

在当今的数字化浪潮中&#xff0c;构建高效、灵活且可扩展的系统已成为企业的重要目标。微服务架构作为一种先进的软件设计模式&#xff0c;通过将复杂的应用程序分解为一系列小型、独立的服务&#xff0c;显著提升了系统的灵活性、可扩展性和维护性。本文将通过解析微服务系统…

Label-studio-ml-backend 和YOLOV8 YOLO11自动化标注,目标检测,实例分割,图像分类,关键点估计,视频跟踪

这里写目录标题 1.目标检测 Detection2.实例分割 segment3.图像分类 classify4.关键点估计 Keypoint detection5.视频帧检测 video detect6.视频帧分类 video classify7.旋转目标检测 obb detect8.替换yolo11模型 给我点个赞吧&#xff0c;谢谢了附录coco80类名称 笔记本 华为m…

恒利联创携手Pearson VUE 亮相第62届高博会

2024年11月15日-17日&#xff0c;第62届中国高等教育博览会&#xff08;简称“高博会”&#xff09;在重庆举行&#xff0c;恒利联创携手全球领先的考试服务提供商Pearson Vue Certiport共同亮相&#xff0c;为中国院校展现并提供数字化职业技能的教育平台及学练考体系。 作为P…

linux复习2:简单命令简述

cp 复制单个文件 cp file.txt /path/to/destination/ 将 file.txt 复制到指定的目标目录。 复制多个文件 cp file1.txt file2.txt /path/to/destination/ 将 file1.txt 和 file2.txt 复制到指定的目标目录。 复制目录&#xff08;递归复制&#xff09; cp -r /path/to/source…