From 22c873b45329f0ef653380d3ce7896bdcdd4d553 Mon Sep 17 00:00:00 2001 From: dkoval Date: Mon, 21 Oct 2024 10:47:08 +0200 Subject: [PATCH] Solution to "Split a String Into the Max Number of Unique Substrings" problem --- ...StringIntoMaxNumberOfUniqueSubstrings.java | 54 +++++++++++++++++++ ...ringIntoMaxNumberOfUniqueSubstringsTest.kt | 42 +++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/main/java/com/github/dkoval/leetcode/challenge/SplitStringIntoMaxNumberOfUniqueSubstrings.java create mode 100644 src/test/kotlin/com/github/dkoval/leetcode/challenge/SplitStringIntoMaxNumberOfUniqueSubstringsTest.kt diff --git a/src/main/java/com/github/dkoval/leetcode/challenge/SplitStringIntoMaxNumberOfUniqueSubstrings.java b/src/main/java/com/github/dkoval/leetcode/challenge/SplitStringIntoMaxNumberOfUniqueSubstrings.java new file mode 100644 index 00000000..656c9309 --- /dev/null +++ b/src/main/java/com/github/dkoval/leetcode/challenge/SplitStringIntoMaxNumberOfUniqueSubstrings.java @@ -0,0 +1,54 @@ +package com.github.dkoval.leetcode.challenge; + +import java.util.HashSet; +import java.util.Set; + +/** + * Split a String Into the Max Number of Unique Substrings + *

+ * Given a string s, return the maximum number of unique substrings that the given string can be split into. + *

+ * You can split string s into any list of non-empty substrings, where the concatenation of the substrings forms the original string. + * However, you must split the substrings such that all of them are unique. + *

+ * Constraints: + *

+ */ +public interface SplitStringIntoMaxNumberOfUniqueSubstrings { + + int maxUniqueSplit(String s); + + class SplitStringIntoMaxNumberOfUniqueSubstringsRev1 implements SplitStringIntoMaxNumberOfUniqueSubstrings { + + @Override + public int maxUniqueSplit(String s) { + return calc(s, 0, new HashSet<>()); + } + + private int calc(String s, int start, Set seen) { + if (start == s.length()) { + return 0; + } + + // try every position to split s[start:] + // ... xxxxx | yyyyyyyyy + // ^ ^ <-------> a new sub-problem + // start end + int count = 0; + for (int end = start; end < s.length(); end++) { + String substr = s.substring(start, end + 1); + if (seen.contains(substr)) { + continue; + } + // apply backtracking technique + seen.add(substr); + count = Math.max(count, 1 + calc(s, end + 1, seen)); + seen.remove(substr); + } + return count; + } + } +} diff --git a/src/test/kotlin/com/github/dkoval/leetcode/challenge/SplitStringIntoMaxNumberOfUniqueSubstringsTest.kt b/src/test/kotlin/com/github/dkoval/leetcode/challenge/SplitStringIntoMaxNumberOfUniqueSubstringsTest.kt new file mode 100644 index 00000000..e78789f0 --- /dev/null +++ b/src/test/kotlin/com/github/dkoval/leetcode/challenge/SplitStringIntoMaxNumberOfUniqueSubstringsTest.kt @@ -0,0 +1,42 @@ +package com.github.dkoval.leetcode.challenge + +import com.github.dkoval.leetcode.challenge.SplitStringIntoMaxNumberOfUniqueSubstrings.SplitStringIntoMaxNumberOfUniqueSubstringsRev1 +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider +import org.junit.jupiter.params.provider.ArgumentsSource +import java.util.stream.Stream + +internal class SplitStringIntoMaxNumberOfUniqueSubstringsTest { + + class InputArgumentsProvider : ArgumentsProvider { + + override fun provideArguments(context: ExtensionContext): Stream = Stream.of( + Arguments.of("ababccc", 5), + Arguments.of("aba", 2), + Arguments.of("aa", 1), + Arguments.of("wwwzfvedwfvhsww", 11) + ) + } + + @Nested + inner class SplitStringIntoMaxNumberOfUniqueSubstringsRev1Test { + + @ParameterizedTest + @ArgumentsSource(InputArgumentsProvider::class) + fun `should return the maximum number of unique substrings that the given string can be split into`( + s: String, + expected: Int + ) { + SplitStringIntoMaxNumberOfUniqueSubstringsRev1().test(s, expected) + } + } +} + +private fun SplitStringIntoMaxNumberOfUniqueSubstrings.test(s: String, expected: Int) { + val actual = maxUniqueSplit(s) + assertEquals(expected, actual) +}