Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,12 @@ $ java -cp classes com.williamfiset.algorithms.search.BinarySearch

- [Bit manipulations](src/main/java/com/williamfiset/algorithms/other/BitManipulations.java) **- O(1)**
- [List permutations](src/main/java/com/williamfiset/algorithms/other/Permutations.java) **- O(n!)**
- [:movie_camera:](https://www.youtube.com/watch?v=RnlHPR0lyOE) [Power set (set of all subsets)](src/main/java/com/williamfiset/algorithms/other/PowerSet.java) **- O(2<sup>n</sup>)**
- [:movie_camera:](https://www.youtube.com/watch?v=RnlHPR0lyOE) [Power set (set of all subsets)](src/main/java/com/williamfiset/algorithms/other/PowerSet.java) **- O(n · 2<sup>n</sup>)**
- [Set combinations](src/main/java/com/williamfiset/algorithms/other/Combinations.java) **- O(n choose r)**
- [Set combinations with repetition](src/main/java/com/williamfiset/algorithms/other/CombinationsWithRepetition.java) **- O((n+r-1) choose r)**
- [Sliding Window Minimum/Maximum](src/main/java/com/williamfiset/algorithms/other/SlidingWindowMaximum.java) **- O(1)**
- [Square Root Decomposition](src/main/java/com/williamfiset/algorithms/other/SquareRootDecomposition.java) **- O(1) point updates, O(√n) range queries**
- [Unique set combinations](src/main/java/com/williamfiset/algorithms/other/UniqueCombinations.java) **- O(n choose r)**
- [Lazy Range Adder](src/main/java/com/williamfiset/algorithms/other/LazyRangeAdder.java) **- O(1) range updates, O(n) to finalize all updates**

# Search algorithms

Expand All @@ -284,6 +283,7 @@ $ java -cp classes com.williamfiset.algorithms.search.BinarySearch
- [Quicksort (in-place, Hoare partitioning)](src/main/java/com/williamfiset/algorithms/sorting/QuickSort.java) **- Θ(nlog(n))**
- [Quicksort3 (Dutch National Flag algorithm)](src/main/java/com/williamfiset/algorithms/sorting/QuickSort3.java) **- Θ(nlog(n))**
- [Selection sort](src/main/java/com/williamfiset/algorithms/sorting/SelectionSort.java) **- O(n<sup>2</sup>)**
- [Tim sort](src/main/java/com/williamfiset/algorithms/sorting/TimSort.java) **- O(nlog(n))**
- [Radix sort](src/main/java/com/williamfiset/algorithms/sorting/RadixSort.java) **- O(n\*w)**

# String algorithms
Expand Down
7 changes: 0 additions & 7 deletions src/main/java/com/williamfiset/algorithms/other/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@ java_binary(
runtime_deps = [":other"],
)

# bazel run //src/main/java/com/williamfiset/algorithms/other:LazyRangeAdder
java_binary(
name = "LazyRangeAdder",
main_class = "com.williamfiset.algorithms.other.LazyRangeAdder",
runtime_deps = [":other"],
)

# bazel run //src/main/java/com/williamfiset/algorithms/other:Permutations
java_binary(
name = "Permutations",
Expand Down

This file was deleted.

115 changes: 53 additions & 62 deletions src/main/java/com/williamfiset/algorithms/other/PowerSet.java
Original file line number Diff line number Diff line change
@@ -1,84 +1,75 @@
/**
* This code snippet shows how to generate the powerset of a set which is the set of all subsets of
* a set. There are two common ways of doing this which are to use the binary representation of
* numbers on a computer or to do it recursively. Both methods are shown here, pick your flavor!
* Generates the power set of a set, which is the set of all subsets.
*
* <p>Time Complexity: O( 2^n )
* Two approaches are provided: an iterative method using binary representation of numbers, and a
* recursive backtracking method. Both produce the same result.
*
* Time Complexity: O(n * 2^n)
*
* @author William Fiset, william.alexandre.fiset@gmail.com
*/
package com.williamfiset.algorithms.other;

public class PowerSet {

// Use the fact that numbers represented in binary can be
// used to generate all the subsets of an array
static void powerSetUsingBinary(int[] set) {
import java.util.*;

final int N = set.length;
final int MAX_VAL = 1 << N;
public class PowerSet {

for (int subset = 0; subset < MAX_VAL; subset++) {
System.out.print("{ ");
for (int i = 0; i < N; i++) {
int mask = 1 << i;
if ((subset & mask) == mask) System.out.print(set[i] + " ");
/**
* Generates the power set using binary representation. Each integer from 0 to 2^n - 1 represents
* a subset, where bit i indicates whether element i is included.
*/
public static <T> List<List<T>> powerSetBinary(List<T> set) {
int n = set.size();
if (n > 30)
throw new IllegalArgumentException("Set too large: n=" + n + " (max 30)");
int total = 1 << n;
List<List<T>> result = new ArrayList<>(total);

for (int mask = 0; mask < total; mask++) {
List<T> subset = new ArrayList<>();
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) != 0)
subset.add(set.get(i));
}
System.out.println("}");
result.add(subset);
}
return result;
}

// Recursively generate the powerset (set of all subsets) of an array by maintaining
// a boolean array used to indicate which element have been selected
static void powerSetRecursive(int at, int[] set, boolean[] used) {

if (at == set.length) {

// Print found subset!
System.out.print("{ ");
for (int i = 0; i < set.length; i++) if (used[i]) System.out.print(set[i] + " ");
System.out.println("}");

} else {

// Include this element
used[at] = true;
powerSetRecursive(at + 1, set, used);
/**
* Generates the power set using recursive backtracking. At each element, branches into including
* or excluding it.
*/
public static <T> List<List<T>> powerSetRecursive(List<T> set) {
List<List<T>> result = new ArrayList<>();
recurse(0, set, new ArrayList<>(), result);
return result;
}

// Backtrack and don't include this element
used[at] = false;
powerSetRecursive(at + 1, set, used);
private static <T> void recurse(int at, List<T> set, List<T> current, List<List<T>> result) {
if (at == set.size()) {
// Snapshot the current subset — must copy since 'current' is mutated during backtracking
result.add(new ArrayList<>(current));
return;
}
// Include set[at] and explore all subsets of the remaining elements
current.add(set.get(at));
recurse(at + 1, set, current, result);

// Backtrack: undo the inclusion of set[at], then explore without it
current.remove(current.size() - 1);
recurse(at + 1, set, current, result);
}

public static void main(String[] args) {
List<Integer> set = List.of(1, 2, 3);

// Example usage:
int[] set = {1, 2, 3};

powerSetUsingBinary(set);
// prints:
// { }
// { 1 }
// { 2 }
// { 1 2 }
// { 3 }
// { 1 3 }
// { 2 3 }
// { 1 2 3 }

System.out.println();

powerSetRecursive(0, set, new boolean[set.length]);
// prints:
// { 1 2 3 }
// { 1 2 }
// { 1 3 }
// { 1 }
// { 2 3 }
// { 2 }
// { 3 }
// { }
System.out.println("Binary method:");
for (List<Integer> subset : powerSetBinary(set))
System.out.println(subset);

System.out.println("\nRecursive method:");
for (List<Integer> subset : powerSetRecursive(set))
System.out.println(subset);
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/williamfiset/algorithms/sorting/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ java_binary(
runtime_deps = [":sorting"],
)

# bazel run //src/main/java/com/williamfiset/algorithms/sorting:TimSort
java_binary(
name = "TimSort",
main_class = "com.williamfiset.algorithms.sorting.TimSort",
runtime_deps = [":sorting"],
)

# bazel run //src/main/java/com/williamfiset/algorithms/sorting:SelectionSort
java_binary(
name = "SelectionSort",
Expand Down
90 changes: 90 additions & 0 deletions src/main/java/com/williamfiset/algorithms/sorting/TimSort.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Tim sort implementation — a hybrid sorting algorithm combining merge sort and insertion sort.
*
* Tim sort divides the array into small chunks called "runs" and sorts each run using insertion
* sort (which is efficient for small or nearly-sorted data). It then merges the runs using a
* merge step similar to merge sort. This is the algorithm used by Java's Arrays.sort() for objects
* and Python's built-in sort.
*
* Time Complexity: O(n log n) worst case, O(n) best case (already sorted)
* Space Complexity: O(n) for the merge buffer
*
* @author Claude
*/
package com.williamfiset.algorithms.sorting;

public class TimSort implements InplaceSort {

private static final int MIN_RUN = 32;

@Override
public void sort(int[] values) {
timSort(values);
}

public static void timSort(int[] ar) {
if (ar == null || ar.length <= 1)
return;

int n = ar.length;

// Sort individual runs using insertion sort
for (int i = 0; i < n; i += MIN_RUN)
insertionSort(ar, i, Math.min(i + MIN_RUN - 1, n - 1));

// Merge runs, doubling the merge size each iteration
for (int size = MIN_RUN; size < n; size *= 2) {
for (int left = 0; left < n; left += 2 * size) {
int mid = Math.min(left + size - 1, n - 1);
int right = Math.min(left + 2 * size - 1, n - 1);
if (mid < right)
merge(ar, left, mid, right);
}
}
}

/** Insertion sort on ar[lo..hi] inclusive. */
private static void insertionSort(int[] ar, int lo, int hi) {
for (int i = lo + 1; i <= hi; i++) {
int key = ar[i];
int j = i - 1;
while (j >= lo && ar[j] > key) {
ar[j + 1] = ar[j];
j--;
}
ar[j + 1] = key;
}
}

/** Merges two sorted sub-arrays ar[lo..mid] and ar[mid+1..hi]. */
private static void merge(int[] ar, int lo, int mid, int hi) {
int len1 = mid - lo + 1;
int len2 = hi - mid;

int[] left = new int[len1];
int[] right = new int[len2];
System.arraycopy(ar, lo, left, 0, len1);
System.arraycopy(ar, mid + 1, right, 0, len2);

int i = 0, j = 0, k = lo;
while (i < len1 && j < len2) {
// Use <= to maintain stability: equal elements from the left run come first
if (left[i] <= right[j])
ar[k++] = left[i++];
else
ar[k++] = right[j++];
}
while (i < len1)
ar[k++] = left[i++];
while (j < len2)
ar[k++] = right[j++];
}

public static void main(String[] args) {
int[] array = {10, 4, 6, 4, 8, -13, 2, 3};
timSort(array);
// Prints:
// [-13, 2, 3, 4, 4, 6, 8, 10]
System.out.println(java.util.Arrays.toString(array));
}
}
19 changes: 10 additions & 9 deletions src/test/java/com/williamfiset/algorithms/other/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,32 @@ TEST_DEPS = [
] + JUNIT5_DEPS

java_test(
name = "LazyRangeAdderTest",
srcs = ["LazyRangeAdderTest.java"],
name = "SlidingWindowMaximumTest",
srcs = ["SlidingWindowMaximumTest.java"],
main_class = "org.junit.platform.console.ConsoleLauncher",
use_testrunner = False,
args = ["--select-class=com.williamfiset.algorithms.other.LazyRangeAdderTest"],
args = ["--select-class=com.williamfiset.algorithms.other.SlidingWindowMaximumTest"],
runtime_deps = JUNIT5_RUNTIME_DEPS,
deps = TEST_DEPS,
)

java_test(
name = "SlidingWindowMaximumTest",
srcs = ["SlidingWindowMaximumTest.java"],
name = "BitManipulationsTest",
srcs = ["BitManipulationsTest.java"],
main_class = "org.junit.platform.console.ConsoleLauncher",
use_testrunner = False,
args = ["--select-class=com.williamfiset.algorithms.other.SlidingWindowMaximumTest"],
args = ["--select-class=com.williamfiset.algorithms.other.BitManipulationsTest"],
runtime_deps = JUNIT5_RUNTIME_DEPS,
deps = TEST_DEPS,
)

# bazel test //src/test/java/com/williamfiset/algorithms/other:PowerSetTest
java_test(
name = "BitManipulationsTest",
srcs = ["BitManipulationsTest.java"],
name = "PowerSetTest",
srcs = ["PowerSetTest.java"],
main_class = "org.junit.platform.console.ConsoleLauncher",
use_testrunner = False,
args = ["--select-class=com.williamfiset.algorithms.other.BitManipulationsTest"],
args = ["--select-class=com.williamfiset.algorithms.other.PowerSetTest"],
runtime_deps = JUNIT5_RUNTIME_DEPS,
deps = TEST_DEPS,
)
Loading
Loading