Given two strings, find the number of common characters between them.
Example
For s1 = "aabcc" and s2 = "adcaa", the output should be commonCharacterCount(s1, s2) = 3.
Strings have 3 common characters - 2 "a"s and 1 "c".
I've been stuck on this problem for quite a bit and I've tried many approaches to solving this problem, but I cannot quite figure it out. I have the principal idea of how to solve it, but I cannot transfer that to code.
What my approach is to put the string's characters in their own ArrayList and use nested loops to iterate through them comparing the similar characters and storing the count in a int value. I don't have any code because I have tried many different attempts varying my code, but no luck.
I used two nested for loops that are separate from each other like this:
for(int i = 0; i<firstString.size(); i++){
for(int j = 0; j<secondString.size(); j++){
if(firstString.get(i) == secondString.get(j){
lettersInCommon++;
secondString.remove(j);
}
}
}
And
for(int i = 0; i<secondString.size(); i++){
for(int j = 0; j<firstString.size(); j++){
if(firstString.get(i) == secondString.get(j){
lettersInCommon2++;
firstString.remove(i);
}
}
}
So after these loops run, I return the difference between the two lettersinCommon ints depending on their size to avoid negatives. So if lettersInCommon > lettersInCommon2 -- return lettersInCommon - lettersInCommon2; and vice versa.
I don't want anyone to tell me how to code this, I would only like advice towards my logic to see if I can simplify this problem or if I am missing something.
I would also like to state that this code works for some test cases but not all.
I've been taking into account the comments I've received and gotten this far:
ArrayList<Character> firstString = new ArrayList<Character>();
ArrayList<Character> secondString = new ArrayList<Character>();
int lettersInCommon = 0;
for(int i = 0; i<s1.length(); i++){
firstString.add(s1.charAt(i));
}
for(int i = 0; i<s2.length(); i++){
secondString.add(s2.charAt(i));
}
Collections.sort(firstString);
Collections.sort(secondString);
for(char c : firstString){
if(firstString.contains(c) && secondString.contains(c)){
lettersInCommon++;
secondString.remove(s2.indexOf(c));
}
}
I am really close, but the error I get is an out of bounds exception on this line secondString.remove(s2.indexOf(c));
Does anyone have any insight on this?
You could go for maps. It may not be the best solution in terms of performance, but imo one that is intuitive to understand. First, iterate each string and collect each of its (distinct) characters with their appearance count. Then, compare the keysets of both maps (ie the characters) and for each character you find in both maps, store it together with its minimum appearance count from both maps. So something like this:
// first collect characters with their appearance count in maps:
"aabcc" -> 2xa, 1xb, 2xc
"adcaa" -> 3xa, 1xc, 1xd
// now, get all shared characters with their minimum count from both maps:
a -> min(2,3) = 2
b -> not shared
c -> min(2,1) = 1
d -> not shared
I guess this could be implemented in a cool way using the Stream API, but it would be quite a complex statement, not sure whether you have experience with Streams.
edit: Here's one solution using Streams. I bet there are better ones, both performance-wise and from its approach, but it's the first thing that I tried:
public static void main(String[] args) {
System.out.println(commonCharacterCount("aabcc","adcaa"));
}
public static int commonCharacterCount(String s1, String s2) {
Map<Character, Integer> s1CharacterCount = getCharacterCount(s1);
Map<Character, Integer> s2CharacterCount = getCharacterCount(s2);
return s1CharacterCount.keySet().stream()
.filter(s2CharacterCount.keySet()::contains)
.mapToInt(c -> Math.min(s1CharacterCount.get(c), s2CharacterCount.get(c)))
.sum();
}
public static Map<Character, Integer> getCharacterCount(String s) {
Map<Character, Integer> characterCount = new HashMap<>();
for (char c: s.toCharArray()) {
characterCount.put(c, characterCount.computeIfAbsent(c, count -> 0) + 1);
}
return characterCount;
}
==
contains()
to do that for you. You don't even need contains()
, since remove()
tells you if something has been removed or not. So all you need is:
List<Character>
from string2 Use the s1.charAt(i) == s2.charAt(i)
comparison. There is no need to put the strings into an arrayList.
Edit: You'll need to add a conditional statement to make sure that you don't go out of bounds when the strings are of different lengths.
Create a map of the letter counts for each string you give it. Then compare the keys to one another and if the letter is contained in both words, grab the lowest count from the two maps. Try this
public static void main(String[] args)
{
String str1 = "aabbcc";
String str2 = "abcddc";
HashMap<Character, Integer> str1LetterCounts = createLetterCountMap(str1);
HashMap<Character, Integer> str2LetterCounts = createLetterCountMap(str2);
HashMap<Character, Integer> commonCounts = new HashMap<>();
Set<Character> possibleCommonCharacterList = str1LetterCounts.keySet();
for(Character letter : possibleCommonCharacterList)
{
if(str2LetterCounts.containsKey(letter))
{
Integer count1 = str1LetterCounts.get(letter);
Integer count2 = str2LetterCounts.get(letter);
commonCounts.put(letter, count1 <= count2 ? count1 : count2);
System.out.println("Common Character " + letter + " : " + (count1 <= count2 ? count1 : count2));
}
}
}
public static HashMap<Character, Integer> createLetterCountMap(String word)
{
HashMap<Character, Integer> letterCountsForWord = new HashMap<>();
for(int i = 0; i < word.length(); i++)
{
Character key = word.charAt(i);
if(letterCountsForWord.containsKey(key))
{
letterCountsForWord.put(key, letterCountsForWord.get(key) + 1);
}
else
letterCountsForWord.put(key, 1);
}
return letterCountsForWord;
}
Output
Common Character a : 1
Common Character b : 1
Common Character c : 2
int solution(String s1, String s2) {
int count = 0;
String[] arr1 = s1.split("");
String[] arr2 = s2.split("");
for (int i = 0; i < s1.length(); i++) {
String s = arr1[i];//anymatch operator complaining if I directly give arr[i]
if (Arrays.stream(arr2).anyMatch(t -> t.equals(s))) {
for (int j = 0; j < arr2.length; j++) {
if (arr2[j].equals(arr1[i])) {
arr2[j] = "";
break;
}
}
arr1[i] = "";
count++;
}
}
return count;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.