My Learning Blog

Backtracking solve perputation and subsequences with duplication - 47,491 - 3/4/2024

use set or array to mark used element

47:Given a collection of numbers, nums, that might contain duplicates, return all possible unique permutations in any order.

function permuteUnique(nums: number[]): number[][] {
  nums.sort((a, b) => a - b);
  const res: number[][] = [];
  const seen = new Array(nums.length).fill(false);

  function dfs(start: number, path: number[]) {
    if (path.length === nums.length) {
      res.push([...path]);
      return;
    }

    for (let i = 0; i < nums.length; i++) {
      if (seen[i]) continue;

      if (i > 0 && nums[i] === nums[i - 1] && !seen[i - 1]) continue;

      path.push(nums[i]);
      seen[i] = true;
      dfs(start + 1, path);
      path.pop();
      seen[i] = false;
    }
  }

  dfs(0, []);

  return res;
}

491: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.

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]]

function findSubsequences(nums: number[]): number[][] {
   const res: number[][] = []

   function dfs(start: number, path: number[]){
       if (path.length > 1) res.push([...path])
       // Use a set for uniqueness checks in the current level
       const used = new Set<number>()
       for (let idx = start; idx < nums.length; idx++) {
           // If the current element is smaller than the last element in the path, skip it
           // Also, skip if the element is already used in this recursion level
           if ((path.length > 0 && nums[idx] < path[path.length - 1]) || used.has(nums[idx])) continue
           // Mark this number as used in the current level
           used.add(nums[idx]);
           path.push(nums[idx])
           dfs(idx + 1, path)
           path.pop()
       }
   }

   dfs(0,[])
   return res
};