[LeetCode解題攻略] 53. Maximum Subarray

更新於 發佈於 閱讀時間約 7 分鐘

題目描述

這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。

題目要求

  • 給定一個數組 nums,找到一個具有最大和的 子陣列(subarray),並返回其最大和。

限制條件

  • 1 <= nums.length <= 10^5
  • -10^4 <= nums[i] <= 10^4

這表示我們要找 最優解法,因為 nums 可能非常大,暴力解法的 O(n²) 可能會超時。


範例

範例 1:

輸入: nums = [-2,1,-3,4,-1,2,1,-5,4]
輸出: 6
解釋: 最大子陣列為 [4, -1, 2, 1],其和為 4 + (-1) + 2 + 1 = 6

範例 2:

輸入: nums = [1]
輸出: 1
解釋: 只有一個數,所以答案就是 1

範例 3:

輸入: nums = [5,4,-1,7,8]
輸出: 23
解釋: 最大子陣列為 [5, 4, -1, 7, 8],其和為 23

解題思路

思路 1:暴力解法

  • 遍歷所有可能的子陣列,計算總和,找出最大值。
  • 這種方法的時間複雜度為 O(n²),不可行。

思路 2:Kadane's Algorithm(動態規劃)

  • 使用 動態規劃(Dynamic Programming),透過 dp[i] 存儲 nums[i] 為結尾的最大子陣列和,然後找出最大值。
  • 這種方法的時間複雜度為 O(n),適合大數據量。

思路 3:分治法(Divide and Conquer)

  • 運用遞迴方式,將陣列分成左、右兩部分,然後合併解決。
  • 這種方法的時間複雜度為 O(n log n)

解法一:暴力枚舉

思路

  1. 遍歷 nums 的所有 子陣列,計算其總和。
  2. 找出 最大的總和 並返回。

程式碼

class Solution:
def maxSubArray(self, nums: List[int]) -> int:
max_sum = float('-inf')
n = len(nums)
for i in range(n):
current_sum = 0
for j in range(i, n):
current_sum += nums[j]
max_sum = max(max_sum, current_sum)
return max_sum

時間與空間複雜度

  • 時間複雜度:O(n²)
    • 內部雙層迴圈,每次都要計算新的子陣列總和,會超時。
  • 空間複雜度:O(1)
    • 只使用了 max_sum 和 current_sum,額外空間需求為 O(1)。

解法二:Kadane's Algorithm(動態規劃)

思路

  1. 使用 current_sum 來記錄 當前以 nums[i] 為結尾的最大子陣列和
  2. 如果 current_sum 變成負數,則 從下一個數字重新開始(因為負數會降低總和)。
  3. 同時維護 max_sum,確保記錄到最大的結果。

程式碼

class Solution:
def maxSubArray(self, nums: List[int]) -> int:
max_sum = nums[0]
current_sum = nums[0]
for i in range(1, len(nums)):
current_sum = max(nums[i], current_sum + nums[i])
max_sum = max(max_sum, current_sum)
return max_sum

時間與空間複雜度

  • 時間複雜度:O(n)
    • 只需一次遍歷 nums,每個元素只計算一次。
  • 空間複雜度:O(1)
    • 只使用了 current_sum 和 max_sum,不需要額外空間。

解法三:分治法(Divide and Conquer)

思路

  1. 拆分陣列,分為 左部分右部分橫跨中點的最大子陣列
  2. 遞迴計算左、右部分的最大子陣列和。
  3. 計算包含中點的最大子陣列和(透過從中點開始向左、向右擴展)。
  4. 返回三者之間的最大值。

程式碼

class Solution:
def maxSubArray(self, nums: List[int]) -> int:
def divide_and_conquer(left, right):
if left == right:
return nums[left]

mid = (left + right) // 2
left_sum = divide_and_conquer(left, mid)
right_sum = divide_and_conquer(mid + 1, right)

cross_sum = find_cross_sum(nums, left, right, mid)

return max(left_sum, right_sum, cross_sum)

def find_cross_sum(nums, left, right, mid):
left_max = float('-inf')
right_max = float('-inf')

sum_temp = 0
for i in range(mid, left - 1, -1):
sum_temp += nums[i]
left_max = max(left_max, sum_temp)

sum_temp = 0
for i in range(mid + 1, right + 1):
sum_temp += nums[i]
right_max = max(right_max, sum_temp)

return left_max + right_max

return divide_and_conquer(0, len(nums) - 1)

時間與空間複雜度

  • 時間複雜度:O(n log n)
    • 由於每次遞迴都將問題劃分為兩半,類似於歸併排序,因此時間複雜度為 O(n log n)。
  • 空間複雜度:O(log n)
    • 由於使用遞迴,每層遞迴佔用 O(log n) 的空間。

結論

這題是一道經典的動態規劃問題,適合用 Kadane's Algorithm 來解,因為它的 O(n) 時間複雜度 適合大數據量。


avatar-img
追極光的北極熊|軟體工程師的小天地
5會員
113內容數
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
留言
avatar-img
留言分享你的想法!
52. N-Queens II 題目是經典的組合優化問題,它要求解出一個 n x n 的棋盤上,放置 n 個皇后,且要求皇后們不互相攻擊,並計算出所有合法的解的數量。
51. N-Queens 是一個經典的演算法題目,要求在 n x n 的棋盤上放置 n 個皇后,並且保證它們之間不會互相攻擊。皇后可以攻擊任意與它處於同一行、同一列或同一對角線的其他棋子,因此我們需要找到所有合法的放置方式,並返回所有解。
實作 pow(x, n),即計算 x 的 n 次方(即 x^n),其中 x 是一個浮點數,而 n 是一個整數。
給定一個字串陣列 strs,請將字母相同但排列順序不同的單字(即異位詞,Anagrams)分組。可以以任意順序返回結果。
給定一個 n × n 的 2D 矩陣 matrix,將其順時針旋轉 90 度(原地 旋轉,不使用額外的矩陣)。
給定一個可包含重複數字的整數數組 nums,返回所有不重複的排列。
52. N-Queens II 題目是經典的組合優化問題,它要求解出一個 n x n 的棋盤上,放置 n 個皇后,且要求皇后們不互相攻擊,並計算出所有合法的解的數量。
51. N-Queens 是一個經典的演算法題目,要求在 n x n 的棋盤上放置 n 個皇后,並且保證它們之間不會互相攻擊。皇后可以攻擊任意與它處於同一行、同一列或同一對角線的其他棋子,因此我們需要找到所有合法的放置方式,並返回所有解。
實作 pow(x, n),即計算 x 的 n 次方(即 x^n),其中 x 是一個浮點數,而 n 是一個整數。
給定一個字串陣列 strs,請將字母相同但排列順序不同的單字(即異位詞,Anagrams)分組。可以以任意順序返回結果。
給定一個 n × n 的 2D 矩陣 matrix,將其順時針旋轉 90 度(原地 旋轉,不使用額外的矩陣)。
給定一個可包含重複數字的整數數組 nums,返回所有不重複的排列。
你可能也想看
Google News 追蹤
Thumbnail
【vocus 精選投資理財/金融類沙龍,輸入 "moneyback" 年訂閱 9 折】 市場動盪時,加碼永遠值得的投資標的——「自己」 川普政府再度拋出關稅震撼彈,全球市場應聲重挫,從散戶到專業投資人,都急著找尋買進殺出的訊號,就是現在,輪到知識進場!把握時機讓自己升級,別放過反彈的機會!
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們一個輸入陣列nums,要求我們掃描美個陣列元素nums[i],計算除了nums[i]以外的陣列元素連乘積。 題目的原文敘述 測試範例 Example 1: Input: nums = [1,2,3,4] Output: [24,12,8,6] nums[0] 以
Thumbnail
題目敘述 題目會給定一個二元陣列nums(也就是說,陣列元素只有0,1這兩種情況)。 我們必須從裡面選擇一個元素刪除之後,請問連續為1的最長子陣列的長度是多少? 測試範例 Example 1: Input: nums = [1,1,0,1] Output: 3 Explanation:
Thumbnail
題目敘述 題目會給定一個二元陣列nums(也就是說,陣列元素只有0,1這兩種情況)和指定的k值。 我們最多可以把k個0反轉成1,請問連續唯一的最長子陣列的長度是多少? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,1,1,0,0,0,1,1,1,1,
Thumbnail
題目敘述 題目會給定一個有n個整數的陣列nums和指定的k值,問我們長度為k的子陣列的平均值的最大值是多少? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,12,-5,-6,50,3], k = 4 Output: 12.75000 Explanati
Thumbnail
題目敘述 題目會給兩個陣列nums1和nums2。 題目要求我們從中同步選擇長度為k的子序列,並且最大化子序列的分數, 回傳最高的分數值。 分數的定義: 分數 = (nums1[i0] + nums1[i1] +...+ nums1[ik - 1]) * min(nums2[i0] ,
Thumbnail
題目敘述 題目會給定一個陣列nums 和 給定的k值,要求我們找出陣列裡第k大的元素。 題目的原文敘述 測試範例 Example 1: Input: nums = [3,2,1,5,6,4], k = 2 Output: 5 第二大的元素為5​ Example 2: Input:
Thumbnail
這題也是滿經典的DP動態規劃教學案例和題目,就順便複習一下吧。 題目敘述 題目會給我們兩個字串text1, text2。 要求我們找出兩個字串的最長共同子序列,並且返回最長共同子序列的長度。 如果彼此沒有共同子序列,則返回0。 題目的原文敘述 測試範例 Example 1: In
Thumbnail
題目會給定一個陣列,裡面有大有小,可以把數字的大小類比成高度 要求我們找出陣列裡面的相對極大值(relative max value)所在的陣列索引 也就是說當下這個元素,大於左邊鄰居的元素值,也大於右邊鄰居的元素值
Thumbnail
【vocus 精選投資理財/金融類沙龍,輸入 "moneyback" 年訂閱 9 折】 市場動盪時,加碼永遠值得的投資標的——「自己」 川普政府再度拋出關稅震撼彈,全球市場應聲重挫,從散戶到專業投資人,都急著找尋買進殺出的訊號,就是現在,輪到知識進場!把握時機讓自己升級,別放過反彈的機會!
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們一個輸入陣列nums,要求我們掃描美個陣列元素nums[i],計算除了nums[i]以外的陣列元素連乘積。 題目的原文敘述 測試範例 Example 1: Input: nums = [1,2,3,4] Output: [24,12,8,6] nums[0] 以
Thumbnail
題目敘述 題目會給定一個二元陣列nums(也就是說,陣列元素只有0,1這兩種情況)。 我們必須從裡面選擇一個元素刪除之後,請問連續為1的最長子陣列的長度是多少? 測試範例 Example 1: Input: nums = [1,1,0,1] Output: 3 Explanation:
Thumbnail
題目敘述 題目會給定一個二元陣列nums(也就是說,陣列元素只有0,1這兩種情況)和指定的k值。 我們最多可以把k個0反轉成1,請問連續唯一的最長子陣列的長度是多少? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,1,1,0,0,0,1,1,1,1,
Thumbnail
題目敘述 題目會給定一個有n個整數的陣列nums和指定的k值,問我們長度為k的子陣列的平均值的最大值是多少? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,12,-5,-6,50,3], k = 4 Output: 12.75000 Explanati
Thumbnail
題目敘述 題目會給兩個陣列nums1和nums2。 題目要求我們從中同步選擇長度為k的子序列,並且最大化子序列的分數, 回傳最高的分數值。 分數的定義: 分數 = (nums1[i0] + nums1[i1] +...+ nums1[ik - 1]) * min(nums2[i0] ,
Thumbnail
題目敘述 題目會給定一個陣列nums 和 給定的k值,要求我們找出陣列裡第k大的元素。 題目的原文敘述 測試範例 Example 1: Input: nums = [3,2,1,5,6,4], k = 2 Output: 5 第二大的元素為5​ Example 2: Input:
Thumbnail
這題也是滿經典的DP動態規劃教學案例和題目,就順便複習一下吧。 題目敘述 題目會給我們兩個字串text1, text2。 要求我們找出兩個字串的最長共同子序列,並且返回最長共同子序列的長度。 如果彼此沒有共同子序列,則返回0。 題目的原文敘述 測試範例 Example 1: In
Thumbnail
題目會給定一個陣列,裡面有大有小,可以把數字的大小類比成高度 要求我們找出陣列裡面的相對極大值(relative max value)所在的陣列索引 也就是說當下這個元素,大於左邊鄰居的元素值,也大於右邊鄰居的元素值