We need to partition the array into subarrays where each subarray is either two equal elements, three equal elements, or three consecutive increasing elements. At each position, we can try taking 2 or 3 elements if they form a valid pattern, then recursively check if the remainder can also be validly partitioned.
0.true (valid partition found).i+2.i+3.true if any recursive path leads to a valid partition.false if no valid partition is possible from the current position.class Solution:
def validPartition(self, nums: List[int]) -> bool:
def dfs(i):
if i == len(nums):
return True
res = False
if i < len(nums) - 1 and nums[i] == nums[i + 1]:
res = dfs(i + 2)
if i < len(nums) - 2:
if ((nums[i] == nums[i + 1] == nums[i + 2]) or
(nums[i] + 1 == nums[i + 1] and nums[i + 1] + 1 == nums[i + 2])
):
res = res or dfs(i + 3)
return res
return dfs(0)The recursive solution has overlapping subproblems because we might reach the same index through different partition choices. By memoizing results for each starting index, we avoid redundant computations. Once we compute whether a valid partition exists from index i, we store it and reuse it.
true.2 (two equal elements) and recurse.3 (three equal or three consecutive) and recurse.0.class Solution:
def validPartition(self, nums: List[int]) -> bool:
dp = { len(nums) : True }
def dfs(i):
if i in dp:
return dp[i]
res = False
if i < len(nums) - 1 and nums[i] == nums[i + 1]:
res = dfs(i + 2)
if i < len(nums) - 2:
if ((nums[i] == nums[i + 1] == nums[i + 2]) or
(nums[i] + 1 == nums[i + 1] and nums[i + 1] + 1 == nums[i + 2])
):
res = res or dfs(i + 3)
dp[i] = res
return res
return dfs(0)Instead of starting from the beginning and recursing forward, we can build our solution from the ground up. We define dp[i] as whether the first i elements can be validly partitioned. We iterate through the array and for each position, check if we can extend a valid partition by adding a valid 2-element or 3-element subarray.
n+1, initialized to false.dp[0] = true (empty prefix is valid).2 to n:i-1 and i-2 are equal, and dp[i-2] is true, set dp[i] = true.i > 2 and the last three elements form a valid pattern (all equal or consecutive), and dp[i-3] is true, set dp[i] = true.dp[n].class Solution:
def validPartition(self, nums: List[int]) -> bool:
dp = [False] * (len(nums) + 1)
dp[0] = True
for i in range(2, len(nums) + 1):
if nums[i - 1] == nums[i - 2]:
dp[i] = dp[i] or dp[i - 2]
if i > 2 and ((nums[i - 1] == nums[i - 2] == nums[i - 3]) or
(nums[i - 3] + 1 == nums[i - 2] and nums[i - 2] + 1 == nums[i - 1])):
dp[i] = dp[i] or dp[i - 3]
return dp[len(nums)]Since each DP state only depends on the previous three states (dp[i-1], dp[i-2], dp[i-3]), we do not need to store the entire DP array. We can use just three variables and rotate them as we iterate through the array from right to left.
i, i+1, and i+2.true for positions at or beyond the array end).0.2 elements forms a valid subarray and the state two positions ahead is true.3 elements forms a valid subarray and the state three positions ahead is true.class Solution:
def validPartition(self, nums: List[int]) -> bool:
dp = [False, True, True]
for i in range(len(nums) - 2, -1, -1):
dp1 = dp[0]
if nums[i] == nums[i + 1] and dp[1]:
dp[0] = True
elif i < len(nums) - 2 and dp[2] and (
(nums[i] == nums[i + 1] == nums[i + 2]) or
(nums[i] + 1 == nums[i + 1] and nums[i + 1] == nums[i + 2] - 1)
):
dp[0] = True
else:
dp[0] = False
dp[2] = dp[1]
dp[1] = dp1
return dp[0]The three-element partition allows either three equal elements OR three consecutive increasing elements, but not both conditions mixed. Writing nums[i] == nums[i+1] + 1 instead of nums[i] + 1 == nums[i+1] reverses the direction and checks for decreasing sequences.
# Wrong: nums[i] == nums[i+1] + 1 (checks decreasing)
# Correct:
nums[i] + 1 == nums[i + 1] and nums[i + 1] + 1 == nums[i + 2]At each position, you must consider both taking 2 elements (if they're equal) AND taking 3 elements (if they form a valid pattern). Only checking one option or using else if when both could be valid may miss the correct partition path.
# Must use OR logic to try both options:
res = dfs(i + 2) if valid_pair else False
res = res or dfs(i + 3) if valid_triple else resIn the bottom-up DP approach, dp[i] represents whether the first i elements can be partitioned. When checking if elements form a valid pattern, you must use nums[i-1], nums[i-2], nums[i-3] (0-indexed array access) rather than nums[i], which would be out of bounds or reference the wrong elements.