Given an integer array nums
, return all the different possible non-decreasing subsequences of the given array with at least two elements. You may return the answer in any order.
Example 1:
Input: nums = [4,6,7,7] Output: [[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]
Example 2:
Input: nums = [4,4,3,2,1] Output: [[4,4]]
Constraints:
1 <= nums.length <= 15
-100 <= nums[i] <= 100
This problem asks to find all non-decreasing subsequences of length at least 2 from a given integer array. The solution utilizes a Depth-First Search (DFS) approach to efficiently explore all possible subsequences.
The core idea is to recursively explore the input array (nums
). The dfs
function takes the following parameters:
u
: The current index being considered in the nums
array.last
: The last element added to the current subsequence (t
). This ensures non-decreasing order.t
: The current subsequence being built.The dfs
function operates as follows:
Base Case: If u
reaches the end of the nums
array, it checks if the length of the current subsequence t
is greater than 1. If it is, the subsequence is added to the result (ans
).
Recursive Step: If the current element nums[u]
is greater than or equal to the last
element in the subsequence, it means we can extend the subsequence. We add nums[u]
to t
, recursively call dfs
with the updated last
and t
, and then backtrack by removing nums[u]
from t
.
Skipping Element: If nums[u]
is different from the last
element, it means we can choose to skip the current element and continue exploring subsequences from the next element without adding the current element to the subsequence. This handles cases where we might have duplicate elements.
This recursive exploration systematically generates all possible non-decreasing subsequences of length at least 2.
class Solution:
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
def dfs(u, last, t):
if u == len(nums):
if len(t) > 1:
ans.append(t[:]) #Append a copy to avoid modification
return
if nums[u] >= last:
t.append(nums[u])
dfs(u + 1, nums[u], t)
t.pop() # Backtrack
if nums[u] != last:
dfs(u + 1, last, t)
ans = []
dfs(0, -1000, []) #Initialize with a very small last value
return ans
The Python code mirrors the approach directly. The -1000
initialization for last
ensures that the first element is always considered. The t[:]
slice creates a copy to avoid modifying the original list during appending to ans
.
Time Complexity: O(N * 2N). In the worst case (all elements are unique and non-decreasing), the number of subsequences can grow exponentially with N (the length of the input array). The DFS explores all these possibilities.
Space Complexity: O(N * 2N) in the worst case. The space is primarily used to store the resulting subsequences. The recursion depth can also be at most N. Therefore, the space complexity is dominated by the size of the ans
list.
The exponential time and space complexity is inherent in the problem because the number of possible subsequences can be very large. For small input arrays (N ≤ 15 as specified), the solution remains practical. For much larger arrays, more sophisticated techniques might be needed to improve performance or handle memory constraints.