Skip to content

Commit db9e20c

Browse files
committed
feat(algorithms, dynamic-programming): max sub array
1 parent 894bbca commit db9e20c

19 files changed

Lines changed: 231 additions & 57 deletions

File tree

File renamed without changes.

datastructures/arrays/max_subarray/__init__.py renamed to algorithms/dynamic_programming/max_subarray/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,17 @@ def find_max_sub_array(array: List[int]) -> int:
4646
max_ending = 0
4747

4848
return max_so_far
49+
50+
51+
def max_sub_array(nums: List[int]) -> int:
52+
if not nums:
53+
return 0
54+
55+
max_sum = current_sum = nums[0]
56+
57+
for num in nums[1:]:
58+
current_sum = max(current_sum, 0) + num
59+
60+
max_sum = max(max_sum, current_sum)
61+
62+
return max_sum

datastructures/arrays/max_subarray/sub_array_maxsum.py renamed to algorithms/dynamic_programming/max_subarray/sub_array_maxsum.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,3 @@ def find_sub_arr_maxsum(array):
4848
maximum = 0
4949

5050
return sub_array_dict
51-
52-
53-
if __name__ == "__main__":
54-
arr = [4, -1, 2, 1, -40, 1, 2, -1, 4]
55-
print(f"Sub arrays for {arr} are {find_sub_arr_maxsum(arr)}")
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import unittest
2+
from typing import List
3+
from parameterized import parameterized
4+
from algorithms.dynamic_programming.max_subarray import (
5+
find_max_sub_array,
6+
max_sub_array,
7+
)
8+
9+
10+
MAX_SUB_ARRAY_TEST_CASES = [
11+
([], 0),
12+
([1], 1),
13+
([-2, 1, -3, 4, -1, 2, 1, -5, 4], 6),
14+
([5, 4, -1, 7, 8], 23),
15+
([1, 2, 3, 4, -10], 10),
16+
([-2, 1, -3, 4, 1, -1, 2, 1, -3, 4, -2, -5], 8),
17+
([-10, 2, 9, 4, -6, -3, 1, 2, 4, -3, 6], 16),
18+
([-3, -2, -8, -7, -6, -4, -6, -3], -2),
19+
]
20+
21+
22+
class MaxSubArrayTestCases(unittest.TestCase):
23+
@parameterized.expand(MAX_SUB_ARRAY_TEST_CASES)
24+
def test_find_max_sub_array(self, nums: List[int], expected: int):
25+
actual = find_max_sub_array(nums)
26+
self.assertEqual(expected, actual)
27+
28+
@parameterized.expand(MAX_SUB_ARRAY_TEST_CASES)
29+
def test_max_sub_array(self, nums: List[int], expected: int):
30+
actual = max_sub_array(nums)
31+
self.assertEqual(expected, actual)
32+
33+
34+
if __name__ == "__main__":
35+
unittest.main()

algorithms/dynamic_programming/unique_paths/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import Dict, Tuple
22
from functools import lru_cache
33

4+
45
def unique_paths_math(m: int, n: int) -> int:
56
"""Uses math formula"""
67
ans = 1
@@ -73,6 +74,6 @@ def unique_paths_bottom_up(rows: int, cols: int) -> int:
7374
# Fill in the rest of the table
7475
for i in range(1, rows):
7576
for j in range(1, cols):
76-
dp[i][j] = dp[i-1][j] + dp[i][j-1]
77+
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
7778

78-
return dp[rows-1][cols-1]
79+
return dp[rows - 1][cols - 1]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Create Maximum Number
2+
3+
You are given two integer arrays, nums1 and nums2, of lengths m and n, respectively. Each array represents the digits of
4+
a number.
5+
6+
You are also given an integer k. Create the largest possible number of length k (where k ≤ m + n) using digits from both
7+
arrays. You may interleave digits from the two arrays, but the relative order of digits within the same array must be preserved.
8+
9+
Return an array of k digits representing the maximum number.
10+
11+
## Constraints
12+
13+
- `m` = `nums1.length`
14+
- `n` = `nums2.length`
15+
- 1 < `m`, `n` <= 500
16+
- 0 <= `nums[i]`, `nums2[i]` <= 9
17+
- 1 <= `k` <= `m` + `n`
18+
- `nums1` and `nums2` do not have leading zeros
19+
20+
## Examples
21+
22+
![Example 1](./images/examples/create_maximum_number_example_1.png)
23+
![Example 2](./images/examples/create_maximum_number_example_2.png)
24+
![Example 3](./images/examples/create_maximum_number_example_3.png)
25+
![Example 4](./images/examples/create_maximum_number_example_4.png)
26+
![Example 5](./images/examples/create_maximum_number_example_5.png)
27+
28+
## Topics
29+
30+
- Array
31+
- Two Pointers
32+
- Stack
33+
- Greedy
34+
- Monotonic Stack
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from typing import List
2+
3+
4+
def max_number(nums1: List[int], nums2: List[int], k: int) -> List[int]:
5+
"""
6+
Creates Maximum number from two arrays nums1 and nums2 where the number has to be of length k using digits from both
7+
integer arrays
8+
Args:
9+
nums1(int): first integer array
10+
nums2(int): second integer array
11+
k(int): number of digits of final array
12+
Returns:
13+
list: list of integers formed from integer array
14+
"""
15+
16+
def extract_maximum_subsequence(nums: List[int], l: int):
17+
"""
18+
Extracts maximum subsequence from nums of length l using a monotonic stack approach
19+
Args:
20+
nums(list): list of integers
21+
l(int): length of extracted maximum subsequence
22+
Returns:
23+
24+
"""
25+
n = len(nums)
26+
stack = [0] * l # Pre-allocate stack of size k
27+
top = -1 # Stack pointer (top index)
28+
elements_to_drop = n - l # Number of elements we can skip
29+
30+
for num in nums:
31+
# Pop smaller elements from stack if we can still drop elements
32+
while top >= 0 and stack[top] < num and elements_to_drop > 0:
33+
top -= 1
34+
elements_to_drop -= 1
35+
36+
# Add current element if stack not full
37+
if top + 1 < l:
38+
top += 1
39+
stack[top] = num
40+
else:
41+
# Stack is full, just decrement elements_to_drop
42+
elements_to_drop -= 1
43+
44+
return stack
45+
46+
def is_greater(nums_one, nums_two, idx1: int, idx2: int) -> bool:
47+
"""
48+
Compare two arrays starting from given indices.
49+
Returns True if nums1[idx1:] is lexicographically greater than nums2[idx2:].
50+
"""
51+
# If nums1 exhausted, it's not greater
52+
if idx1 >= len(nums_one):
53+
return False
54+
# If nums2 exhausted but nums1 has elements, nums1 is greater
55+
if idx2 >= len(nums_two):
56+
return True
57+
# Compare current elements
58+
if nums_one[idx1] > nums_two[idx2]:
59+
return True
60+
if nums_one[idx1] < nums_two[idx2]:
61+
return False
62+
# If equal, recursively compare next elements
63+
return is_greater(nums_one, nums_two, idx1 + 1, idx2 + 1)
64+
65+
def merge_arrays(
66+
nums_1_subsequence: List[int], nums_2_subsequence: List[int]
67+
) -> List[int]:
68+
"""
69+
Merge two arrays to create the maximum possible array.
70+
Always picks the lexicographically larger remaining portion.
71+
"""
72+
nums_1_len, nums_2_len = len(nums_1_subsequence), len(nums_2_subsequence)
73+
idx1 = idx2 = 0
74+
result = [0] * (nums_1_len + nums_2_len)
75+
76+
for pos in range(nums_1_len + nums_2_len):
77+
# Choose from nums1 if it has greater or equal remaining portion
78+
if is_greater(nums_1_subsequence, nums_2_subsequence, idx1, idx2):
79+
result[pos] = nums_1_subsequence[idx1]
80+
idx1 += 1
81+
else:
82+
result[pos] = nums_2_subsequence[idx2]
83+
idx2 += 1
84+
85+
return result
86+
87+
# Main logic
88+
m, n = len(nums1), len(nums2)
89+
# Determine valid range for elements to take from nums1
90+
min_from_nums1 = max(0, k - n) # Must take at least k-n from nums1
91+
max_from_nums1 = min(k, m) # Can take at most min(k, m) from nums1
92+
93+
max_result = [0] * k
94+
95+
# Try all valid splits between nums1 and nums2
96+
for take_from_nums1 in range(min_from_nums1, max_from_nums1 + 1):
97+
take_from_nums2 = k - take_from_nums1
98+
99+
# Get maximum subsequences from each array
100+
subsequence1 = extract_maximum_subsequence(nums1, take_from_nums1)
101+
subsequence2 = extract_maximum_subsequence(nums2, take_from_nums2)
102+
103+
# Merge the subsequences to get candidate result
104+
candidate = merge_arrays(subsequence1, subsequence2)
105+
106+
# Update max_result if candidate is lexicographically larger
107+
if max_result < candidate:
108+
max_result = candidate
109+
110+
return max_result
123 KB
Loading
69.6 KB
Loading
113 KB
Loading

0 commit comments

Comments
 (0)