Kadane算法 C++实现

算法通关之路:一文吃透Kadane算法(C++实现)

在算法面试和日常刷题中,最大子数组和(Maximum Subarray) 是一道经典必考题。暴力枚举所有子数组的解法时间复杂度高达 O(n²),而今天要讲的 Kadane算法(卡登算法) 能以 O(n) 时间复杂度 + O(1) 空间复杂度 完美解决这个问题,简洁又高效。

今天就用博客的形式,带你从原理到C++代码,彻底掌握Kadane算法!

一、问题背景

先明确问题:给定一个整数数组(包含正数、负数、0),找到一个连续的子数组,使其元素之和最大,返回这个最大和。

示例:

  • 输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
  • 输出:6(对应子数组 [4,-1,2,1]

暴力思路:遍历所有起点和终点,计算子数组和取最大值。但数组长度一大就会超时,这时候Kadane算法就派上用场了。

二、Kadane算法核心原理

Kadane算法的核心思想只有一句话:****每一步都做出当前最优选择,最终得到全局最优解(贪心思想)

我们遍历数组时,维护两个关键变量:

  1. 当前最大和(current_max) :以当前元素为结尾的连续子数组的最大和。
  2. 全局最大和(global_max):遍历过程中所有子数组的最大和(最终答案)。

核心决策逻辑:

对于数组中的每一个元素 nums[i],我们只有两种选择:

  1. nums[i] 加入前面的子数组current_max + nums[i]
  2. nums[i] 作为新子数组的起点nums[i]

我们取两者的最大值 作为新的 current_max,保证每一步都是当前最优。

同时,每次更新 current_max 后,用它更新 global_max,记录全局最优。

举个例子理解(数组 [-2,1,-3,4]):

  1. 初始:current_max=-2global_max=-2
  2. 元素1:max(1, -2+1)=1 → current_max=1global_max=1
  3. 元素-3:max(-3, 1+(-3))=-2 → current_max=-2global_max=1
  4. 元素4:max(4, -2+4)=4 → current_max=4global_max=4

三、算法步骤(清晰版)

  1. 初始化 current_maxglobal_max 为数组第一个元素
  2. 从数组第二个元素 开始遍历:
    • 更新 current_max = max(nums[i], current_max + nums[i])
    • 更新 global_max = max(global_max, current_max)
  3. 遍历结束,global_max 就是答案。

四、C++ 代码实现

1. 基础版(最简洁,面试首选)

直接实现核心逻辑,无多余操作,时间O(n),空间O(1):

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>  // 用于max函数
using namespace std;

// Kadane算法:求最大子数组和
int maxSubArray(vector<int>& nums) {
    // 边界判断:数组为空返回0(根据题目要求调整)
    if (nums.empty()) return 0;
    
    // 初始化当前最大和、全局最大和为第一个元素
    int current_max = nums[0];
    int global_max = nums[0];
    
    // 从第二个元素开始遍历
    for (int i = 1; i < nums.size(); ++i) {
        // 核心:当前最优选择
        current_max = max(nums[i], current_max + nums[i]);
        // 更新全局最优
        global_max = max(global_max, current_max);
    }
    
    return global_max;
}

// 测试代码
int main() {
    vector<int> nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
    cout << "最大子数组和:" << maxSubArray(nums) << endl;  // 输出6
    return 0;
}

2. 进阶版:记录最大子数组的下标

如果题目不仅要求最大和,还要求输出子数组的起始、结束下标,可以在基础版上稍作修改:

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int maxSubArray(vector<int>& nums, int& start, int& end) {
    if (nums.empty()) return 0;
    
    int current_max = nums[0];
    int global_max = nums[0];
    int temp_start = 0;  // 临时记录当前子数组的起点
    
    for (int i = 1; i < nums.size(); ++i) {
        // 选择重新开始:更新临时起点
        if (nums[i] > current_max + nums[i]) {
            current_max = nums[i];
            temp_start = i;
        } else {
            // 选择加入前面的子数组
            current_max += nums[i];
        }
        
        // 更新全局最大和,记录最终起止下标
        if (current_max > global_max) {
            global_max = current_max;
            start = temp_start;
            end = i;
        }
    }
    
    return global_max;
}

// 测试代码
int main() {
    vector<int> nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
    int start = 0, end = 0;
    int max_sum = maxSubArray(nums, start, end);
    
    cout << "最大子数组和:" << max_sum << endl;
    cout << "子数组下标:[" << start << ", " << end << "]" << endl;
    cout << "子数组:";
    for (int i = start; i <= end; ++i) {
        cout << nums[i] << " ";
    }
    return 0;
}

输出结果

复制代码
最大子数组和:6
子数组下标:[3, 6]
子数组:4 -1 2 1 

五、关键细节说明

  1. 全负数数组 :Kadane算法依然有效!比如数组 [-5,-3,-2,-1],算法会返回最大的单个元素 -1(符合题意,因为子数组至少包含一个元素)。
  2. 空间复杂度 :基础版只用到两个变量,是最优空间复杂度,无需额外开辟数组。
  3. 适用场景 :除了经典的最大子数组和,还能解决最大子矩阵和 (二维Kadane)、环形数组最大子数组和等变形题。

六、算法复杂度分析

  • 时间复杂度:O(n) ------ 只遍历数组一次,无嵌套循环。
  • 空间复杂度:O(1) ------ 仅使用常数个变量,不随数组长度变化。

这也是Kadane算法成为最优解的原因!

七、总结

Kadane算法是贪心思想 的经典应用,核心就是每一步只做最优选择

  • 要么延续前面的子数组,要么重新开始新子数组。
  • 时间O(n) + 空间O(1),是最大子数组和问题的最优解法。
  • C++实现简洁,面试手写无压力,还能轻松扩展记录子数组下标。

掌握这个算法,再也不怕最大子数组和相关的面试题啦!


核心要点回顾

  1. 核心思想:贪心,每一步取当前最优(延续/重启子数组)
  2. 关键变量current_max(当前结尾最大和)、global_max(全局最大和)
  3. 复杂度:O(n)时间,O(1)空间
  4. 适用场景:最大子数组和及各类变形题
相关推荐
JieE2129 小时前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack2017 小时前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树18 小时前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
唐青枫1 天前
Java JDBC 实战指南:从 Connection 到事务和连接池
java
一个做软件开发的牛马1 天前
MyBatis-Plus 从零实战:完整搭建可运行 Demo,BaseMapper 零 SQL、Wrapper 条件构造、分页插件与代码生成器详解
java·后端
用户3721574261351 天前
Java 处理 PDF 图片:提取 PDF 中的图片,并压缩 PDF 图片体积
java
用户3721574261351 天前
Java 打印 Word 文档:从基础打印到高级设置
java
JieE2121 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2121 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法