Skip to content

Sets

Definition

Sets Definition


Big O Complexity

Sets Complexity


When to Use

Sets When to Use


Pros and Cons

Sets Pros and Cons


Implementation

HashSet (Simplified)

// HashSet is typically implemented using a HashMap
public class MyHashSet<E> {
    private static final Object PRESENT = new Object();
    private HashMap<E, Object> map;

    public MyHashSet() {
        map = new HashMap<>();
    }

    public boolean add(E e) {
        return map.put(e, PRESENT) == null;
    }

    public boolean remove(E e) {
        return map.remove(e) == PRESENT;
    }

    public boolean contains(E e) {
        return map.containsKey(e);
    }

    public int size() {
        return map.size();
    }

    public boolean isEmpty() {
        return map.isEmpty();
    }

    public void clear() {
        map.clear();
    }
}

Bit Set (for integers in range)

// Efficient for dense integer sets
public class BitSet {
    private long[] bits;
    private int size;

    public BitSet(int maxValue) {
        this.bits = new long[(maxValue + 63) / 64];
    }

    public void add(int value) {
        int index = value / 64;
        int bit = value % 64;
        if ((bits[index] & (1L << bit)) == 0) {
            bits[index] |= (1L << bit);
            size++;
        }
    }

    public boolean contains(int value) {
        int index = value / 64;
        int bit = value % 64;
        return (bits[index] & (1L << bit)) != 0;
    }

    public void remove(int value) {
        int index = value / 64;
        int bit = value % 64;
        if ((bits[index] & (1L << bit)) != 0) {
            bits[index] &= ~(1L << bit);
            size--;
        }
    }
}

Java Collections Usage

// HashSet - unordered, O(1) operations
Set<String> hashSet = new HashSet<>();
hashSet.add("apple");
hashSet.add("banana");
hashSet.add("apple");  // Ignored (duplicate)
hashSet.contains("apple");  // true
hashSet.remove("apple");
hashSet.size();  // 1

// Initialize from collection
Set<Integer> fromList = new HashSet<>(Arrays.asList(1, 2, 3, 2, 1));
// Result: {1, 2, 3}

// LinkedHashSet - maintains insertion order
Set<String> linkedSet = new LinkedHashSet<>();
linkedSet.add("c");
linkedSet.add("a");
linkedSet.add("b");
// Iteration order: c, a, b

// TreeSet - sorted order
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(5);
treeSet.add(2);
treeSet.add(8);
// Iteration order: 2, 5, 8

// TreeSet navigation methods
TreeSet<Integer> navSet = new TreeSet<>(Arrays.asList(1, 3, 5, 7, 9));
navSet.first();           // 1 - smallest
navSet.last();            // 9 - largest
navSet.floor(4);          // 3 - largest ≤ 4
navSet.ceiling(4);        // 5 - smallest ≥ 4
navSet.lower(4);          // 3 - largest < 4
navSet.higher(4);         // 5 - smallest > 4
navSet.headSet(5);        // [1, 3] - elements < 5
navSet.tailSet(5);        // [5, 7, 9] - elements ≥ 5
navSet.subSet(3, 7);      // [3, 5] - elements in [3, 7)
navSet.descendingSet();   // [9, 7, 5, 3, 1]

// Custom comparator
Set<String> customSet = new TreeSet<>((a, b) -> b.compareTo(a));  // Reverse order

Set Operations

Set<Integer> setA = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
Set<Integer> setB = new HashSet<>(Arrays.asList(4, 5, 6, 7, 8));

// Union: A ∪ B
Set<Integer> union = new HashSet<>(setA);
union.addAll(setB);  // {1, 2, 3, 4, 5, 6, 7, 8}

// Intersection: A ∩ B
Set<Integer> intersection = new HashSet<>(setA);
intersection.retainAll(setB);  // {4, 5}

// Difference: A - B
Set<Integer> difference = new HashSet<>(setA);
difference.removeAll(setB);  // {1, 2, 3}

// Symmetric Difference: (A - B) ∪ (B - A)
Set<Integer> symDiff = new HashSet<>(setA);
symDiff.addAll(setB);
Set<Integer> temp = new HashSet<>(setA);
temp.retainAll(setB);
symDiff.removeAll(temp);  // {1, 2, 3, 6, 7, 8}

// Subset check: A ⊆ B
boolean isSubset = setB.containsAll(setA);  // false

// Disjoint check: A ∩ B = ∅
boolean isDisjoint = Collections.disjoint(setA, setB);  // false

Common Patterns & Problems

Remove Duplicates

// From array
public int[] removeDuplicates(int[] nums) {
    return Arrays.stream(nums)
        .distinct()
        .toArray();
}

// From list
public List<Integer> removeDuplicates(List<Integer> list) {
    return new ArrayList<>(new LinkedHashSet<>(list));  // Preserves order
}

Find Duplicates

public List<Integer> findDuplicates(int[] nums) {
    Set<Integer> seen = new HashSet<>();
    List<Integer> duplicates = new ArrayList<>();

    for (int num : nums) {
        if (!seen.add(num)) {  // add returns false if already present
            duplicates.add(num);
        }
    }
    return duplicates;
}

Intersection of Two Arrays

public int[] intersection(int[] nums1, int[] nums2) {
    Set<Integer> set1 = new HashSet<>();
    for (int num : nums1) set1.add(num);

    Set<Integer> result = new HashSet<>();
    for (int num : nums2) {
        if (set1.contains(num)) {
            result.add(num);
        }
    }

    return result.stream().mapToInt(i -> i).toArray();
}

Contains Duplicate II (Within k distance)

public boolean containsNearbyDuplicate(int[] nums, int k) {
    Set<Integer> window = new HashSet<>();

    for (int i = 0; i < nums.length; i++) {
        if (i > k) {
            window.remove(nums[i - k - 1]);
        }
        if (!window.add(nums[i])) {
            return true;  // Duplicate found within window
        }
    }
    return false;
}

Longest Consecutive Sequence

public int longestConsecutive(int[] nums) {
    Set<Integer> numSet = new HashSet<>();
    for (int num : nums) numSet.add(num);

    int longest = 0;

    for (int num : numSet) {
        // Only start counting from sequence beginning
        if (!numSet.contains(num - 1)) {
            int currentNum = num;
            int currentStreak = 1;

            while (numSet.contains(currentNum + 1)) {
                currentNum++;
                currentStreak++;
            }
            longest = Math.max(longest, currentStreak);
        }
    }
    return longest;
}

Valid Sudoku

public boolean isValidSudoku(char[][] board) {
    Set<String> seen = new HashSet<>();

    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            char c = board[i][j];
            if (c != '.') {
                String row = c + " in row " + i;
                String col = c + " in col " + j;
                String box = c + " in box " + i/3 + "-" + j/3;

                if (!seen.add(row) || !seen.add(col) || !seen.add(box)) {
                    return false;
                }
            }
        }
    }
    return true;
}

Group Anagrams (Using Set for lookup)

public List<List<String>> groupAnagrams(String[] strs) {
    Map<String, List<String>> map = new HashMap<>();

    for (String s : strs) {
        char[] chars = s.toCharArray();
        Arrays.sort(chars);
        String key = new String(chars);

        map.computeIfAbsent(key, k -> new ArrayList<>()).add(s);
    }

    return new ArrayList<>(map.values());
}

Word Break (Using Set for dictionary)

public boolean wordBreak(String s, List<String> wordDict) {
    Set<String> wordSet = new HashSet<>(wordDict);
    boolean[] dp = new boolean[s.length() + 1];
    dp[0] = true;

    for (int i = 1; i <= s.length(); i++) {
        for (int j = 0; j < i; j++) {
            if (dp[j] && wordSet.contains(s.substring(j, i))) {
                dp[i] = true;
                break;
            }
        }
    }
    return dp[s.length()];
}

Tips & Tricks

Sets Tips