自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

最大子序和,又貪心又DP

開發(fā) 前端
本題的貪心思路其實并不好想,這也進(jìn)一步驗證了,別看貪心理論很直白,有時候看似是常識,但貪心的題目一點都不簡單!

[[434714]]

從本題開始,貪心題目都比較難了!

 最大子序和

力扣題目鏈接:https://leetcode-cn.com/problems/maximum-subarray

給定一個整數(shù)數(shù)組 nums ,找到一個具有最大和的連續(xù)子數(shù)組(子數(shù)組最少包含一個元素),返回其最大和。

示例: 輸入: [-2,1,-3,4,-1,2,1,-5,4] 輸出: 6 解釋: 連續(xù)子數(shù)組 [4,-1,2,1] 的和最大,為 6。

暴力解法

暴力解法的思路,第一層for 就是設(shè)置起始位置,第二層for循環(huán)遍歷數(shù)組尋找最大值

時間復(fù)雜度:O(n^2) 空間復(fù)雜度:O(1)

  1. class Solution { 
  2. public
  3.     int maxSubArray(vector<int>& nums) { 
  4.         int result = INT32_MIN; 
  5.         int count = 0; 
  6.         for (int i = 0; i < nums.size(); i++) { // 設(shè)置起始位置 
  7.             count = 0; 
  8.             for (int j = i; j < nums.size(); j++) { // 每次從起始位置i開始遍歷尋找最大值 
  9.                 count += nums[j]; 
  10.                 result = count > result ? count : result; 
  11.             } 
  12.         } 
  13.         return result; 
  14.     } 
  15. }; 

以上暴力的解法C++勉強(qiáng)可以過,其他語言就不確定了。

貪心解法

貪心貪的是哪里呢?

如果 -2 1 在一起,計算起點的時候,一定是從1開始計算,因為負(fù)數(shù)只會拉低總和,這就是貪心貪的地方!

局部最優(yōu):當(dāng)前“連續(xù)和”為負(fù)數(shù)的時候立刻放棄,從下一個元素重新計算“連續(xù)和”,因為負(fù)數(shù)加上下一個元素 “連續(xù)和”只會越來越小。

全局最優(yōu):選取最大“連續(xù)和”

局部最優(yōu)的情況下,并記錄最大的“連續(xù)和”,可以推出全局最優(yōu)。

從代碼角度上來講:遍歷nums,從頭開始用count累積,如果count一旦加上nums[i]變?yōu)樨?fù)數(shù),那么就應(yīng)該從nums[i+1]開始從0累積count了,因為已經(jīng)變?yōu)樨?fù)數(shù)的count,只會拖累總和。

這相當(dāng)于是暴力解法中的不斷調(diào)整最大子序和區(qū)間的起始位置。

那有同學(xué)問了,區(qū)間終止位置不用調(diào)整么?如何才能得到最大“連續(xù)和”呢?

區(qū)間的終止位置,其實就是如果count取到最大值了,及時記錄下來了。例如如下代碼:

  1. if (count > result) result = count

這樣相當(dāng)于是用result記錄最大子序和區(qū)間和(變相的算是調(diào)整了終止位置)。

如動畫所示:

圖片

最大子序和

紅色的起始位置就是貪心每次取count為正數(shù)的時候,開始一個區(qū)間的統(tǒng)計。

那么不難寫出如下C++代碼(關(guān)鍵地方已經(jīng)注釋)

  1. class Solution { 
  2. public
  3.     int maxSubArray(vector<int>& nums) { 
  4.         int result = INT32_MIN; 
  5.         int count = 0; 
  6.         for (int i = 0; i < nums.size(); i++) { 
  7.             count += nums[i]; 
  8.             if (count > result) { // 取區(qū)間累計的最大值(相當(dāng)于不斷確定最大子序終止位置) 
  9.                 result = count
  10.             } 
  11.             if (count <= 0) count = 0; // 相當(dāng)于重置最大子序起始位置,因為遇到負(fù)數(shù)一定是拉低總和 
  12.         } 
  13.         return result; 
  14.     } 
  15. }; 

時間復(fù)雜度:O(n) 空間復(fù)雜度:O(1)

當(dāng)然題目沒有說如果數(shù)組為空,應(yīng)該返回什么,所以數(shù)組為空的話返回啥都可以了。

不少同學(xué)認(rèn)為 如果輸入用例都是-1,或者 都是負(fù)數(shù),這個貪心算法跑出來的結(jié)果是0, 這是又一次證明腦洞模擬不靠譜的經(jīng)典案例,建議大家把代碼運(yùn)行一下試一試,就知道了,也會理解 為什么 result 要初始化為最小負(fù)數(shù)了。

動態(tài)規(guī)劃

當(dāng)然本題還可以用動態(tài)規(guī)劃來做,當(dāng)前「代碼隨想錄」主要講解貪心系列,后續(xù)到動態(tài)規(guī)劃系列的時候會詳細(xì)講解本題的dp方法。

那么先給出我的dp代碼如下,有時間的錄友可以提前做一做:

  1. class Solution { 
  2. public
  3.     int maxSubArray(vector<int>& nums) { 
  4.         if (nums.size() == 0) return 0; 
  5.         vector<int> dp(nums.size(), 0); // dp[i]表示包括i之前的最大連續(xù)子序列和 
  6.         dp[0] = nums[0]; 
  7.         int result = dp[0]; 
  8.         for (int i = 1; i < nums.size(); i++) { 
  9.             dp[i] = max(dp[i - 1] + nums[i], nums[i]); // 狀態(tài)轉(zhuǎn)移公式 
  10.             if (dp[i] > result) result = dp[i]; // result 保存dp[i]的最大值 
  11.         } 
  12.         return result; 
  13.     } 
  14. }; 

時間復(fù)雜度:O(n) 空間復(fù)雜度:O(n)

總結(jié)

本題的貪心思路其實并不好想,這也進(jìn)一步驗證了,別看貪心理論很直白,有時候看似是常識,但貪心的題目一點都不簡單!

后續(xù)將介紹的貪心題目都挺難的,哈哈,所以貪心很有意思,別小看貪心!

其他語言版本

Java

  1. class Solution { 
  2.     public int maxSubArray(int[] nums) { 
  3.         if (nums.length == 1){ 
  4.             return nums[0]; 
  5.         } 
  6.         int sum = Integer.MIN_VALUE; 
  7.         int count = 0; 
  8.         for (int i = 0; i < nums.length; i++){ 
  9.             count += nums[i]; 
  10.             sum = Math.max(sumcount); // 取區(qū)間累計的最大值(相當(dāng)于不斷確定最大子序終止位置) 
  11.             if (count <= 0){ 
  12.                 count = 0; // 相當(dāng)于重置最大子序起始位置,因為遇到負(fù)數(shù)一定是拉低總和 
  13.             } 
  14.         } 
  15.        return sum
  16.     } 
  1. // DP 方法 
  2. class Solution { 
  3.     public int maxSubArray(int[] nums) { 
  4.         int ans = Integer.MIN_VALUE; 
  5.         int[] dp = new int[nums.length]; 
  6.         dp[0] = nums[0]; 
  7.         ans = dp[0]; 
  8.  
  9.         for (int i = 1; i < nums.length; i++){ 
  10.             dp[i] = Math.max(dp[i-1] + nums[i], nums[i]); 
  11.             ans = Math.max(dp[i], ans); 
  12.         } 
  13.  
  14.         return ans; 
  15.     } 

Python

  1. class Solution: 
  2.     def maxSubArray(self, nums: List[int]) -> int
  3.         result = -float('inf'
  4.         count = 0 
  5.         for i in range(len(nums)): 
  6.             count += nums[i] 
  7.             if count > result: 
  8.                 result = count 
  9.             if count <= 0: 
  10.                 count = 0 
  11.         return result 

Go

  1. func maxSubArray(nums []intint { 
  2.     maxSum := nums[0] 
  3.     for i := 1; i < len(nums); i++ { 
  4.         if nums[i] + nums[i-1] > nums[i] { 
  5.             nums[i] += nums[i-1] 
  6.         } 
  7.         if nums[i] > maxSum { 
  8.             maxSum = nums[i] 
  9.         } 
  10.     } 
  11.     return maxSum 

 

責(zé)任編輯:姜華 來源: 代碼隨想錄
相關(guān)推薦

2023-07-18 19:11:21

配置信令系統(tǒng)

2014-07-23 10:19:02

小米4

2021-09-09 18:12:22

內(nèi)存分段式網(wǎng)絡(luò)

2019-07-18 09:17:19

Kafka消息隊列服務(wù)器

2013-12-06 10:11:48

Windows 8Windows 7Windows 8.1

2017-12-28 10:44:08

JavaScript瀏覽器網(wǎng)頁

2022-03-04 12:09:25

SQL數(shù)據(jù)量多表查詢

2019-11-11 13:40:45

Python 開發(fā)編程語言

2021-12-27 13:57:34

Vite 工具項目

2020-12-19 10:46:20

黑客網(wǎng)絡(luò)安全網(wǎng)絡(luò)攻擊

2014-12-04 09:58:59

PHP

2019-05-27 08:09:43

WiFi無線信道上網(wǎng)

2018-03-05 10:27:47

電腦卡頓舊電腦

2022-01-04 14:21:56

Vite組件React

2024-12-04 13:54:19

pnpm存儲項目

2024-05-27 10:09:26

2018-08-15 14:02:19

ODCCIT領(lǐng)域液冷

2023-12-19 08:28:34

RabbitMQ消息隊列架構(gòu)

2022-12-05 14:35:30

點贊
收藏

51CTO技術(shù)棧公眾號