Non-decreasing Subsequences

medium array hash set backtracking

Problem

Given an integer array nums, return all distinct non-decreasing subsequences with length ≥ 2. You may return the answer in any order.

Inputnums = [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]]
Dedup is over subsequences, not positions — picking the first 7 or second 7 first yields the same sequence.

def find_subsequences(nums):
    out = []
    def dfs(i, path):
        if len(path) >= 2: out.append(path[:])
        used = set()
        for j in range(i, len(nums)):
            if path and nums[j] < path[-1]: continue
            if nums[j] in used: continue
            used.add(nums[j])
            path.append(nums[j])
            dfs(j + 1, path)
            path.pop()
    dfs(0, [])
    return out
function findSubsequences(nums) {
  const out = [];
  function dfs(i, path) {
    if (path.length >= 2) out.push(path.slice());
    const used = new Set();
    for (let j = i; j < nums.length; j++) {
      if (path.length && nums[j] < path[path.length - 1]) continue;
      if (used.has(nums[j])) continue;
      used.add(nums[j]);
      path.push(nums[j]);
      dfs(j + 1, path);
      path.pop();
    }
  }
  dfs(0, []);
  return out;
}
class Solution {
    List<List<Integer>> out = new ArrayList<>();
    int[] a;
    public List<List<Integer>> findSubsequences(int[] nums) {
        a = nums; dfs(0, new ArrayList<>()); return out;
    }
    void dfs(int i, List<Integer> path) {
        if (path.size() >= 2) out.add(new ArrayList<>(path));
        Set<Integer> used = new HashSet<>();
        for (int j = i; j < a.length; j++) {
            if (!path.isEmpty() && a[j] < path.get(path.size() - 1)) continue;
            if (used.contains(a[j])) continue;
            used.add(a[j]);
            path.add(a[j]);
            dfs(j + 1, path);
            path.remove(path.size() - 1);
        }
    }
}
class Solution {
    vector<vector<int>> out;
    vector<int> a;
    void dfs(int i, vector<int>& path) {
        if ((int)path.size() >= 2) out.push_back(path);
        unordered_set<int> used;
        for (int j = i; j < (int)a.size(); j++) {
            if (!path.empty() && a[j] < path.back()) continue;
            if (used.count(a[j])) continue;
            used.insert(a[j]);
            path.push_back(a[j]);
            dfs(j + 1, path);
            path.pop_back();
        }
    }
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        a = nums; vector<int> p; dfs(0, p); return out;
    }
};
Time: O(2^n · n) Space: O(n) recursion + output