Skip to content

Instantly share code, notes, and snippets.

@jacob-pro
Last active November 13, 2022 01:27
Show Gist options
  • Save jacob-pro/74c84c8c545359c49ec2daeee1a1eb55 to your computer and use it in GitHub Desktop.
Save jacob-pro/74c84c8c545359c49ec2daeee1a1eb55 to your computer and use it in GitHub Desktop.
import org.junit.jupiter.api.Test;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
class MergeTest {
/**
* A tuple that represents a character combined with count of how many
* times this character appeared in its string
*/
static class CharacterAndFrequency {
char character;
long frequency;
public CharacterAndFrequency(char character, Map<Character, Long> frequencies) {
this.character = character;
this.frequency = frequencies.get(character);
}
}
/**
* Creates a map counting the frequency of each character in a string.
*/
static Map<Character, Long> frequencyMap(String string) {
Map<Character, Long> frequencyMap = new HashMap<>();
characterStream(string).forEach(character -> {
frequencyMap.compute(character, (_key, count) -> {
if (Objects.isNull(count)) {
return 1L;
} else {
return count + 1L;
}
});
});
return frequencyMap;
}
static String solution(String s1, String s2) {
// Create maps of how frequently each character occurs in each string
Map<Character, Long> s1frequencies = frequencyMap(s1);
Map<Character, Long> s2frequencies = frequencyMap(s2);
Deque<CharacterAndFrequency> s1queue = characterStream(s1)
.map(c -> new CharacterAndFrequency(c, s1frequencies)).collect(Collectors.toCollection(ArrayDeque::new));
Deque<CharacterAndFrequency> s2queue = characterStream(s2)
.map(c -> new CharacterAndFrequency(c, s2frequencies)).collect(Collectors.toCollection(ArrayDeque::new));
StringBuilder stringBuilder = new StringBuilder();
// Compare characters first by the frequency they appear in their respective strings
// then by the lexicographical order of the char.
Comparator<CharacterAndFrequency> comparator = Comparator.<CharacterAndFrequency>comparingLong(c -> c.frequency)
.thenComparing(c -> c.character);
while (!s1queue.isEmpty() && !s2queue.isEmpty()) {
if (comparator.compare(s1queue.peekFirst(), s2queue.peekFirst()) <= 0) {
stringBuilder.append(s1queue.pop().character);
} else {
stringBuilder.append(s2queue.pop().character);
}
}
// Add any leftovers
s1queue.forEach(c -> stringBuilder.append(c.character));
s2queue.forEach(c -> stringBuilder.append(c.character));
return stringBuilder.toString();
}
/**
* Helper function because {@link String#chars()} returns an IntStream when
* we actually want a stream of characters
*/
static Stream<Character> characterStream(String s) {
return s.chars().mapToObj(c -> (char) c);
}
@Test
public void testSolution() {
assertEquals("dcecccbd", solution("dce", "cccbd"));
assertEquals("stouperwer", solution("super", "tower"));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment