Programming & Development / April 8, 2025

LeetCode 90: Subsets II in Go – Efficient Solution to Handle Duplicates

Go Golang LeetCode Subsets II Subsets Backtracking Combinations Handling Duplicates Array Manipulation

Introduction

LeetCode 90: Subsets II is a variation of the classic "Subsets" problem, where the input array may contain duplicates. The task is to generate all possible subsets of a given array, but unlike the classic version, subsets with duplicate elements should not be repeated in the result.

This problem can be efficiently solved using the backtracking approach with some clever handling of duplicates. The idea is to recursively build subsets while ensuring that duplicate subsets are avoided.

Problem Statement

Given an integer array nums that may contain duplicates, return all possible subsets (the power set) of the array. The solution must be unique and should not contain duplicate subsets.

Example:

go

Input: nums = [1,2,2]
Output: [[],[1],[1,2],[1,2,2],[2],[2,2]]

Approach: Backtracking with Sorting

Strategy:

  1. Sorting: We begin by sorting the array. Sorting helps in handling duplicates because duplicates will appear consecutively. This will allow us to skip duplicate elements during the backtracking process.
  2. Backtracking: We can generate subsets by recursively choosing whether to include or exclude each element:
  • For each element, we can either include it in the current subset or exclude it.
  • If an element is the same as the previous one and it has not been included in the previous subset, we skip it to avoid duplicates.
  1. Unique Subsets: To ensure uniqueness:
  • After sorting, we skip over elements that are the same as the previous one when we're at the decision point to include or exclude.
  1. Recursive Function: The recursive function explores both options for each element (include or exclude) and accumulates the subsets.

Go Implementation

go

func subsetsWithDup(nums []int) [][]int {
    var res [][]int
    var subset []int
    
    // Sort the array to handle duplicates
    sort.Ints(nums)
    
    // Helper function for backtracking
    var backtrack func(start int)
    backtrack = func(start int) {
        // Append the current subset to the result
        res = append(res, append([]int(nil), subset...))
        
        // Explore further elements
        for i := start; i < len(nums); i++ {
            // Skip duplicates
            if i > start && nums[i] == nums[i-1] {
                continue
            }
            
            // Include the element in the current subset
            subset = append(subset, nums[i])
            // Recurse with the next elements
            backtrack(i + 1)
            // Exclude the element to explore other subsets
            subset = subset[:len(subset)-1]
        }
    }
    
    // Start the backtracking process
    backtrack(0)
    
    return res
}

Explanation

  1. Sorting:
  2. We begin by sorting the nums array. This ensures that duplicate elements are adjacent to each other. Sorting helps to efficiently skip over duplicates during the recursion step.
  3. Backtracking Function (backtrack):
  4. The recursive function backtrack(start) explores subsets starting from the index start. It first adds the current subset to the result (res) and then iterates over the remaining elements starting from start.
  5. Skip Duplicates:
  6. Before including an element in the current subset, we check if it is the same as the previous element. If it is, and if it hasn’t been included in the previous subset, we skip it to avoid duplicates.
  7. Recursion:
  8. For each element, we have two choices:
  • Include the element in the current subset and recurse.
  • Exclude the element and move to the next one.
  1. Building Subsets:
  2. We construct the subset by adding or removing elements as we backtrack, ensuring that all possible subsets are generated without duplicates.

Time and Space Complexity

MetricComplexityTime ComplexityO(2^n)Space ComplexityO(n)

Where n is the number of elements in the nums array. The time complexity is O(2^n) because we generate all possible subsets, and the space complexity is O(n) due to the recursion stack and storing subsets.

Edge Cases

  1. Empty array: If the input array is empty, the only subset is the empty set.
  • Example: nums = []
  • Output: [[]]
  1. Array with all identical elements: The subsets must only include unique combinations, even if the elements are the same.
  • Example: nums = [2, 2, 2]
  • Output: [[], [2], [2, 2], [2, 2, 2]]
  1. Array with negative and positive numbers: The solution should work for arrays with negative numbers as well.
  • Example: nums = [-1, 0, 1]
  • Output: [[], [-1], [-1, 0], [-1, 0, 1], [0], [0, 1], [1]]
  1. Array with a mix of unique and duplicate elements: The approach should efficiently handle mixed arrays and avoid duplicate subsets.
  • Example: nums = [1, 2, 2, 3]
  • Output: [[], [1], [1, 2], [1, 2, 2], [1, 2, 2, 3], [1, 2, 3], [1, 3], [2], [2, 2], [2, 2, 3], [2, 3], [3]]

Conclusion

LeetCode 90 is an interesting problem where you need to generate all possible subsets, but avoid duplicates in the result. Using backtracking combined with sorting allows us to efficiently generate the power set while skipping duplicate subsets.

The solution ensures that all unique subsets are found in O(2^n) time complexity, which is optimal for subset generation problems, and uses O(n) space complexity due to the recursion stack.

This problem is an excellent exercise in backtracking and array manipulation, particularly when dealing with arrays that may contain duplicate elements.


Comments

No comments yet

Add a new Comment

NUHMAN.COM

Information Technology website for Programming & Development, Web Design & UX/UI, Startups & Innovation, Gadgets & Consumer Tech, Cloud Computing & Enterprise Tech, Cybersecurity, Artificial Intelligence (AI) & Machine Learning (ML), Gaming Technology, Mobile Development, Tech News & Trends, Open Source & Linux, Data Science & Analytics

Categories

Tags

©{" "} Nuhmans.com . All Rights Reserved. Designed by{" "} HTML Codex