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)", "");
Related
The question is as follows:
A pangram is a string that contains every letter of the alphabet. Given a sentence determine whether it is a pangram in the English alphabet. Ignore case. Return either pangram or not pangram as appropriate.
My code works for all input except "qmExzBIJmdELxyOFWv LOCmefk TwPhargKSPEqSxzveiun", for which it returns "not pangram", even though the correct answer is "pangram." Does anybody have any ideas as to why my code is outputting the incorrect solution?
public static String pangrams(String s) {
Hashtable<Character, Integer> alpha = new Hashtable<Character, Integer>();
s = s.toLowerCase();
for (int i = 0; i < s.length()-1; i++){
if (alpha.get(s.charAt(i)) != null){
int value = alpha.get(s.charAt(i));
alpha.put(s.charAt(i), value + 1);
}
else{
alpha.put(s.charAt(i), 1);
}
}
if (alpha.size() != 27){
return "not pangram";
}
else{
return "pangram";
}
}
As per your definition of pangram you might want to consider the following:
Use a Set instead of a Map
As far as I know, English has 26 letters
Make sure you don't mistakenly add digits or symbols to your set
Given the three above statements I would slightly change your code to reflect that. That would, more or less, look something like this:
public static String pangrams(String s) {
Set<Character> alpha = new HashSet<>();
s = s.toLowerCase();
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
if (Character.isLetter(c)){
alpha.add(c);
}
}
if (alpha.size() == 26){
return "pangram";
}
return "not pangram";
}
I've written code to find the amount of duplicated characters in a string input. However after reading the specification, I realise this isn't what is being asked. Yes, I need to count the duplicated characters, but not the amount of that particular character, I need the amount of all characters being duplicated.
I've given an input and output to help explain better. I don't think I'm doing a good job.
Input:
"abcdea" => "a" is duplicated =>
Output:
1
Input:
"abcdeae" => "a" and "e" is duplicated =>
Output:
2
Input:
"abcdeaed" => "a", "d" and "e" is duplicated =>
Output:
3
I've put my code below. Can anyone help adjust my code please?
public static int duplicatesCount(String text)
{
Map<Character,Integer> map = new HashMap<Character,Integer>();
char[] carray = text.toCharArray();
for (char c : carray)
{
if (map.containsKey(c))
{
map.put(c, map.get(c) +1);
}
else
{
map.put(c, 1);
}
}
Set <Character> setChar = map.keySet();
int returnC = 1;
for (Character c : setChar)
{
if (map.get(c) > 1)
{
returnC = map.get(c);
}
}
return returnC;
A better way to do this is to sort the string and then iterate through it. If the previous character = the current character, you increase the duplicate number and don't increment it again util you see the character change.
This requires no extra storage (e.g. the hash map).
This can also be used to count the number of duplicates of each letter with a minor change :).
At the end of your snippet...
int returnC = 0;
for (Character c : setChar)
{
if (map.get(c) > 1)
{
returnC ++; //for each which has more than one instance
}
}
return returnC;
Just count everytime you come across a character that has a value greater than 1 in your hashmap
int returnC = 0;
for (Character c : setChar)
{
if (map.get(c) > 1)
returnC++;
}
Or you can do it while you're creating your hashmap like this
Map<Character,Integer> map = new HashMap<Character,Integer>();
char[] carray = text.toCharArray();
Set <Character> setChar = new Set<Character>(); //initialize the set up here
for (char c : carray)
{
if (map.containsKey(c))
{
map.put(c, map.get(c) +1);
setChar.add(c); //just add to set when a char already exists
}
else
{
map.put(c, 1);
}
}
return setChar.size(); //then simply return the size of the set
Here is another approach - without using Map or sorting algorithm.
public static int duplicatesCount(String text) {
int cnt = 0;
while (text.length() > 1) {
char firstLetter = text.charAt(0);
if (text.lastIndexOf(firstLetter) > 0) {
cnt++;
text = text.replaceAll(("" + firstLetter), "");
} else {
text = text.substring(1, text.length());
}
}
return cnt;
}
The basic idea is to go through a string, char-by-char and check does the character exist somewhere in the string ( if (text.lastIndexOf(firstLetter) > 0)). If it exists increment cnt and then remove all occurrences of the character in the string.
Otherwise, just remove the fist character (text = text.substring(1, text.length());)
You could use String methods
int count = 0;
String s = "abcdeabc";
while(s.length() > 0) {
String c = s.substring(0, 1);
if(s.lastIndexOf(c) != 0) {
count++;
}
s = s.replaceAll(c, "");
}
In your current code you are returning the value not the count.
For Eg:
If your input was "abcdea", then returnC holds the value 2 which is the
number of times the key a has repeated.
If your input was "abcdabeb" where a is repeated twice and b is repeated
thrice. Your output will be 3, as returnC will be holding the value for the key
b.
You can modify your code like this.
Set <Character> setChar = map.keySet();
int returnC = 0;
for (Character c : setChar) {
if (map.get(c) > 1) {
returnC++;
}
}
return returnC;
Also we can user String Buffer class to to create another string of duplicate charracters-- and then we can display it--
public static void main(String arghya[])
{
String name="ARGHYA MUKHERJEE";
StringBuffer duplicate=new StringBuffer();
Set<Character> charlist=new HashSet<Character>();
for(int i=0;i<name.length();i++) {
Character c=name.charAt(i);
if(charlist.contains(c))
{
duplicate.append(c);
//System.out.println(c+ " is repeatitive character in the string");
}
else {
charlist.add(c);
}
}
System.out.print("Duplicate characters which has appeared are as follows: "+duplicate);
}
I have been trying to solve this task for probably more than an hour already.
I need to remove all the duplicates from a string but the tricky part is that if a letter is duplicated and odd number of times, one copy of that letter should remain in the final string. For example a string of assdafff should be converted to df because f is presented odd number of times. I managed to make a program to remove all duplicates but I cant find those that are presented an odd number of times there.
It's important to keep the order of encountered elements in the output string the same like in the input.
public static void main(String[] args){
Scanner reader = new Scanner(System.in);
String x = reader.nextLine();
String ne = "";
StringBuffer buf = new StringBuffer(x.length() -1);
for(int i=0; i<x.length(); i++){
for(int v = 0; v<x.length(); v++){
if((x.charAt(i)==x.charAt(v))&&(i!=v)){
break;
}
if((v==x.length()-1)&&(i!=v)){
ne+=x.charAt(i);
}}
}
if(ne.equals("")){
System.out.println("Empty String");
}else{
System.out.println(ne);
}
}
The algorithm is straightforward. As others have pointed, you could store the count for each character of the string in a map, and then keep only the entries of the map with an odd count. In order to preserve the insertion order, you should use a LinkedHashMap. Then, we merge the keys of the map into a new string.
A Java 8 solution could be as follows:
String string = "string-123-string";
Map<Integer, Long> map = string.chars()
.boxed()
.collect(Collectors.groupingBy(
Function.identity(),
LinkedHashMap::new,
Collectors.counting()));
map.values().removeIf(count -> count % 2 == 0);
String result = map.keySet().stream()
.map(i -> new char[] { (char) i.intValue() })
.map(String::new)
.collect(Collectors.joining());
System.out.println(result); // 123
I'd use a Map like the other answers suggested, but the problem with it is that it doesn't store the key/value pairs in an ordered manner, so I used two ArrayLists to store the characters and their equivalent counts.
Here's a working solution:
String string = "thisisastring";
StringBuffer buffer = new StringBuffer();
ArrayList<Character> chars = new ArrayList<>();
ArrayList<Integer> counts = new ArrayList<>();
for(int i= 0; i< string.length(); i++)
{
char curChar = string.charAt(i);
int charIndex;
// if curChar already exists in chars, increment its count
if((charIndex = chars.indexOf(curChar))>-1)
{
counts.set(charIndex, counts.get(charIndex)+1);
}
else // else add it to chars and add its count which is 1 to counts
{
chars.add(curChar);
counts.add(1);
}
}
for(int i= 0; i< chars.size(); i++)
// if char count is odd, add it to the buffer
if(counts.get(i)%2!=0)
buffer.append(Character.toString(chars.get(i)));
System.out.println(buffer.toString()); // prints hisarng
Edit: as #Federico Peralta Schaffner mentioned, you can also use a LinkedHashMap as follows:
String string = "thisisastring";
StringBuffer buffer = new StringBuffer();
LinkedHashMap<Character, Integer> linkedHashMap = new LinkedHashMap<>();
for(int i=0; i< string.length(); i++)
{
char curChar = string.charAt(i);
linkedHashMap.put(curChar, linkedHashMap.containsKey(curChar)?linkedHashMap.get(curChar)+1:1);
}
for(Map.Entry<Character, Integer> entry : linkedHashMap.entrySet())
if(entry.getValue()%2 !=0)
buffer.append(entry.getKey());
System.out.println(buffer.toString()); // prints hisarng
1 iterate and use a Map< Char, Integer > to keep the counts.
2 iterate again and keep only chars with odd count
String string = "deadbeef";
// ALL COUNTS
Map<Character,Integer> counts=new HashMap<Character,Integer>();
for(int i= 0; i< string.length(); i++)
{
char c = string.charAt(i);
if (counts.containsKey(c))
counts.put(c,counts.get(c)+1);
else
counts.put(c, 1);
}
// RESULT
String result="";
// ALLREADY USED
Set<Character> set=new HashSet<Character>();
for(int i= 0; i< string.length(); i++)
{
char c = string.charAt(i);
// ODD AND FIRST
if ((counts.get(c)%2==1)
&&(!set.contains(c)))
result+=c;
set.add(c);
}
System.out.println("RESULT:"+result); // => eabf
You can solve this problem in just one iteration. First you need to save the locations of characters encountered for the first time. If you encounter them again delete the current one and the one you encountered earlier. For example, you have
s = "assdafff"
For all first encountered characters you save them by
for(i = 0; i<s.length(); i++)
if(dict.get(s[i]) == null) //
dict[s[i]] = i;
and else
else // which means it's duplicate
delete both s[i] and s[dict.get(s[i])] from string
and don't forget to delete that current map entry as well.
I am kind of stuck on this java problem involving returning the number of isomorphic pairs in an array of Strings. The code I have written keeps returning incorrect number of isomorphic word pairs.
The definition of isomorphic words is given as follows: Two words are called isomorphic if the letters in one word can be remapped to get the second word. Remapping a letter means replacing all occurrences of it with another letter. The ordering of the letters remains unchanged. No two letters may map to the same letter, but a letter may map to itself.
For example, the words "abca" and "zbxz" are isomorphic because we can map 'a' to 'z', 'b' to 'b' and 'c' to 'x'.
I am not inlcuding the getMap method which I call in the function. The getMap method take any string as input, and returns a map where the keys are the letters in the string, and the corresponding values are the number of times the letter appears in the string.
public class IsomorphicWords {
public int countPairs(String[] words) {
Set <String> pairs = new HashSet<String>();
for (String word:words){
Map noOfOccurencesOfEachLetter= getMap(word);
ArrayList<Integer> valuesFromFirstWord = new ArrayList<Integer>(noOfOccurencesOfEachLetter.values());
Collections.sort(valuesFromFirstWord);
java.util.List<String> list = new ArrayList<String>(Arrays.asList(words));
list.remove(word);
String[] oneLessWord = list.toArray(new String[words.length-1]);
for(String secondWord:oneLessWord){
Map secondNoOfOccurencesOfEachLetter = getMap(secondWord);
ArrayList<Integer> valuesFromSecondWord = new ArrayList<Integer>(secondNoOfOccurencesOfEachLetter.values());
Collections.sort(valuesFromSecondWord);
if (valuesFromFirstWord.equals(valuesFromSecondWord)){
pairs.add(""+word+","+secondWord+"");
}
else{
continue;
}
}
}
return pairs.size()/2;
public Map getMap(String word){
HashMap<String,Integer> noOfOccurencesOfEachLetter= new HashMap<String,Integer>();
for (int i=0;i<word.length();i++){
char letter = word.charAt(i);
String letterInDictionary= Character.toString(letter);
if (noOfOccurencesOfEachLetter.containsKey(letterInDictionary)==true){
int count= noOfOccurencesOfEachLetter.get(letterInDictionary);
noOfOccurencesOfEachLetter.put(letterInDictionary, count+1);
}
else{
noOfOccurencesOfEachLetter.put(letterInDictionary, 1);
}
}
return noOfOccurencesOfEachLetter;
}
}
I'd really appreciate any feedback you can give me on this code.
Thanks,
Junaid
The reason why it gives the incorrect answer probably comes from you take the letter count, and don't look at the position that they have in both words. The first solution that comes up in me, is to create a new array in which you translate the letters to the index of the first occurrence of this letter for each word. For example: "abcd" would be "0123", "abca" would be "0120" and "fhjf" would be "0120" as well. Then you can simply compare the results. I hope this helps...
public int countPairs(String[] words) {
int isomorphicPairs = 0;
for (int i = 0; i < words.length; i++) {
for (int j = i+1; j < words.length; j++) {
if (words[i].length() == words[j].length()) {
String tmp = new String(words[j]);
for (int k = 0; k < tmp.length(); k++)
tmp = tmp.replaceAll("" + tmp.charAt(k), "" + words[i].charAt(k));
if (words[i].equals(tmp)) isomorphicPairs++;
}
}
}
return isomorphicPairs;
}
I recently faced some technical interviews, the questions were:
Q.1 Two Strings are given "Hello" & "World". Print Unique
Characters Present in first and not in the second string
OUTPUT: He.
My Answer: Compare each character of one string to with every other character of second, not optimal at all (wrong, obviously).
Q.2 ABCABBABCAB, OUTPUT:4A5B2C`, (basically count occurrence of each character)
do this in one pass, not multiple traversal in string, there where other
Again do this in optimal way.
Similarly, there where few other question too..
Question which arises at core to me is:
Which data structure from collection framework will help me to handle such scenarios in most optimum way; and
Which particular data structure from Java Collection Framework to be used when and why?
Also, If there are books for such topics, do tell
Any Help-Books, References and Links will be of great help in learning and understanding.
IMPORTANT: I need real time scenarios, where which the data structure is implemented
I have studied, Collection API, not throughly, but a summarised idea of hierachy and major data structure classes. i know how to use them, but where and why exactly use them eludes me?
public class G {
public static void main(String[] args) {
new G().printCharacterCount("ABCABBABCAB");
System.out.println();
new G().printUniqueCharacters("Hello", "world");
}
void printUniqueCharacters(String a, String b) {
Set<Character> set = new HashSet<Character>();
for (int i = 0; i < a.length(); i++)
set.add(a.charAt(i));
for (int i = 0; i < b.length(); i++)
set.remove(b.charAt(i));
for (Character c : set)
System.out.print(c);
}
void printCharacterCount(String a) {
Map<Character, Integer> map = new TreeMap<Character, Integer>();
for(int i = 0; i < a.length(); i++) {
char c = a.charAt(i);
if(!map.containsKey(c))
map.put(c, 0);
map.put(c, map.get(c) +1);
}
for(char c : map.keySet()) {
System.out.print(map.get(c) + "" + c);
}
}
}
Example of algorithm you could use.
Q1.
put all the letters of String1 in a set (which only keeps unique entries)
remove all the letters of String2 from the set
your set now contains the unique letters of String1 which were not in String2
Q2.
store the number of occurrence of the letters in a Map<Character, Integer>
if a letter is not in the map, the count is 1
if a letter is already in the map, the count needs to be incremented
I know how to use them, but where and why exactly use them eludes me?
By trying to solve that kind of puzzle on your own ;-)
Set<Character> set1=new HashSet<Character>(Arrays.asList(ArrayUtils.toObject("Hello".toCharArray())));
Set<Character> set2=new HashSet<Character>(Arrays.asList(ArrayUtils.toObject("World".toCharArray())));
set1.removeAll(set2);
System.out.println(set1);
Using apache ArrayUtils.toObject(char[] array) .You could write a util method instead.
For #1 :
String one = "Hello";
String two = "World";
Set<Character> set = new HashSet<Character>();
for (int i = 0; i < one.length(); i++) {
set.add(one.charAt(i));
}
for (int i = 0; i < two.length(); i++) {
set.remove(two.charAt(i));
}
for (char ch : set) {
System.out.println(ch);
}
For #2 :
String str = YourInput;
int[] array = new int[26];
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
array[ch - 'A']++;
}
for (int i = 0; i < array.length; i++) {
if (array[i] != 0) {
System.out.println(array[i] + (char) (i + 'A'));
}
}
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "World";
List<Character> list1 = new ArrayList<Character>();
List<Character> list2 = new ArrayList<Character>();
for(char c : s1.toCharArray()){
if(!list1.contains(c)){
list1.add(c);
}
}
for(char c : s2.toCharArray()){
if(!list2.contains(c)){
list2.add(c);
}
}
List<Character> uniqueList = new ArrayList<Character>();
for (Character character1 : list1) {
boolean unique = true;
for (Character character2 : list2) {
if(character1.equals(character2)){
unique = false;
}
}
if(unique){
uniqueList.add(character1);
}
}
for (Character character : uniqueList) {
System.out.print(character);
}
}