dart实现leetcode_53

[toc]

题目:https://leetcode-cn.com/problems/maximum-subarray/

1.暴力法


  ///
  /// Author: liyanjun
  /// description: 暴力法
  ///
  int maxSubArray(List<int> nums) {
    if (nums == null || nums.length == 0) {
      return 0;
    }

    int maxNumber = nums.first;
    for (var begin = 0; begin < nums.length; begin++) {
      for (var end = begin + 1; end < nums.length; end++) {
        int sum = 0;
        for (var i = begin; i <= end; i++) {
          sum += nums[i];
        }
        maxNumber = max(sum, maxNumber);
      }
    }
    return maxNumber;
  }

空间复杂度:O(1),时间复杂度:O(n^3)

1.1 暴力法优化

重复利用前面计算过的结果


// ◼ 重复利用前面计算过的结果
   int maxSubArray1(List<int> nums) {
    if (nums == null || nums.length == 0) {
      return 0;
    }
    int maxNumber = nums.first;
    for (var begin = 0; begin < nums.length; begin++) {
      int sum = 0;
      for (var end = begin; end < nums.length; end++) {
        sum +=nums[end];
        maxNumber = max(sum, maxNumber);
      }
    }
    return maxNumber;
  }
}

空间复杂度:O(1),时间复杂度:O(n^2)

2.分治法

将序列均匀地分割成 2 个子序列

  • [begin , end) = [begin , mid) + [mid , end),mid = (begin + end) >> 1

假设 [begin , end) 的最大连续子序列和是 S[i , j) ,那么它有 3 种可能

  • [i , j) 存在于 [begin , mid) 中,同时 S[i , j) 也是 [begin , mid) 的最大连续子序列和
  • [i , j) 存在于 [mid , end) 中,同时 S[i , j) 也是 [mid , end) 的最大连续子序列和
  • [i , j) 一部分存在于 [begin , mid) 中,另一部分存在于 [mid , end) 中
    • [i , j) = [i , mid) + [mid , j)
    • S[i , mid) = max { S[k , mid) },begin ≤ k < mid
    • S[mid , j) = max { S[mid , k) },mid < k ≤ end

代码

///
  /// Author: liyanjun
  /// description: [begin]到[end]连续子序列的和 左闭右开
  ///
  int divideConquer(List<int> nums, int begin, int end) {
    if (end - begin < 2) return nums[begin];
    int mid = (end + begin) >> 1;
    int leftMax = nums[mid - 1];
    //计算从mid-1开始往左遍历 最大值
    int leftSum = leftMax;
    for (int i = mid - 2; i >= begin; i--) {
      leftSum += nums[i];
      leftMax = max(leftMax, leftSum);
    }
    //计算从mid开始开始往右遍历 最大值
    int rightMax = nums[mid];
    int rightSum = rightMax;
    for (int i = mid + 1; i < end; i++) {
      rightSum += nums[i];
      rightMax = max(rightMax, rightSum);
    }
    return max(
        leftMax + rightMax, //横跨左右两边的最大子序列和
        max(
            divideConquer(nums, begin, mid), //左边最大子序列和
            divideConquer(nums, mid, end))); //右边最大子序列和
  }
}

空间复杂度:O(logn),
时间复杂度$T(n)=2T(n/2)+O(n) = O(n*logn)

3.动态规划

状态定义:
假设 dp(i) 是以 nums[i] 结尾的最大连续子序列和(nums是整个序列)

  • 以 nums[0] –2 结尾的最大连续子序列是 –2,所以 dp(0) = –2
  • 以 nums[1] 1 结尾的最大连续子序列是 1,所以 dp(1) = 1
  • 以 nums[2] –3 结尾的最大连续子序列是 1、–3,所以 dp(2) = dp(1) + (–3) = –2
  • 以 nums[3] 4 结尾的最大连续子序列是 4,所以 dp(3) = 4
  • 以 nums[4] –1 结尾的最大连续子序列是 4、–1,所以 dp(4) = dp(3) + (–1) = 3
  • 以 nums[5] 2 结尾的最大连续子序列是 4、–1、2,所以 dp(5) = dp(4) + 2 = 5
  • 以 nums[6] 1 结尾的最大连续子序列是 4、–1、2、1,所以 dp(6) = dp(5) + 1 = 6
  • 以 nums[7] –5 结尾的最大连续子序列是 4、–1、2、1、–5,所以 dp(7) = dp(6) + (–5) = 1
  • 以 nums[8] 4 结尾的最大连续子序列是 4、–1、2、1、–5、4,所以 dp(8) = dp(7) + 4 = 5

状态转移方程:

  • 如果 dp(i – 1) ≤ 0,那么 dp(i) = nums[i]
  • 如果 dp(i – 1) > 0,那么 dp(i) = dp(i – 1) + nums[i]

初始状态

  • dp(0) 的值是 nums[0]

最终的解

  • 最大连续子序列和是所有 dp(i) 中的最大值 max { dp(i) },i ∈ [0, nums.length)

代码

int maxSubArray3(List<int> nums) {
    if (nums == null || nums.length == 0) {
      return 0;
    }
    List<int> dp = List(nums.length);
    dp[0] = nums[0];
    int maxDp = dp[0];
    for (var i = 1; i < nums.length; i++) {
      if (dp[i - 1] <= 0) {
        dp[i] = nums[i];
      } else {
        dp[i] = dp[i - 1] + nums[i];
      }
      maxDp = max(maxDp, dp[i]);
    }
    return maxDp;
  }

3.1 动态规划优化

优化空间,不需要数组


///
/// Author: liyanjun
/// description: 动态规划优化
/// 优化空间
///
int maxSubArray4(List<int> nums) {
    if (nums == null || nums.length == 0) {
      return 0;
    }
    int dp = nums[0];
    int maxDp =dp;
    for (var i = 1; i < nums.length; i++) {
      if (dp <= 0) {
        dp = nums[i];
      } else {
       dp = dp + nums[i];
      }
      maxDp = max(maxDp, dp);
    }
    return maxDp;
  }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容