find matching characters in two strings at different indexes - java

I am a C++ programmer. Out of interest, I am developing a java application.
I have two strings in java:
String word1 = "Fold";
String word2 = "Flow";
Now I need a function to get the count of matching characters in both strings but those that are at different indexes. The strings could be of any length but always both words will be of the same length.
Added:
We should increment count for a character by that many occurrences in both words. Ex: abcd and xyaa should return 1, but abca and xaay should return 2. Hope it is clear now.
For ex:, the count for the above example should be 2 (Only letters 'o' and 'l' are considered. Though letter 'f' is present in both words, it is not considered since it is present at the same index on both strings.
My method was to create two map variables Map and initialize it with 0 for all characters. Then calculate count of how many times each letter occurs in both strings and finally check how many of these characters have count more than one.
Ex:
Map<Character, Integer> word_count_1 = createMap(); // initialize with a:0, b:0, c:0,...z:0
Map<Character, Integer> word_count_2 = createMap(); // initialize with a:0, b:0, c:0,...z:0
int count, value;
for (int i=0; i<word1.length(); i++)
{
if (word1.charAt(i) != word2.charAt(i))
{
value = word_count_1.get(word1.charAt(i));
word_count_1.put(word1.charAt(i), ++value);
value= word_count_2.get(word2.charAt(i));
word_count_2.put(word2.charAt(i), ++value);
}
}
Set set = word_count_2.entrySet();
Iterator i = set.iterator();
Map.Entry<Character, Integer> iter;
while(i.hasNext())
{
iter = (Map.Entry)i.next();
if ( (iter.getValue() > 0) && (word_count_1.get(iter.getKey())) > 0 )
{
count++; // This line has a bug. We shall ignore it for now
}
}
Is there any other better method to get the count instead of what I am trying to do? I just dont get a good feeling about what I have done.
Edited:
The line count++ (that I mentioned having a bug) should be changed to following to give correct result:
int letterCount1 = word_count_1.get(iter.getKey());
int letterCount2 = iter.getValue();
if ( (letterCount1 > 0) && (letterCount2 > 0 )
{
int minVal = letterCount1;
if (minVal > letterCount2)
minVal = letterCount2;
count+= minVal;
}

Java 8 Solution
public int duplicates(String wordOne, String wordTwo ){
Set<Character> charSet = new HashSet(109);
wordOne.chars().mapToObj(i -> (char)i).forEach(letter->charSet.add(letter));
int count = 0;
for(int i = 0; i < wordTwo.length(); i++)
if( charSet.contains(wordTwo.charAt(i)) && wordTwo.charAt(i) != wordOne.charAt(i) )
count++;
return count;
}
duplicates("Fold", "Flow"); // -> 2

There's nicer syntax to iterate over the set (see example below) but the actual counting looks fine.
Map<Character, Integer> word_count_1 = createMap(); // initialize with a:0, b:0, c:0,...z:0
Map<Character, Integer> word_count_2 = createMap(); // initialize with a:0, b:0, c:0,...z:0<Character, Integer>
int count, value;
for (int i=0; i<word1.length(); i++)
{
if (word1.charAt(i) != word2.charAt(i))
{
value = word_count_1.get(word1.charAt(i));
word_count_1.put(word1.charAt(i), ++value);
value= word_count_2.get(word2.charAt(i));
word_count_2.put(word2.charAt(i), ++value);
}
}
Set set = word_count_2.entrySet();
for(<Map.Entry<Character, Integer>> iter:set)
{
if ( (iter.getValue() > 0) && (word_count_1.get(iter.getKey())) > 0 )
{
count++; // This line has a bug. We shall ignore it for now
}
}

//Create set which contains word1's unique chars
Set<Character> word1Chars = new HashSet<>();
for(int i = 0; i< word1.length(); i++)
{
char ch = word1.charAt(i);
word1Chars.add(ch);
}
// Count how many chars in word2 are contained in word1 but in another position
int count = 0;
for(int i = 0; i < word2.length(); i++)
{
char ch = word2.charAt(i);
if(ch != word1.charAt(i) && word1Chars.contains(ch))
{
count++;
}
}
EDIT: You have to take into consideration that you may get a different counting depending on which word you iterate. E.g: "abc" and "daa"; "abc" has 1 but "daa" has 2.
If you want the total of correspondences in both words you need to modify this code accordingly.

You do not need to initialize maps for all the characters.
public static int matchCharCountInDifferentIndex(String word1, String word2) {
Map<Character, Integer> word_count_1 = new HashMap<>();
Map<Character, Integer> word_count_2 = new HashMap<>();
for (int i=0; i<word1.length(); i++)
{
if (word1.charAt(i) != word2.charAt(i))
{
word_count_1.compute(word1.charAt(i), (k, v) -> v == null ? 1 : v + 1);
word_count_2.compute(word2.charAt(i), (k, v) -> v == null ? 1 : v + 1);
}
}
int count = 0;
for (Map.Entry<Character, Integer> e : word_count_2.entrySet())
{
count += Math.min(e.getValue(), word_count_1.getOrDefault(e.getKey(), 0));
}
System.out.printf("word1=%s word2=%s result=%d%n", word_count_1, word_count_2, count);
return count;
}
Tests are
matchCharCountInDifferentIndex("Fold", "Flow"); // -> word1={d=1, l=1, o=1} word2={w=1, l=1, o=1} result=2
matchCharCountInDifferentIndex("abca", "xaay"); // -> word1={a=2, b=1, c=1} word2={a=2, x=1, y=1} result=2
In this code
map.compute(key, (k, v) -> v == null ? 1 : v + 1);
is equivalent to
map.put(key, map.getOrDefault(key, 0) + 1);
And
map.getOrDefault(key, 0)
is equivalent to
map.containsKey(key) ? map.get(key) : 0;

Related

Find the intersection of two strings in which characters appearing in both strings are returned (same sequence order as 1st String)

I am using HashMap() for the problem but am facing issues with regards to order and occurrence of characters in output.
I tried to reverse the String builder both while iteration and after StringBuilder was created, still face another issues.
int l1 = inputStr1.length();
int l2 = inputStr2.length();
StringBuilder mkr = new StringBuilder();
HashMap<Character, Integer> res = new HashMap<>();
for (int i = 0; i < l1; i++) {
res.put(inputStr1.charAt(i),i);
}
for (int j = 0; j < l2; j++) {
if (res.containsKey(inputStr2.charAt(j))){
mkr.append(inputStr2.charAt(j));
}
}
mkr = mkr.reverse(); // Code only used in Test Scenario - 2
String result = mkr.toString();
if(result == null){return null;}
return result;
Test Scenario 1 -
Input String 1 : Hello
Input String 2 : world
Expected output is: lo
Actual output generated by my code: ol
Test Scenario 2 - [After reversing the StringBuilder]
Input String 1: hi you are good
Input String 2 : hi man
Expected output is: hi a
Actual output generated by my code: a ih
Your approach seems to be correct. But since you are expecting the final intersection characters to be in order with input String 1, instead of creating a hashmap of characters for string 1, and iterating over string 2, if those operations are reversed, it would give you the expected answer. But this may return duplicates. For e.g, if inputString1 = 'apple' and inputString2 = 'pot', this method may return two p's instead of 1. To avoid this problem, you can remove the character from hashmap once it matches with character in inputString1.
int l1 = inputStr1.length();
int l2 = inputStr2.length();
StringBuilder mkr = new StringBuilder();
HashMap<Character, Integer> res = new HashMap<>();
for (int i = 0; i < l2; i++) {
res.put(inputStr2.charAt(i),i);
}
for (int j = 0; j < l1; j++) {
if (res.containsKey(inputStr1.charAt(j))){
res.remove(inputStr1.charAt(j));
mkr.append(inputStr1.charAt(j);
}
}
String result = mkr.toString();
if(result == null){return null;}
return result;
Finally, found the solution with help of #askipop :
if(inputStr1 == null || inputStr2 == null){
return null;
}
String res = "";
HashMap<Character, Integer> hm = new HashMap<>();
for(int i = 0; i < inputStr2.length(); i++){
Character c = inputStr2.charAt(i);
if(hm.containsKey(c)){
hm.put(c, hm.get(c) + 1);
} else{
hm.put(c, 1);
}
}
for(int i = 0; i < inputStr1.length(); i++){
Character ch = inputStr1.charAt(i);
if(hm.containsKey(ch)){
res += ch;
int c = hm.get(ch);
if (c - 1 > 0){
hm.put(ch, c - 1);
} else{
hm.remove(ch);
}
}
}
if(res.length() > 0){
return res;
}
return null;
}

counting occurance of characters using hashtable in Java

I am trying to count occurrence of each character in a string.
So if I input aaabbbccc I am expecting o/p as {a=3, b=3, c=3} but instead I keep on getting it as {a=1, b=1, c=1} as my hashtable contains method fails and returns false. What is wrong in the code?
I also know that there is a HashMap collection quite similar to hashtable. but as I am learing java I want to try the same code with all datastructures just to get an idea of methods. The code with map is not much different than what I am doing here still this code fails. and I am not able to figure out where is the bug in the code.
I have following code:
Hashtable<Character, Integer> stringHash = new Hashtable<Character, Integer>();
This stringHash is a class level variable.
for(int i=0; i<s.length(); i++){
if(stringHash ==null || stringHash.size()==0){
stringHash.put(s.charAt(i), 1);
}
else{
if(! stringHash.contains(s.charAt(i)) ){
System.out.println(s.charAt(i));
stringHash.put(s.charAt(i), 1);
}
else{
int count = stringHash.get(s.charAt(i));
stringHash.put(s.charAt(i), count++);
}
}
System.out.println(stringHash + " " + s.charAt(i) + " "+ stringHash.contains(s.charAt(i)));
}
This code works for me:
String s = "aaabbbccc";
Map<Character, Integer> stringHash = new HashMap<Character, Integer>();
for (char ch : s.toCharArray())
stringHash.put(ch, stringHash.containsKey(ch) ? (stringHash.get(ch) + 1) : 1);
System.out.println(stringHash);
// output: "{a=3, b=3, c=3}"
I am using a Map<K, V> instead of HashTable<K, V>, but this is more common.
Try something like this....The reason your code is failing is that you are checking contains() on HashTable instead of its keySet. Hope that helps
public static void main(String[] args) {
// TODO Auto-generated method stub
String s = "aaaaabbcccc";
Hashtable<Character, Integer> counter = new Hashtable<Character, Integer>();
int count = 0;
for(int i=0;i<s.length();i++){
if(!counter.keySet().contains(s.charAt(i))){
counter.put(s.charAt(i), 1);
} else {
count = counter.get(s.charAt(i));
counter.put(s.charAt(i), ++count);
}
}
for(char c:counter.keySet()) {
System.out.println("Character : "+c+" - Occurences : "+counter.get(c));
}
}
o/p
Character : b - Occurences : 2
Character : c - Occurences : 4
Character : a - Occurences : 5
Your code
if(stringHash ==null || stringHash.size()==0){
stringHash.put(s.charAt(i), 1);
}
would throw NPE if somehow the hashmap is null. Luckily it seems that you have initialized it properly. The block rather should have been
if(stringHash ==null){
stringHash = new HashMap()
stringHash.put(s.charAt(i), 1);
}
Again, that would not have fixed your bug. You should use containsKey instead of contains that checks for value in HashTable. What you are looking to implement can be summarized in following pseudocode.
initialize hashmap
for each character c in inputString
count = 0
if hashmap has a key for c
count = get value for c from hashmap
end if
put in to hashmap c, count + 1
end for
In Java this would look like :
Map<Character, Integer> charCountMap = new HashMap<>();
for(char c : inputString.toCharArray()){
int count = 0;
if(charCountMap.containsKey(c)){
count = charCountMap.get(c);
}
charCountMap.put(c,count+1);
}
Or for the adventurous, here is Java8 version
Map<Character,Long> map = s.chars().mapToObj(i->(char)i)
.collect(Collectors
.groupingBy(e -> e,
Collectors.counting()));
System.out.println(map);
Finally, do not use HashTable its a legacy class, no one uses it now a days. Stick with HashMap or other flavors of Map implementations.
Debug my code questions are discouraged, but in the way of solving the general problem of counting characters in a string I can suggest a much simpler method:
public static int[] countCharacters( String s ){
int[] count = new int[ 256 ];
for( int xChar = 0; xChar < s.length(); xChar++ ) count[ s.charAt( xChar ) ]++;
return count;
}
This assumes you have single byte characters.
Why do you use hashMap for counting character occurance?
I would use integer array of size 255 like so:
int[] counter = new int[256];
String s = "aaabbbcccc";
for(int i = 0; i < s.length(); i++){
counter[s.charAt(i)]++;
}
for(int i = 0; i < counter.length; i++)
if(counter[i] > 0)
System.out.println(((char)i) + " occurs " + counter[i] + " times");
that coude would give an output:
a occurs 3 times
b occurs 3 times
c occurs 4 times
Don't use Hashtable, you can simplify that code a lot, something like this should work:
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
public class Main {
public static void main(String[] args) {
Map<Character, Long> countMap = count("aabbbcccc");
for (Map.Entry<Character, Long> entry : countMap.entrySet()) {
System.out
.println(MessageFormat.format("Char ''{0}'' with count ''{1}''", entry.getKey(), entry.getValue()));
}
}
private static Map<Character, Long> count(String value) {
Map<Character, Long> countMap = new HashMap<Character, Long>();
if (StringUtils.isNotBlank(value)) {
for (int i = 0; i < value.length(); i++) {
Long count = countMap.get(value.charAt(i));
count = count == null ? 1 : count + 1;
countMap.put(value.charAt(i), count);
}
}
return countMap;
}
}

Find if a string is unique or not

I want to use hashtable to find unique characters as it seems more efficient to me so for example, hello in hashtable would be=> {h:1,e:1,l:2,o:1} & since value is more than 1 then string isnt unique. I know I can do ascii way of counting unique characters but I want to implement the hashtable way.
Please note, I do not want a regex implementation.
static void findHashUnique(String str)
{
Hashtable<Character, Integer> ht = new Hashtable<Character, Integer>();
for(int i=0;i<str.length();i++)
{
int cnt=1;
if(!ht.containsKey(str.charAt(i)))
{
ht.put(str.charAt(i), cnt);
}
}
System.out.print(ht);
}
I am stuck at the part of how will I first initialize the hashtable & also check if value exists then increment. In case of 'l' it will increment to 2 instead of being 1 since the key is the same.
Also Is this solution efficient?
Here's my approach.
String string = "hello";
Hashtable<Character, Integer> map = new Hashtable<>();
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
if (map.containsKey(c)) {
map.put(c, map.get(c) + 1);
} else {
map.put(c, 1);
}
}
System.out.println(map);
Output: {e=1, o=1, l=2, h=1}
Well, I don't know exactly what character encodings you will be examining, but if you are constraining yourself to only ASCII characters, you can use a simple array of 128 elements.
public static String uniqueLetters(String s) {
// storage for ascii characters
char[] letters = new char[128];
// mark counts of all letters
for(int i = 0; i < s.length(); i++) {
letters[ (int)s.charAt(i) ]++;
}
// find unique letters
String uniques = "";
for(int i = 0; i < letters.length; i++) {
if ( letters[i] == 1 ) {
uniques += Character.toString( (char)letters[i] );
}
}
return uniques;
}
To "fix" your code, use a HashSet<Character>, which uses a Hashtable internally, but you don't have to know or worry about that. Just keep adding the chars to the set and you'll be left with a unique set of chars at the end.
To achieve the intention more easily:
String uniqueChars = str.replaceAll("(.)(?=.*\\1)", "");

Having trouble with a frequency table in Java

I have to create a frequency table for how many times a word appears in a sentence. I was trying to accomplish this with 2 arrays but every time I trace it, the words will not go into the frequency tables.
boolean found = false;
for (int y = 0; y < numWordsInArray; y++)
{
found = arrayOfWords[y].equals(word);
if(found)
{
numTimesAppeared[y]++;
}
if (!found) //it's not already found
{
//add the word to the array of words
arrayOfWords[numWordsInArray] = word;
numWordsInArray++;
}
}
and when I run this loop:
for(int x = 0; x < 10; x++)
{
System.out.println(arrayOfWords[x]);
}
to trace the array, I get output of 10 spaces.
link to the whole program : http://pastebin.com/F4t6yCkD
Use a HashMap instead of the array numTimesAppeared.
Sample code:
private Map<String, Integer> freqMap = new HashMap<String, Integer>();
public void statFreq(String[] words) {
for(String word : words) {
Integer freq = freqMap.get(word);
if(freq == null) {
freqMap.put(word, 1);
} else {
freqMap.put(word, freq + 1);
}
}
}
try using a hashtable instead
Hashtable<String, Integer> words = new Hashtable<String, Integer>();
using
Integer count = words.get (word)
and
if (count == null) {
words.put (word, 1);
else
words.put (word, count.intValue () + 1);

Java count occurrence of each item in an sorted array

I have an Array of Strings and want to count the occurrences of any single String.
I have already sorted it. (It's a long Array and I wanted to get rid of the O(n²)-loop)
Here my code.. obviously it runs out in an ind.outOfB. exc.. the reason is clear but I donno how to solve..
for (int i = 0; i < patternsTest.length-1; i++) {
int occ=1;
String temp=patternsTest[i];
while(temp.equals(patternsTest[i+1])){
i++;
occ++;
}
}
This would be a good place for a HashMap, the key would be the Word, and the value the Number of times it occurs. The Map.containsKey and Map.get methods are constant time lookups which are very fast.
Map<String,Integer> map = new HashMap<String,Integer>();
for (int i = 0; i < patternsTest.length; i++) {
String word=patternsTest[i];
if (!map.containsKey(word)){
map.put(word,1);
} else {
map.put(word, map.get(word) +1);
}
}
As a side benefit you don't even need to sort beforehand!
You can use Java HashMap:
Map<String, Integer> occurrenceOfStrings = new HashMap<String, Integer>();
for(String str: patternsTest)
{
Integer currentValue = occurrenceOfStrings.get(str);
if(currentValue == null)
occurrenceOfStrings.put(str, 1);
else
occurrenceOfStrings.put(str, currentValue + 1);
}
This does not have index out of bounds:
String[] patternsTest = {"a", "b"};
for (int i = 0; i < patternsTest.length-1; i++) {
int occ=1;
String temp=patternsTest[i];
while(temp.equals(patternsTest[i+1])){
i++;
occ++;
}
}
You can cause an Index Out of Bounds by changing the data to:
String[] patternsTest = {"a", "a"};
you could try a map and only one loop
Map<String, Integer> occurences = new HashMap<String, Integer>();
String currentString = patternsTest[0];
Integer count = 1;
for (int i = 1; i < patternsTest.length; i++) {
if(currentString.equals(patternsTest[i]) {
count++;
} else {
occurrences.put(currentString, count);
currentString = patternsTest[i];
count = 1;
}
}
occurrences.put(currentString, count);
Guava Multiset solution (two lines of code):
Multiset<String> multiset = HashMultiset.create();
multiset.addAll(Arrays.asList(patternsTest));
//Then you could do...
multiset.count("hello");//Return count the number of occurrences of "hello".
We could use it both sorted and un-sorted arrays. Easy to maintain code.
My solution is:
public int cantOccurences(String pattern, String[] values){
int count = 0;
for (String s : values) {
count += (s.replaceAll("[^".concat(pattern).concat("]"), "").length());
}
return count;
}

Categories

Resources