【Leetcode_Hot100】普通数组

news/2024/11/16 8:59:20/文章来源:https://www.cnblogs.com/syr463/p/18383637

普通数组

53. 最大子数组和

56. 合并区间

189. 轮转数组

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

41. 缺失的第一个正数

53. 最大子数组和

方法一:暴力解

依次遍历数组中的每个子数组,进而判断res的最大值

超时

class Solution {public int maxSubArray(int[] nums) {int res = 0;for(int i=0; i<nums.length; i++) {int sum = 0;for(int j=i; j<nums.length; j++) {sum += nums[j];res = Math.max(res, sum);}}return res;}
}

方法二:贪心算法

贪心算法,保证累加后的结果始终对当前结果存在增益效果即可

  1. sum用于记录前几项的元素和,动态更新;res用于记录最大的元素和,动态更新
  2. 求解的关键在于sum值的更新,假设不考虑nums[i]的值,此处仅关注nums[i-1]
    1. 如果nums[i-1]>0,那么对nums[i]均有增益作用
    2. 如果nums[i-1]<0,无论nums[i]为正还是负,对nums[i]均无增益作用;例如nums[i-1]=-1,nums[i]=-3,此时,重新累加的值为-3,而叠加后的值却为-4
  3. 那么何时应该累加sum?将上述思路扩展至前几项的和sum:如果sum值小于0,则sum再加上nums[i]值会更小,无有增益作用。因此此时sum应从0开始计算。
  4. 初始化,res = Integer.MIN_VALUEsum = 0表示从0开始累加
class Solution {public int maxSubArray(int[] nums) {int res = Integer.MIN_VALUE;int sum = 0;for(int i=0; i<nums.length; i++) {// 如果 sum<0, 说明前几项无增益作用,重新累计sumif(sum<0) {sum = 0;}sum += nums[i];res = Math.max(res, sum);}return res;}
}

方法三:动态规划

与上述贪心算法的实现思路似乎比较类似,动态规划问题设计了一个状态转移方程,而贪心算法则侧重于取当前最优方案

  1. 状态转移方程:dp[i] = max(dp[i-1]+nums[i], nums[i]),如果加上nums[i]的元素后的值还小于nums[i],则舍弃之前的元素
  2. 优化上述方程,更新时只需要dp[i-1]dp[i],因此可采用变量sum进行更新
  3. 初始化,res = Integer.MIN_VALUEsum = 0表示从0开始累加
class Solution {public int maxSubArray(int[] nums) {int res = Integer.MIN_VALUE;int sum = 0;for(int i=0; i<nums.length; i++) {sum = Math.max(sum+nums[i], nums[i]);res = Math.max(res, sum);}return res;}
}

56. 合并区间

先将给定数组按照左边界进行排序,之后依次比较右边界的值,即可确定合并区间。

变量定义:ArrayList<int[]> res存储结果

左边界leftBound,右边界rightBound

注意表达含义:

  1. Arrays.sort(intervals, (a,b) -> Integer.compare(a[0], b[0]));
  2. res.add(new int[]{leftBound, rightBound});这句表述,以leftBoundrightBound为值,构建了一个int[],并将int[]存入ArrayList<int[]>
  3. res.toArray(new int[res.size()][]);List的toArray()方法_list.toarray-CSDN博客
class Solution {public int[][] merge(int[][] intervals) {// 将数组Intervals按照左边界排序,调用compare方法Arrays.sort(intervals, (a,b) -> Integer.compare(a[0], b[0]));ArrayList<int[]> res = new ArrayList<>();int leftBound = intervals[0][0];int rightBound = intervals[0][1];for(int i=1; i<intervals.length; i++) {if(intervals[i][0] > rightBound) {// 边界不重叠,将结果存入res中,并且同时更新左右边界res.add(new int[]{leftBound, rightBound});leftBound = intervals[i][0];rightBound = intervals[i][1];} else {// 边界重叠,更新右边界,大中取大rightBound = Math.max(rightBound, intervals[i][1]);}}// 上述循环最后一次更新右边界,结果未写入res中,将此次结果插入res.add(new int[]{leftBound, rightBound});return res.toArray(new int[res.size()][]);}
}

189. 轮转数组

方法一:模拟

  1. 向后移动k位,可利用取余操作(i+k)%len,计算更新后的元素位置

  2. 数组复制相关知识:深入解析Java中的数组复制:System.arraycopy、Arrays.copyOf和Arrays.copyOfRange - 知乎 (zhihu.com)

class Solution {public void rotate(int[] nums, int k) {int len = nums.length;// 复制数组int[] nums,到int[] tempint[] temp = Arrays.copyOf(nums, len);int count = 0;for(int i=0; i<len; i++) {// 使用取余运算,判断nums中的值nums[(i+k) % len] = temp[i];}}
}

方法二:反转数组

将数组进行三次反转即可,例如:nums = [1,2,3,4,5,6,7], k=3

  1. 第一次反转,从0到nums.length-1:nums = [7,6,5,4,3,2,1]
  2. 第二次反转,从0到k-1:nums = [5,6,7,4,3,2,1]
  3. 第三次反转,从k到nums.length:nums = [5,6,7,1,2,3,4]
class Solution {public void rotate(int[] nums, int k) {// 注意此处应该取余,处理nums=[1,2], k=3的情况k %= nums.length;reverse(nums, 0, nums.length-1);reverse(nums, 0, k-1);reverse(nums, k, nums.length-1);}private void reverse(int[] nums, int left, int right) {while(left < right) {int temp = nums[left];nums[left] = nums[right];nums[right] = temp;left++;right--;}}
}

方法三:环状替代

【待补充】

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

方法一:前缀积 + 后缀积

为了避免重复计算,可将nums[i]的前缀积和后缀积均计算出来,则数组中除nums[i]的乘积则为前缀积 * 后缀积;计算时应注意边界条件

初始化:前缀积leftMul[0] = 1,从左向右计算;后缀积rightMul[nums.length - 1] = 1从右向左计算

class Solution {public int[] productExceptSelf(int[] nums) {int[] res = new int[nums.length];int[] leftMul = new int[nums.length];int[] rightMul = new int[nums.length];leftMul[0] = 1;rightMul[nums.length - 1] = 1;// 计算时,最后一个元素不用计算,假如取到最后一个元素,其乘积不用计算自己for(int i=0; i<nums.length-1; i++) {leftMul[i+1] = leftMul[i] * nums[i];// System.out.print(leftMul[i] + ",");}for(int i=nums.length-1; i>0; i--) {rightMul[i-1] = rightMul[i] * nums[i];// System.out.print(rightMul[i-1] + ",");}for(int i=0; i<nums.length; i++) {res[i] = leftMul[i] * rightMul[i];}return res;}
}

方法二:优化

上述实现方法中,leftMulrightMul中的值仅在计算res[]时使用一次,并未重复使用,因此可以直接将计算结果写入res数组中,利用变量R记录后缀积,将空间复杂度从O(n)降为O(1)

class Solution {public int[] productExceptSelf(int[] nums) {int[] res = new int[nums.length];res[0] = 1;// 先计算前缀乘积for(int i=0; i<nums.length-1; i++) {res[i+1] = res[i] * nums[i];// System.out.print(res[i+1] + ",");}// 再乘以后缀乘积int R = 1;for(int i=nums.length-1; i>=0; i--) {res[i] = res[i] * R;// 更新后缀乘积R *= nums[i];// System.out.print(res[i-1] + ",");}return res;}
}

41. 缺失的第一个正数

方法一:HashSet

先将正数放入HashSet中,之后枚举正整数,判断其是否在HashSet中

时间复杂度为O(n),符合要求;空间复杂度为O(1),不符合要求

class Solution {public int firstMissingPositive(int[] nums) {int res = -1;HashSet<Integer> set = new HashSet<>();// 将nums中符合要求的数放入hashSet中for(int i=0; i<nums.length; i++) {if(nums[i] > 0) {set.add(nums[i]);}}// 从1开始遍历,判断哪个i不在hashSet中for(int i=1; i<Integer.MAX_VALUE; i++) {if(!set.contains(i)) {res = i;break;}}return res;}
}

方法二:置换

class Solution {public int firstMissingPositive(int[] nums) {int res = -1;// 从i开始遍历,一次操作后,nums[i]中元素置换完成for(int i=0; i<nums.length; i++) {// 只有当元素的值位于[0, nums.length]时才开始交换// 并且当交换的值恰好在当前位置时则不进行交换while(nums[i]>0 && nums[i]<=nums.length && nums[nums[i]-1] != nums[i]) {int temp = nums[nums[i]-1];nums[nums[i]-1] = nums[i];nums[i] = temp; }}for(int i=0; i<nums.length; i++) {if(nums[i] != i+1) {return i+1;}}return nums.length+1;}
}

方法三:哈希表

  1. 将数组中的非正数修改为N+1
  2. 将小于等于N的元素值修改为负数
  3. 遍历数组,确定第一个正数的位置

image-20240827153233205

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

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

相关文章

【python】基础之迭代器

1.总览2.迭代器介绍2.1:迭代器是一个实现了迭代协议的对象,它可以让我们遍历一个容器中的所有元素,而不需要知道容器的内部结构,迭代器可以用于遍历列表,元祖,字典,集合等容器类型; 2.2:迭代器的工作原理是通过实现两个方法:iter()和__next__()方法,iter()方法返回迭…

Java元注解介绍

Java四种元注解相关介绍 概述 注解从Java1.5引入以来,不断地简化我们编写代码的流程,逐渐的也成为了我们必学的一项技术。我们学习了各种注解,学习了他们的用法,学习了他们的限制,是否想过他们的组成呢,下面我将我对元注解的理解分享给大家。 元注解是用来修饰注解的注解…

RocketMQ在基金大厂的分布式事务实践

1 行业背景 基金公司核心业务主要分为:投研线业务,即投资管理和行业研究业务,体现基金公司核心竞争力 市场线业务,即基金公司利用自身渠道和市场能力完成基金销售并做好客户服务随互联网技术发展,基金销售渠道更加多元化,线上成为基金销售重要渠道。相比传统基金客户,线上…

从混乱到有序:10款建筑项目管理软件推荐

国内外主流的 10 款建筑企业项目管理系统对比:PingCode、Worktile、广联达、泛普软件、建文软件、Asana、Trello、Basecamp、Jira、Monday.com。在建筑行业,找到一个能够高效管理时间、成本和资源的项目管理系统常常是一项挑战。这种系统的选择不仅影响项目的流程和效率,还直…

begin-预览,不行啊还是太弱了

方便管理,主要是想熟悉下git的操作 先创建并且切换到一个新的分支: git commit --allow-empty -am "before starting PA1" git checkout -b PA1其中--allow-empty表示允许提交一个空的提交,git默认是不能提交一个空的提交信息,如果当前的文档没有什么修改,那么就…

nginx部署出现 Welcome to nginx! If you see this page 该如何解决

当你部署nginx的时候出现,ping域名网站可以通,但是访问不了网站怎么办,不用急,往下看; 1.问题所在其实出现以上的问题就代表你已经成功搭建好了nginx,只是现在默认访问的时候跳转到了nginx的首页问题。 2.解决方案 默认情况下,Nginx 安装后会使用默认配置文件,这些文件…

GLM-4-Flash 大模型API免费了,手把手构建“儿童绘本”应用实战(附源码)

GLM-4-Flash 大模型API免费了,我们本文基于免费API构建一个“儿童绘本”应用,包括使用文生图产出绘本故事插图……老牛同学刚刷到了一条劲爆的消息,GLM-4-Flash大模型推理 API 免费了:https://bigmodel.cn/pricing老牛同学一直觉得上次阿里云百炼平台为期 1 个月免费额度的…

CoreShop---.NET、Uni-App开发支持多平台的小程序商城系统

前言 小程序商城系统是当前备受追捧的开发领域,它可以为用户提供一个更加便捷、流畅、直观的购物体验,无需下载和安装,随时随地轻松使用。今天给大家推荐一个基于.NET、Uni-App开发支持多平台的小程序商城系统(该商城系统完整开源、无封装无加密、商用免费、支持二次开发、…

SQL server 特殊字符\u0000处理

某天,接到用户反馈点击某个项目分组的时候页面报错,点击其他项目不报错。初步以为是下标数字特殊符号导致的。通过前台输出对应的数值后发现该字段末尾有个“\u0000”特殊字符(ASCII字符char(0))。通常是导入数据时的格式问题或是程序处理时将页面中的换行字符保存数据库导…

Kettle: pentaho-server-ce-9.4 连接失败:ConnectionServiceImpl.ERROR_0009

pentaho-server-ce-9.4 数据库连接MYSQL8.0.37 , 测试连接失败, 提示: ConnectionServiceImpl.ERROR_0009-Connection to database [MYSQL8] failed .pentaho-server-ce-9.4 数据库连接MYSQL8.0.37 , 测试连接失败, 提示: ConnectionServiceImpl.ERROR_0009-Connection…

蓝桥杯补档

2013 省B P8597 翻硬币 H 一排硬币给出初态和终态,每次只能翻转相邻的两枚,求最少多少次 用贪心,因为翻转两次相当于没翻,所以最优方案中同一组硬币肯定最多翻转一次,所以翻转顺序无后效性。从前往后翻,只要不一样就把它和它后面的硬币都翻转一次,计数器累加2023 省A P9…