【Kadane】Leetcode 918. 环形子数组的最大和【中等】

server/2024/9/24 16:17:14/

环形子数组的最大和

  • 给定一个长度为 n 的环形整数数组 nums ,返回 nums 的非空 子数组 的最大可能和 。

环形数组 意味着数组的末端将会与开头相连呈环状。形式上,

  • nums[i] 的下一个元素是 nums[(i + 1) % n] ,
  • nums[i] 的前一个元素是 nums[(i - 1 + n) % n] 。

子数组 最多只能包含固定缓冲区 nums 中的每个元素一次。
形式上,对于子数组 nums[i], nums[i + 1], …, nums[j] , 不存在 i <= k1, k2 <= j 其中 k1 % n == k2 % n 。

示例 1:
输入:nums = [1,-2,3,-2]
输出:3
解释:从子数组 [3] 得到最大和 3

示例 2:
输入:nums = [5,-3,5]
输出:10
解释:从子数组 [5,5] 得到最大和 5 + 5 = 10

示例 3:
输入:nums = [3,-2,2,-3]
输出:3
解释:从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3

解题思路

要找到环形数组的最大子数组和,分为两种情况进行考虑:

子数组不跨越数组的末尾和开头:这种情况可以通过经典的Kadane算法求解,
Kadane算法可以在O(n)时间复杂度内找到数组中的最大子数组和。

子数组跨越数组的末尾和开头: 这种情况可以转换为一个求解问题,
即数组中的最小子数组和,然后用总和减去最小子数组和得到最大子数组和。
在这里插入图片描述

Java实现

public class MaxCircularSubarraySum {public int maxSubarraySumCircular(int[] nums) {// 计算不跨越数组末尾和开头的最大子数组和int maxKadane = kadane(nums);// 计算数组的总和int totalSum = 0;for (int num : nums) {totalSum += num;}// 计算最小子数组和int minKadane = kadaneMin(nums);// 如果数组中的所有元素都是负数,则返回 Kadane 算法的结果if (totalSum == minKadane) {return maxKadane;} else {return Math.max(maxKadane, totalSum - minKadane);}}// Kadane 算法,计算最大子数组和private int kadane(int[] nums) {//记录以当前元素结尾的最大子数组和int maxEndingHere = nums[0];//记录到目前为止找到的最大子数组和int maxSoFar = nums[0];for (int i = 1; i < nums.length; i++) {maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);maxSoFar = Math.max(maxSoFar, maxEndingHere);}return maxSoFar;}// 计算最小子数组和private int kadaneMin(int[] nums) {//记录以当前元素结尾的最大子数组和,记录到目前为止找到的最小子数组和int minEndingHere = nums[0], minSoFar = nums[0];for (int i = 1; i < nums.length; i++) {minEndingHere = Math.min(nums[i], minEndingHere + nums[i]);minSoFar = Math.min(minSoFar, minEndingHere);}return minSoFar;}// 测试用例public static void main(String[] args) {MaxCircularSubarraySum solution = new MaxCircularSubarraySum();int[] nums1 = {1, -2, 3, -2};int[] nums2 = {5, -9, 4, 4,-9,5};int[] nums3 = {3, -1, 2, -1};int[] nums4 = {3, -2, 2, -3};int[] nums5 = {-2, -3, -1};System.out.println(solution.maxSubarraySumCircular(nums1)); // 期望输出: 3System.out.println(solution.maxSubarraySumCircular(nums2)); // 期望输出: 10System.out.println(solution.maxSubarraySumCircular(nums3)); // 期望输出: 4System.out.println(solution.maxSubarraySumCircular(nums4)); // 期望输出: 3System.out.println(solution.maxSubarraySumCircular(nums5)); // 期望输出: -1}
}

时间空间复杂度

  • 时间复杂度:O(n),其中 n 是数组的长度。Kadane算法的复杂度为 O(n),我们在代码中调用了两次Kadane算法,以及一次求数组和的操作,总体时间复杂度为 O(n)。
  • 空间复杂度:O(1),除了输入数组外,使用的额外空间仅限于一些常量。

http://www.ppmy.cn/server/48603.html

相关文章

加入 Microsoft Build 2024 的 .NET 团队!

作者&#xff1a;Mehul Harry 排版&#xff1a;Alan Wang Microsoft Build 2024 为 .NET 爱好者带来了一系列精彩的会议。无论您是经验丰富的开发人员还是刚刚开始您的开发之旅&#xff0c;每个人都能找到适合自己的东西。 活动形式&#xff1a;混合体验 大会通过现场和在线会…

sublime如何写python

推荐一款好用且轻量级的编辑器——sublime—text3&#xff0c;sublime现在支持的语言有很多。 右边弹出的列表可以往下拉&#xff0c;亮点是支持了python&#xff0c;而且不需要安装任何的python环境&#xff0c;直接下载sublime就可以编写python代码并运行了。 使用方法&…

WPF框架,修改ComboBox控件背景色 ,为何如此困难?

直接修改Background属性不可行 修改控件背景颜色&#xff0c;很多人第一反应便是修改Background属性&#xff0c;但是修改过后便会发现&#xff0c;控件的颜色没有发生任何变化。 于是在网上搜索答案&#xff0c;便会发现一个异常尴尬的情况&#xff0c;要么就行代码简单但是并…

超详解——​深入理解Python中的位运算与常用内置函数/模块——基础篇

目录 ​编辑 1.位运算 2.常用内置函数/模块 math模块 random模块 decimal模块 常用内置函数 3.深入理解和应用 位运算的实际应用 1.权限管理 2.位图 3.图像处理 2.math模块的高级应用 统计计算 几何计算 总结 1.位运算 位运算是对整数在内存中的二进制表示进行…

adb卸载系统应用

1.进入shell adb shell2.查看所有包 pm list packages3.查找包 如查找vivo相关的包 pm list packages | grep vivo发现包太多了,根本不知道哪个是我们想卸载的应用 于是可以打开某应用,再查看当前运行应用的包名 如下: 4.查找当前前台运行的包名 打开某应用,在亮屏状态输入 …

JVM内存分析之JVM分区与介绍

JVM&#xff08;Java Virtual Machine&#xff09;作为Java平台的核心组件&#xff0c;为Java应用程序的运行提供了一个虚拟的计算机环境。为了更好地理解和优化Java应用程序的性能&#xff0c;对JVM的内存管理进行深入分析是至关重要的。本文将详细介绍JVM的内存分区及其功能。…

ClickHouse数据库对比、适用场景与入门指南

本文全面对比了ClickHouse与其他数据库&#xff08;如StarRocks、HBase、MySQL、Hive、Elasticsearch等&#xff09;的性能、功能、适用场景&#xff0c;并提供了ClickHouse的教学入门指南&#xff0c;旨在帮助读者选择合适的数据库产品并快速掌握ClickHouse的使用。 文章目录 …

Segment Anything CSharp| 在 C# 中通过 OpenVINO™ 部署 SAM 模型实现万物分割

​ OpenVINO™ C# API 是一个 OpenVINO™ 的 .Net wrapper&#xff0c;应用最新的 OpenVINO™ 库开发&#xff0c;通过 OpenVINO™ C API 实现 .Net 对 OpenVINO™ Runtime 调用.Segment Anything Model&#xff08;SAM&#xff09;是一个基于Transformer的深度学习模型&#x…