DEV Community

Dev Cookies
Dev Cookies

Posted on

Blog 4: Combination & Combinatorial Search (Extended Guide)

🔹 Introduction

The combination pattern focuses on choosing elements (without regard to order). Unlike permutations (order matters), here we only care about unique groups.

This pattern appears in problems like:

  • k-combinations (choose k out of n).
  • Combination Sum family of problems (LeetCode 39, 40, 216, 377).
  • Letter case permutations.
  • Palindrome partitioning.

👉 Interviewers love combinations because it tests recursion + pruning + constraints.


🔹 Core Template

void backtrack(int start, List<Integer> current, int[] nums, List<List<Integer>> results) { // Add to results if valid results.add(new ArrayList<>(current)); for (int i = start; i < nums.length; i++) { // Choose current.add(nums[i]); // Explore (move forward) backtrack(i + 1, current, nums, results); // Undo current.remove(current.size() - 1); } } 
Enter fullscreen mode Exit fullscreen mode

🔹 Variations of Combination Problems

Let’s cover all major ones with code snippets.


✅ 1. k-Combinations (Choose k out of n)

  • Input: n=4, k=2
  • Output: [ [1,2], [1,3], [1,4], [2,3], [2,4], [3,4] ]
public List<List<Integer>> combine(int n, int k) { List<List<Integer>> results = new ArrayList<>(); backtrack(1, new ArrayList<>(), n, k, results); return results; } private void backtrack(int start, List<Integer> current, int n, int k, List<List<Integer>> results) { if (current.size() == k) { results.add(new ArrayList<>(current)); return; } for (int i = start; i <= n; i++) { current.add(i); backtrack(i + 1, current, n, k, results); current.remove(current.size() - 1); } } 
Enter fullscreen mode Exit fullscreen mode

✅ 2. Combination Sum I (LeetCode 39)

  • Input: candidates=[2,3,6,7], target=7
  • Output: [ [2,2,3], [7] ]
  • Trick: You can reuse the same number multiple times.
public List<List<Integer>> combinationSum(int[] candidates, int target) { List<List<Integer>> results = new ArrayList<>(); backtrack(0, new ArrayList<>(), candidates, target, results); return results; } private void backtrack(int start, List<Integer> current, int[] candidates, int target, List<List<Integer>> results) { if (target == 0) { results.add(new ArrayList<>(current)); return; } if (target < 0) return; for (int i = start; i < candidates.length; i++) { current.add(candidates[i]); backtrack(i, current, candidates, target - candidates[i], results); // reuse allowed current.remove(current.size() - 1); } } 
Enter fullscreen mode Exit fullscreen mode

✅ 3. Combination Sum II (LeetCode 40)

  • Input: candidates=[10,1,2,7,6,1,5], target=8
  • Output: [ [1,1,6], [1,2,5], [1,7], [2,6] ]
  • Trick: Each number can only be used once & must handle duplicates.
public List<List<Integer>> combinationSum2(int[] candidates, int target) { Arrays.sort(candidates); List<List<Integer>> results = new ArrayList<>(); backtrack(0, new ArrayList<>(), candidates, target, results); return results; } private void backtrack(int start, List<Integer> current, int[] candidates, int target, List<List<Integer>> results) { if (target == 0) { results.add(new ArrayList<>(current)); return; } for (int i = start; i < candidates.length; i++) { if (i > start && candidates[i] == candidates[i - 1]) continue; // skip duplicate if (candidates[i] > target) break; current.add(candidates[i]); backtrack(i + 1, current, candidates, target - candidates[i], results); // i+1 since single use current.remove(current.size() - 1); } } 
Enter fullscreen mode Exit fullscreen mode

✅ 4. Combination Sum III (LeetCode 216)

  • Find k numbers from 1..9 that sum to n.
  • Input: k=3, n=7
  • Output: [ [1,2,4] ]
public List<List<Integer>> combinationSum3(int k, int n) { List<List<Integer>> results = new ArrayList<>(); backtrack(1, new ArrayList<>(), k, n, results); return results; } private void backtrack(int start, List<Integer> current, int k, int target, List<List<Integer>> results) { if (target == 0 && current.size() == k) { results.add(new ArrayList<>(current)); return; } for (int i = start; i <= 9; i++) { if (i > target) break; current.add(i); backtrack(i + 1, current, k, target - i, results); current.remove(current.size() - 1); } } 
Enter fullscreen mode Exit fullscreen mode

✅ 5. Combination Sum IV (LeetCode 377 – DP)

âš¡ Twist: Count combinations, not list them (Dynamic Programming).


✅ 6. Letter Case Permutations (LeetCode 784)

  • Input: "a1b2"
  • Output: "a1b2", "a1B2", "A1b2", "A1B2"
public List<String> letterCasePermutation(String s) { List<String> results = new ArrayList<>(); backtrack(0, new StringBuilder(), s.toCharArray(), results); return results; } private void backtrack(int index, StringBuilder current, char[] chars, List<String> results) { if (index == chars.length) { results.add(current.toString()); return; } char c = chars[index]; if (Character.isLetter(c)) { current.append(Character.toLowerCase(c)); backtrack(index + 1, current, chars, results); current.deleteCharAt(current.length() - 1); current.append(Character.toUpperCase(c)); backtrack(index + 1, current, chars, results); current.deleteCharAt(current.length() - 1); } else { current.append(c); backtrack(index + 1, current, chars, results); current.deleteCharAt(current.length() - 1); } } 
Enter fullscreen mode Exit fullscreen mode

✅ 7. Palindrome Partitioning (LeetCode 131)

  • Input: "aab"
  • Output: [ ["a","a","b"], ["aa","b"] ]
public List<List<String>> partition(String s) { List<List<String>> results = new ArrayList<>(); backtrack(0, new ArrayList<>(), s, results); return results; } private void backtrack(int start, List<String> current, String s, List<List<String>> results) { if (start == s.length()) { results.add(new ArrayList<>(current)); return; } for (int end = start + 1; end <= s.length(); end++) { String sub = s.substring(start, end); if (isPalindrome(sub)) { current.add(sub); backtrack(end, current, s, results); current.remove(current.size() - 1); } } } private boolean isPalindrome(String s) { int l = 0, r = s.length() - 1; while (l < r) if (s.charAt(l++) != s.charAt(r--)) return false; return true; } 
Enter fullscreen mode Exit fullscreen mode

🔹 Complexity Analysis

  • Subset/Combination generation: O(2^n)
  • Combination Sum: exponential but pruned with constraints.
  • Palindrome partitioning: O(2^n * n)

🔹 Interview References

  • LeetCode 39, 40, 216, 377
  • LeetCode 784 (Letter Case Permutation)
  • LeetCode 131 (Palindrome Partitioning)
  • Asked in Google, Microsoft, Amazon, Adobe, Facebook

🔹 Key Takeaways

✅ Combinations = choose elements (order doesn’t matter).
✅ Use start index to avoid duplicates & enforce forward-only choice.
✅ Palindrome + Letter Case = specialized variations.
✅ Combination Sum family = top FAANG interview favorites.


🔹 What’s Next?

In Blog 5: Constraint Satisfaction Pattern, we’ll explore Sudoku Solver, N-Queens revisited, Word Search, and CSP techniques (constraint pruning, branch & bound).


Top comments (0)