3 ms·
This seems a bit overcomplicated to me. Using a bitmap to track letters you've seen is a great idea. But the parity and counting gives me a headache. How about
by twic 4y ago
This seems a bit overcomplicated to me.
Using a bitmap to track letters you've seen is a great idea. But the parity and counting gives me a headache. How about you start with a zero-size window at the start of the string, then iteratively try to grow it by moving the end forward until it's long enough, and if the character added would be a duplicate, moving the start forward until it's no longer a duplicate? Sort of inchworm-style movement.
I am not smart enough to write Rust, so here it is in Java:
private static int run(String input, int windowSize) {
int windowStart = 0; // start at the start
int windowEnd = 0; // the window is initially zero-size
int lettersSeen = 0; // a bitmap of letters we have seen
while (windowEnd - windowStart < windowSize) {
if (windowEnd >= input.length()) throw new IllegalArgumentException("No unique window found");
int letterToAdd = 1 << input.charAt(windowEnd) - 'a';
while ((lettersSeen & letterToAdd) != 0) {
// duplicate, slide the start until we drop the original
int letterToRemove = 1 << input.charAt(windowStart) - 'a';
assert (lettersSeen & letterToRemove) == letterToRemove; // sanity check that we have seen this letter
lettersSeen ^= letterToRemove;
++windowStart;
}
// add the new letter
assert (lettersSeen & letterToAdd) == 0; // sanity check that we have seen this letter
lettersSeen ^= letterToAdd;
++windowEnd;
}
return windowStart;
}
This is not quite optimal in terms of bit operations - i mask the bitmap in the inner loop condition, but you could just test letterToRemove against letterToAdd and break if they're the same. I think that's a bit less readable though.
Note that although this has two nested loops, they don't both independently range over the whole string, so this is not O(n^2). The outer loop moves windowEnd over the whole string, and the inner one moves windowStart over the whole string bit by bit. Each index visits each position in the string at most once.
- feoren 4y agoThis is clever: you let the window size vary such that you never allow two copies of the same character in your window, and just stop when your window size reaches the target size. Seems like it should work well. But: > i mask the bitmap in the inner loop condition, but you could just test letterToRemove against letterToAdd and break if they're the same You still need to check ((lettersSeen & letterToAdd) != 0) once to know whether you need to enter that loop at all. Worst case (a long string of the same letter) you do this twice per letter in the input anyway.
- nerpderp82 4y agoI asked ChatGPT for a Rust port, https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fdb045f4c83dda36a540da615393ece0 https://play.rust-lang.org/?version=stable&mode=debug&editio... I had to make zero changes, it appears to work.
- twic 4y agoAlthough input.chars().nth() is not good - because of how strings work in Rust, that has to iterate over the string, rather than indexing directly, so O(n) rather than O(1). I think the idiomatic efficient translation would be to use a CharIndices iterator to track each end of the window.