Hi 你們好,我是張小豬。歡迎來到『寶寶也能看懂』系列特別篇 - 30-Day LeetCoding Challenge。git
這是一個 leetcode 官方的小活動。能夠在官網看到,從 4 月 1 號開始,天天官方會選出一道題,在 24 小時內完成便可得到一點小獎勵。雖然獎勵彷佛也沒什麼用,不過做爲一個官方的打卡活動,小豬仍是來打一下卡吧,正好做爲天天下班回家後的娛樂。github
這裏是 4 月 3 號的題,也是題目列表中的第 53 題 -- 『最大子序和』shell
給定一個整數數組 nums
,找到一個具備最大和的連續子數組(子數組最少包含一個元素),返回其最大和。segmentfault
示例 1:數組
輸入: [-2,1,-3,4,-1,2,1,-5,4], 輸出: 6 解釋: 連續子數組 [4,-1,2,1] 的和最大,爲 6。
進階:優化
若是你已經實現複雜度爲 O(n) 的解法,嘗試使用更爲精妙的分治法求解。spa
EASYcode
題目中比較關鍵的點就在於,要求目標數組是一個連續子數組。這也就意味着,咱們不能更改順序,也不能只從中間間隔的挑選一些子項。若是用一個形象的栗子的話,咱們能夠想象成如今有一個長度可變的窗口,它的左邊界能夠左右移動,右邊界也能夠,這樣它在數組中框選出來的就是一個連續子數組。blog
基於這個栗子,咱們來看看在遍歷數組項的時候,咱們會遇到哪些狀況。首先對於右邊界來講,可能會有兩種狀況:leetcode
而後咱們再嘗試站在左邊界的視角,看看以上兩個狀況:
這裏獲得了幾個遍歷過程當中的情況,目前看起來彷佛仍是比較的雲裏霧裏。不過不要着急,咱們繼續分析。
首先,最直接的方式,那就是嘗試全部可能的窗口,而後就能找到和最大的窗口狀況。不過這種方式的時間複雜度過高,相信並不會有小夥伴這麼寫。這裏只是做爲一個最基本的實現,具體代碼以下:
const maxSubArray = nums => { let max = nums[0]; for (let i = 0; i < nums.length; ++i) { let cur = 0; for (let j = i; i < nums.length; ++j) { cur += nums[j]; cur > max && (max = cur); } } return max; };
上面的直接方案在遍歷過程當中徹底沒有利用到咱們的目的和以前分析的狀況。若是加上這一些,咱們能夠想象一下,在遍歷數組的過程當中,其實咱們面臨的情況總共就只有兩種:繼續擴充當前窗口或者基於此位置創建新窗口。
爲何這麼說呢?假設當前窗口的和爲 x,而咱們遇到一個新的值 y,那麼站在右邊界的視角,因爲不知道將來的狀況,因此不管是正負數咱們都會默認不斷的擴充當前窗口。除非這時候 x + y < y,即站在左邊界的視角,能夠經過向右移動來扔掉一堆負擔。
這也就是爲何在最開始的時候咱們會先分析左右兩個邊界的狀況了。最後,爲了獲得全局最大值,咱們會在過程當中不斷的比較局部最大值。具體代碼以下:
const maxSubArray = nums => { let max = cur = nums[0]; for (let i = 1; i < nums.length; i++) { cur += nums[i]; nums[i] > cur && (cur = nums[i]); cur > max && (max = cur); } return max; };
這裏其實仍是基於咱們最初分析的狀況,不過咱們換一個姿式來看看。假設當前的位置始終爲窗口的右邊界,那麼是否須要把窗口的左邊界進行左移,徹底取決於左邊累計下來的結果。而這個累計結果是能夠經過計算一直保持下來的。具體代碼以下:
const maxSubArray = nums => { let max = nums[0]; for (let i = 1; i < nums.length; i++) { nums[i - 1] > 0 && (nums[i] += nums[i - 1]); nums[i] > max && (max = nums[i]); } return max; };
做爲『30-Day LeetCoding Challenge』的第三題,這道題目的突破點就在於分析出如何利用現有的結果來簡化狀況從而導向最終目標。但願能幫到有須要的小夥伴。
若是以爲不錯的話,記得『三連』哦。小豬愛大家喲~