diff --git a/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/combinatorics/Combinatorics.java b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/combinatorics/Combinatorics.java new file mode 100644 index 0000000000..a5c4b325a4 --- /dev/null +++ b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/combinatorics/Combinatorics.java @@ -0,0 +1,67 @@ +package com.baeldung.algorithms.combinatorics; + +import java.util.*; + +import static java.util.Collections.swap; + +public class Combinatorics { + + public static List> permutations(List sequence) { + List> results = new ArrayList<>(); + permutationsInternal(sequence, results, 0); + return results; + } + + private static void permutationsInternal(List sequence, List> results, int index) { + if (index == sequence.size() - 1) { + results.add(new ArrayList<>(sequence)); + } + + for (int i = index; i < sequence.size(); i++) { + swap(sequence, i, index); + permutationsInternal(sequence, results, index + 1); + swap(sequence, i, index); + } + } + + public static List> combinations(List inputSet, int k) { + List> results = new ArrayList<>(); + combinationsInternal(inputSet, k, results, new ArrayList<>(), 0); + return results; + } + + private static void combinationsInternal( + List inputSet, int k, List> results, ArrayList accumulator, int index) { + int leftToAccumulate = k - accumulator.size(); + int possibleToAcculumate = inputSet.size() - index; + + if (accumulator.size() == k) { + results.add(new ArrayList<>(accumulator)); + } else if (leftToAccumulate <= possibleToAcculumate) { + combinationsInternal(inputSet, k, results, accumulator, index + 1); + + accumulator.add(inputSet.get(index)); + combinationsInternal(inputSet, k, results, accumulator, index + 1); + accumulator.remove(accumulator.size() - 1); + } + } + + public static List> powerSet(List sequence) { + List> results = new ArrayList<>(); + powerSetInternal(sequence, results, new ArrayList<>(), 0); + return results; + } + + private static void powerSetInternal( + List set, List> powerSet, List accumulator, int index) { + if (index == set.size()) { + powerSet.add(new ArrayList<>(accumulator)); + } else { + accumulator.add(set.get(index)); + + powerSetInternal(set, powerSet, accumulator, index + 1); + accumulator.remove(accumulator.size() - 1); + powerSetInternal(set, powerSet, accumulator, index + 1); + } + } +} diff --git a/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/combinatorics/CombinatoricsUnitTest.java b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/combinatorics/CombinatoricsUnitTest.java new file mode 100644 index 0000000000..95ffdec239 --- /dev/null +++ b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/combinatorics/CombinatoricsUnitTest.java @@ -0,0 +1,80 @@ +package com.baeldung.algorithms.combinatorics; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +public class CombinatoricsUnitTest { + + @Test + public void givenEmptySequence_whenCallingPermutations_ShouldReturnEmptyList() { + List sequence = Arrays.asList(); + + List> permutations = Combinatorics.permutations(sequence); + + assertEquals(0, permutations.size()); + } + + @Test + public void givenOneElementSequence_whenCallingPermutations_ShouldReturnPermutations() { + List sequence = Arrays.asList(1); + + List> permutations = Combinatorics.permutations(sequence); + + assertEquals(1, permutations.size()); + assertEquals(1, permutations.get(0).size()); + assertSame(1, permutations.get(0).get(0)); + } + + @Test + public void givenFourElementsSequence_whenCallingPermutations_ShouldReturnPermutations() { + List sequence = Arrays.asList(1, 2, 3, 4); + + List> permutations = Combinatorics.permutations(sequence); + + assertEquals(24, permutations.size()); + assertEquals(24, new HashSet<>(permutations).size()); + } + + @Test + public void givenTwoElements_whenCalling3Combinations_ShouldReturnEmptyList() { + List set = Arrays.asList(1, 2); + + List> combinations = Combinatorics.combinations(set, 3); + + assertEquals(0, combinations.size()); + } + + @Test + public void givenThreeElements_whenCalling3Combinations_ShouldReturnOneCombination() { + List set = Arrays.asList(1, 2, 3); + + List> combinations = Combinatorics.combinations(set, 3); + + assertEquals(1, combinations.size()); + assertEquals(combinations.get(0), Arrays.asList(1, 2, 3)); + } + + @Test + public void givenFourElements_whenCalling2Combinations_ShouldReturnCombinations() { + List set = Arrays.asList(1, 2, 3, 4); + + List> combinations = Combinatorics.combinations(set, 2); + + assertEquals(6, combinations.size()); + assertEquals(6, new HashSet<>(combinations).size()); + } + + @Test + public void givenFourElements_whenCallingPowerSet_ShouldReturn15Sets() { + List sequence = Arrays.asList('a', 'b', 'c', 'd'); + + List> combinations = Combinatorics.powerSet(sequence); + + assertEquals(16, combinations.size()); + } +}