Maximum Subarray Problem
Finding the Maximum Subarray Sum
The Maximum Subarray Problem is a classic algorithmic challenge that frequently appears in coding interviews and real-world applications. The goal is to identify the contiguous subarray within a given array of integers that has the largest sum.
This article provides a clear and efficient approach to solve the problem using Kadane’s Algorithm.
Problem Description
Given an array of integers, nums
, the task is to find the largest sum of any contiguous subarray within the array.
Key Points:
- A subarray is a sequence of consecutive elements within the array.
- The solution should work efficiently even for larger arrays.
Explanation:
The subarray [4,-2,2,1,-1,4] has the largest sum 8.
Constraints:
- 1 <= nums.length <= 1000
- -1000 <= nums[i] <= 1000
Optimized Solution: Kadane’s Algorithm
Kadane’s Algorithm provides an elegant and efficient way to solve this problem with a linear time complexity of O(n). It works by iterating through the array and maintaining two values:
- Current Sum (
current_sum
): The maximum sum of the subarray ending at the current index. - Global Maximum (
max_sum
): The maximum sum encountered so far.
Steps of the Algorithm:
- Initialize
current_sum
as0
andmax_sum
as negative infinity. - Iterate through each element in the array:
- Add the current element to
current_sum
. - If
current_sum
becomes less than the current element, resetcurrent_sum
to the current element. This is equivalent to starting a new subarray. - Update
max_sum
ifcurrent_sum
exceeds it.
- Add the current element to
- Return
max_sum
.
Challenges in Multiplying Strings
Handling Large Numbers:
Since the strings can be up to 200 digits long, directly converting them to integers is not feasible due to potential overflow or performance issues.Simulating Manual Multiplication:
Multiplication needs to be performed at the digit level, just like how we multiply numbers by hand on paper.Efficient Result Construction:
Managing intermediate results and carrying over values without excessive computational overhead can be tricky.
There are mainly 2 approach to solve this problem –
- Brute Force
- Recursion Method
1. Brute Force
- Time complexity: O(n^2)
- Space complexity: O(1)
class Solution { public: string multiply(string num1, string num2) { if (num1 == "0" || num2 == "0") return "0"; if (num1.size() < num2.size()) { return multiply(num2, num1); } string res = ""; int zero = 0; for (int i = num2.size() - 1; i >= 0; --i) { string cur = mul(num1, num2[i], zero); res = add(res, cur); zero++; } return res; } string mul(string s, char d, int zero) { int i = s.size() - 1, carry = 0; int digit = d - '0'; string cur; while (i >= 0 || carry) { int n = (i >= 0) ? s[i] - '0' : 0; int prod = n * digit + carry; cur.push_back((prod % 10) + '0'); carry = prod / 10; i--; } reverse(cur.begin(), cur.end()); return cur + string(zero, '0'); } string add(string num1, string num2) { int i = num1.size() - 1, j = num2.size() - 1, carry = 0; string res; while (i >= 0 || j >= 0 || carry) { int n1 = (i >= 0) ? num1[i] - '0' : 0; int n2 = (j >= 0) ? num2[j] - '0' : 0; int total = n1 + n2 + carry; res.push_back((total % 10) + '0'); carry = total / 10; i--; j--; } reverse(res.begin(), res.end()); return res; } };
public class Solution { public int maxSubArray(int[] nums) { int n = nums.length, res = nums[0]; for (int i = 0; i < n; i++) { int cur = 0; for (int j = i; j < n; j++) { cur += nums[j]; res = Math.max(res, cur); } } return res; } }
class Solution: def maxSubArray(self, nums: List[int]) -> int: n, res = len(nums), nums[0] for i in range(n): cur = 0 for j in range(i, n): cur += nums[j] res = max(res, cur) return res
class Solution { /** * @param {number[]} nums * @return {number} */ maxSubArray(nums) { let n = nums.length, res = nums[0]; for (let i = 0; i < n; i++) { let cur = 0; for (let j = i; j < n; j++) { cur += nums[j]; res = Math.max(res, cur); } } return res; } }
2. Recursion
Time & Space Complexity
- Time complexity: O(2^n)
- Space complexity: O(n)
Where m is the length of the array queries and n is the length of the array intervals.
class Solution { public: int maxSubArray(vector<int>& nums) { return dfs(nums, 0, false); } private: int dfs(vector<int>& nums, int i, bool flag) { if (i == nums.size()) return flag ? 0 : -1e6; if (flag) return max(0, nums[i] + dfs(nums, i + 1, true)); return max(dfs(nums, i + 1, false), nums[i] + dfs(nums, i + 1, true)); } };
public class Solution { public int maxSubArray(int[] nums) { return dfs(nums, 0, false); } private int dfs(int[] nums, int i, boolean flag) { if (i == nums.length) { return flag ? 0 : (int) -1e6; } if (flag) { return Math.max(0, nums[i] + dfs(nums, i + 1, true)); } return Math.max(dfs(nums, i + 1, false), nums[i] + dfs(nums, i + 1, true)); } }
class Solution: def maxSubArray(self, nums: List[int]) -> int: def dfs(i, flag): if i == len(nums): return 0 if flag else -1e6 if flag: return max(0, nums[i] + dfs(i + 1, True)) return max(dfs(i + 1, False), nums[i] + dfs(i + 1, True)) return dfs(0, False)
class Solution { /** * @param {number[]} nums * @return {number} */ maxSubArray(nums) { const dfs = (i, flag) => { if (i === nums.length) return flag ? 0 : -1e6; if (flag) return Math.max(0, nums[i] + dfs(i + 1, true)); return Math.max(dfs(i + 1, false), nums[i] + dfs(i + 1, true)); }; return dfs(0, false); } }