当前位置: 首页 > article >正文

Kadane 算法 详解

Kadane 算法详解

Kadane 算法是一种动态规划思想的算法,用于解决 “最大子数组和”(Maximum Subarray Sum) 问题。该算法以其简单且高效的特点广泛应用于面试和实践中。


问题描述

给定一个数组 nums,寻找一个连续子数组(至少包含一个元素),使得该子数组的和最大,并返回这个最大和。

例如:

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 最大子数组为 [4,-1,2,1],其和为 6。

Kadane 算法核心思想

  1. 定义状态变量:

    • currentSum:表示以当前元素为结束的子数组的最大和。
    • maxSum:记录全局最大子数组和。
  2. 动态规划转移方程:
    对于数组中的每个元素 nums[i]

    • 如果 currentSum + nums[i] > nums[i],则将当前元素加到之前的子数组中(即扩展子数组)。
    • 如果 currentSum + nums[i] <= nums[i],则重新开始一个新的子数组,从 nums[i] 开始。
    • 转移方程:
      c u r r e n t S u m = max ⁡ ( c u r r e n t S u m + n u m s [ i ] , n u m s [ i ] ) currentSum = \max(currentSum + nums[i], nums[i]) currentSum=max(currentSum+nums[i],nums[i])
  3. 更新全局最大值:

    • 在每一步计算中,比较 currentSummaxSum,更新全局最大值:
      m a x S u m = max ⁡ ( m a x S u m , c u r r e n t S u m ) maxSum = \max(maxSum, currentSum) maxSum=max(maxSum,currentSum)
  4. 时间复杂度:

    • 遍历一次数组,时间复杂度为 O ( n ) O(n) O(n)
    • 空间复杂度为 O ( 1 ) O(1) O(1),只需常量空间记录 currentSummaxSum

Kadane 算法的实现

代码实现
public class Kadane {
    public static int maxSubArray(int[] nums) {
        // 初始化变量
        int currentSum = nums[0]; // 以第一个元素开始
        int maxSum = nums[0];     // 全局最大值

        for (int i = 1; i < nums.length; i++) {
            // 动态规划转移方程
            currentSum = Math.max(currentSum + nums[i], nums[i]);
            // 更新全局最大值
            maxSum = Math.max(maxSum, currentSum);
        }

        return maxSum;
    }

    public static void main(String[] args) {
        int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
        System.out.println("最大子数组和为: " + maxSubArray(nums)); // 输出: 6
    }
}

Kadane 算法的步骤分析

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
索引 inums[i]currentSummaxSum
0-2-2-2
11 max ⁡ ( − 2 + 1 , 1 ) = 1 \max(-2 + 1, 1) = 1 max(2+1,1)=11
2-3 max ⁡ ( 1 − 3 , − 3 ) = − 2 \max(1 - 3, -3) = -2 max(13,3)=21
34 max ⁡ ( − 2 + 4 , 4 ) = 4 \max(-2 + 4, 4) = 4 max(2+4,4)=44
4-1 max ⁡ ( 4 − 1 , − 1 ) = 3 \max(4 - 1, -1) = 3 max(41,1)=34
52 max ⁡ ( 3 + 2 , 2 ) = 5 \max(3 + 2, 2) = 5 max(3+2,2)=55
61 max ⁡ ( 5 + 1 , 1 ) = 6 \max(5 + 1, 1) = 6 max(5+1,1)=66
7-5 max ⁡ ( 6 − 5 , − 5 ) = 1 \max(6 - 5, -5) = 1 max(65,5)=16
84 max ⁡ ( 1 + 4 , 4 ) = 5 \max(1 + 4, 4) = 5 max(1+4,4)=56
  • 最终结果:maxSum = 6,对应子数组 [4, -1, 2, 1]

扩展问题

1. 返回最大子数组本身

Kadane 算法的简单实现只返回最大和,如果需要返回子数组本身,可以增加两个变量记录子数组的起始和结束索引。

public class KadaneWithSubarray {
    public static int[] maxSubArray(int[] nums) {
        int currentSum = nums[0], maxSum = nums[0];
        int start = 0, end = 0, tempStart = 0;

        for (int i = 1; i < nums.length; i++) {
            if (currentSum + nums[i] > nums[i]) {
                currentSum += nums[i];
            } else {
                currentSum = nums[i];
                tempStart = i; // 更新临时起始索引
            }

            if (currentSum > maxSum) {
                maxSum = currentSum;
                start = tempStart; // 更新起始索引
                end = i;           // 更新结束索引
            }
        }

        // 返回子数组和最大和
        return new int[]{maxSum, start, end};
    }

    public static void main(String[] args) {
        int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
        int[] result = maxSubArray(nums);
        System.out.println("最大子数组和: " + result[0]); // 输出: 6
        System.out.println("最大子数组: " + Arrays.toString(
            Arrays.copyOfRange(nums, result[1], result[2] + 1))); // 输出: [4, -1, 2, 1]
    }
}

2. 处理全负数组

Kadane 算法可以直接处理全负数组,因为它初始化 currentSummaxSum 为第一个元素,确保算法能够返回正确的结果(即最大负数)。

例如:nums = [-3, -5, -2, -8]

  • 输出:-2(子数组为 [-2])。

3. 二维最大子矩阵问题

Kadane 算法可扩展到二维数组,用于求解矩阵中的最大子矩阵和问题。

大致思路:

  1. 固定两个行边界。
  2. 对每列求和,转换为一维数组问题。
  3. 使用 Kadane 算法求解该一维数组的最大和。

时间复杂度与优化

  • 时间复杂度 O ( n ) O(n) O(n),每个元素遍历一次。
  • 空间复杂度 O ( 1 ) O(1) O(1),只使用了常量空间。

总结

Kadane 算法是一种高效的动态规划算法,核心在于维护以当前元素为结尾的最大子数组和,更新全局最大值。它可以轻松扩展以处理不同的变体问题,例如返回子数组本身、处理二维矩阵等,因其高效性和简单性而广泛应用。


http://www.kler.cn/a/403232.html

相关文章:

  • SpringCloud多机部署,负载均衡-LoadBalance
  • 【AIGC】如何使用高价值提示词Prompt提升ChatGPT响应质量
  • 04 —— Webpack打包CSS代码
  • aws凭证(一)凭证存储
  • 99.【C语言】数据结构之二叉树的基本知识
  • Unity3d场景童话梦幻卡通Q版城镇建筑植物山石3D模型游戏美术素材
  • C++:类和对象
  • 使用MATLAB进行遗传算法设计
  • kafka是如何做到高效读写
  • 前端算法题
  • 前端基础的讲解-JS(14)
  • 【AIGC】ChatGPT提示词Prompt解析:情感分析,分手后还可以做朋友吗?
  • LTE Cat 1 无线通信模块 AT 指令使用
  • uni-app Vue3语法实现微信小程序样式穿透uview-plus框架
  • 第7章硬件测试-7.3 功能测试
  • JS一个then方法异步的问题
  • 【模型级联】YOLO-World与SAM2通过文本实现指定目标的零样本分割
  • 原生JS和CSS,HTML实现开屏弹窗
  • 快速简单的视频下载器——lux
  • 部门管理系统功能完善(删除部门、添加部门、根据 ID 查询部门 和 修改部门)
  • 思考Redis的用途 2024-11-19
  • 【数据结构】—— 时间复杂度、空间复杂度
  • 依赖管理(go mod)
  • Android开发实战班 - 网络编程 - WebSocket 实时通信
  • 数据结构-堆排序笔记
  • 本草纲目数字化:Spring Boot在中药实验管理中的应用