Optimal Partition of String
Given a string s
Example 1
Output: 4
Explanation: for example "ab", "ac", "ab", "a".
Example 2
Output: 6
Explanation: every "s" must be on its own.
How to Think About It
Step 1: Make each piece as long as possible
Read the string from the left and keep adding letters to the current piece. Only start a new piece when the next letter is already in the current one.
Step 2: Why greedy is optimal
Ending a piece early never helps: a shorter piece leaves the next piece with more letters to hold, and more letters can only cause more repeats. So the longest possible first piece is always part of some best answer, and the same argument repeats for the rest of the string.
Step 3: Track the letters with a bitmask
The current piece's letters fit in one intccused & bitused |= bitused = 0
Walkthrough
s = "abacaba"
| Letter | Already in piece? | Pieces | Current piece |
|---|---|---|---|
| a | no | 1 | a |
| b | no | 1 | ab |
| a | yes: new piece | 2 | a |
| c | no | 2 | ac |
| a | yes: new piece | 3 | a |
| b | no | 3 | ab |
| a | yes: new piece | 4 | a |
Java Solution
parts
public class OptimalPartitionOfString {
public static int partitionString(String s) {
int parts = 1;
int used = 0; // bit c is set if letter c is in the current part
for (char ch : s.toCharArray()) {
int bit = 1 << (ch - 'a');
if ((used & bit) != 0) {
parts++; // the letter repeats: start a new part
used = 0;
}
used |= bit;
}
return parts;
}
public static void main(String[] args) {
System.out.println(partitionString("abacaba")); // 4
System.out.println(partitionString("ssssss")); // 6
}
}
The original implementation,
Complexity
- Time: O(n).
- Space: O(1): a single integer.
When the pieces must be different strings rather than have different letters, greedy no longer works: see