Collection Framework & Data Structures - java

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);
}
}

Related

How can I compare two strings and try to print out comman latters but i could not avoid to repeat a latter more than once

I am comparing two strings and try to print out comman latters but i could not avoid to repeat a latter more than once.
here is my code
public static String getCommonCharacters ( final String a, final String b){
String result="";
for(int i = 0; i < a.length(); i++){
for(int j = 0; j < b.length(); j++)
if(a.charAt(i)==b.charAt(j)){
result +=a.charAt(i);
}
} return result;
the problem is when a = "baac" and b =" fdeabac " then i get out = "aabaac" instead of "abc" or "bca" etc
change the if condition to:
if (a.charAt(i) == b.charAt(j) &&
!result.contains(String.valueOf(a.charAt(i)))) { ... }
Thus, you only perform the statement:
result +=a.charAt(i);
if the accumulating string doesn't already contain the character.
Working code with minor modification to yours:
public class StringCompare {
public static String getCommonCharacters(final String a, final String b) {
String result = "";
for (int i = 0; i < a.length(); i++) {
for (int j = 0; j < b.length(); j++)
if (a.charAt(i) == b.charAt(j)) {
result += a.charAt(i);
}
}
return result;
}
public static void main(String[] args) {
System.out.println(getCommonCharacters("baac", "fdeabac ").replaceAll(
"(.)\\1{1,}", "$1")); // You could use regular expressions for
// that. Removing repeated characters.
}
}
Output:
bac
Pattern explanation:
"(.)\1{1,}" means any character (added to group 1) followed by itself at least once
"$1" references contents of group 1
More about Regular Expressions Oracle Docs
Hier is another solution: create two new HashSet for each String which we change to charArray, then add them to hashSet with For loops,
retainAll() method provide used to remove it's elements from a list that are not contained in the specified collection.#Java Doc by Oracle
Last For-Loop used to concatenate char as a strings.
String str ="";
Set<Character> s1 = new HashSet<Character>();
Set<Character> s2 = new HashSet<Character>();
for(char c:a.toCharArray()) s1.add(c);
for(char c:b.toCharArray()) s2.add(c);
s1.retainAll(s2);
for(char s:s1) str +=s;
return str;

Given two words, return a list of letters that occur in both words - Java

I have another challenge, it is when the user inputs 2 words, java prints to the console a list of letters that occur in both words. My thought was to create a char array out of the two inputs. But when I did that, I realized that some words are longer than others (Obviously), so I used an if statement to account for both possibilities (word one is bigger than word 2 and vice versa). When I did that, I got an ArrayIndexOutOfBoundsException. I do not know how else to do this. I have looked on StackOverflow for other solutions. Please help! My method for the challenge is below. PS: This is a challenge "within a challenge", I have to have the user choose 1 of five programs. When the user chooses 3, it runs the program below.
System.out.println("Enter a String");
Scanner scan = new Scanner(System.in);
String word1 = scan.nextLine();
System.out.println("Enter another String");
String word2 = scan.nextLine();
String list = "";
System.out.println("");
System.out.println("");
char[] word1Chars = word1.toCharArray();
char[] word2Chars = word2.toCharArray();
if(word1Chars.length > word2Chars.length) {
for(int s = 1; s < word1Chars.length;) {
if(word1Chars[s] == word2Chars[s]) {
list = "" + word1Chars[s];
}
}
} else if(word2Chars.length > word2Chars.length) {
for(int s = 1; s < word2Chars.length;) {
if(word1Chars[s] == word2Chars[s]) {
list = "" + word2Chars[s];
}
}
}
System.out.println(list);
return list;
If this isn't supposed to be very fast, I recommend writing as little code as possible, e.g. given String word1, word2:
Set<String> s1 = new HashSet<>( Arrays.asList( word1.split( "" ) ) );
Set<String> s2 = new HashSet<>( Arrays.asList( word2.split( "" ) ) );
s1.retainAll( s2 );
for( String c: s1 ) System.out.print(c);
System.out.println();
Replace the code after the initialisation of word1 and word2.
A simple regex could do the trick :
public static void main(String[] args) {
String s1 = "abcd";
String s2 = "saxydp";
System.out.println(s1.replaceAll("[^+" + s2 + "]", "").replaceAll("(\\w).*?\\1+","$1"));
}
O/P :
ad
Explanation : first of all in s1 replace everything that doesn't occur in s2. Next, replace every duplicate element :). Purely experimental code ..
This:
if(word1Chars.length > word2Chars.length) {
for(int s = 1; s < word1Chars.length;) {
is incrementing until s is the length of the LONGER of the two strings, but calling this:
if(word1Chars[s] == word2Chars[s])
So if word1 has 10 letters, eventually s will equal 9, and you'll check word2Chars[9], which could be out of bounds.
You can do something like this :
Scanner input = new Scanner(System.in);
System.out.println("Enter 2 strings : ");
String word1 = input.next();
String word2 = input.next();
String commonChar="";
for(char ch: word1.toCharArray()) {
if(word2.contains(ch+"") && !commonChar.contains(ch+"")) {
commonChar+=ch;
}
}
System.out.println(commonChar);
o/p
Enter 2 strings :
12345678
111222
12
In this we check if the letters contains in the other word then we add it but we add it only once.
I think the easiest way is to use nested for loops to iterate through the char arrays and compare each individual char. Then add to your list as needed.
Something like:
for (int i=0; i < word1chars.length; i++)
for(int x=0; x < word2chars.length; x++)
if (word1chars[i] == word2chars[x])
{
//add your letter to your list here
}
Using a set you can maybe achieve better performance. It follows an example:
import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
class C {
public static void main(String[] args) {
String w1 = "samefoo";
String w2 = "barsame";
Set set = new HashSet();
char[] a1 = w1.toCharArray();
char[] a2 = w2.toCharArray();
List list = new ArrayList();
for(int i = 0; i < a1.length; i++)
set.add(a1[i]);
for(int i = 0; i < a2.length; i++)
if(set.contains(a2[i]))
list.add(a2[i]);
System.out.println(list);
}
}
This is probably not as good as some of the others, but since I've written it, may as well add it to the list.
char[] word1Chars = word1.toCharArray();
char[] word2Chars = word2.toCharArray();
Arrays.sort(word1Chars);
Arrays.sort(word2Chars);
int i = 0, j = 0;
String duplicates = "";
while (i < word1Chars.length && j < word2Chars.length)
{
if (word1Chars[i] == word2Chars[j]) {
duplicates += word1Chars[i];
i++;
j++;
}
else if (word1Chars[i] > word2Chars[j]) j++;
else i++;
}
System.out.println(duplicates);

Sorting characters alphabetically in a String

Could smb please explaing the process of sorting characters of String alphabetically? For example, if I have String "hello" the output should be "ehllo" but my code is doing it wrong.
public static void main(String[] args)
{
String result = "";
Scanner kbd = new Scanner(System.in);
String input = kbd.nextLine();
for(int i = 1; i < input.length(); i++)
{
if(input.charAt(i-1) < input.charAt(i))
result += input.charAt(i-1);
//else
// result += input.charAt(i);
}
System.out.println(result);
}
}
You may do the following thing -
1. Convert your String to char[] array.
2. Using Arrays.sort() sort your char array
Code snippet:
String input = "hello";
char[] charArray = input.toCharArray();
Arrays.sort(charArray);
String sortedString = new String(charArray);
System.out.println(sortedString);
Or if you want to sort the array using for loop (for learning purpose) you may use (But I think the first one is best option ) the following code snippet-
input="hello";
char[] charArray = input.toCharArray();
length = charArray.length();
for(int i=0;i<length;i++){
for(int j=i+1;j<length;j++){
if (charArray[j] < charArray[i]) {
char temp = charArray[i];
charArray[i]=arr[j];
charArray[j]=temp;
}
}
}
You can sort a String in Java 8 using Stream as below:
String sortedString =
Stream.of("hello".split(""))
.sorted()
.collect(Collectors.joining());
Procedure :
At first convert the string to char array
Then sort the array of character
Convert the character array to string
Print the string
Code snippet:
String input = "world";
char[] arr = input.toCharArray();
Arrays.sort(arr);
String sorted = new String(arr);
System.out.println(sorted);
Sorting as a task has a lower bound of O(n*logn), with n being the number of elements to sort. What this means is that if you are using a single loop with simple operations, it will not be guaranteed to sort correctly.
A key element in sorting is deciding what you are sorting by. In this case its alphabetically, which, if you convert each character to a char, equates to sorting in ascending order, since a char is actually just a number that the machine maps to the character, with 'a' < 'b'. The only gotcha to look out for is mixed case, since 'z' < 'A'. To get around, this, you can use str.tolower(). I'd recommend you look up some basic sorting algorithms too.
Your for loop is starting at 1 and it should be starting at zero:
for(int i = 0; i < input.length(); i++){...}
You can do this using Arrays.sort, if you put the characters into an array first.
Character[] chars = new Character[str.length()];
for (int i = 0; i < chars.length; i++)
chars[i] = str.charAt(i);
// sort the array
Arrays.sort(chars, new Comparator<Character>() {
public int compare(Character c1, Character c2) {
int cmp = Character.compare(
Character.toLowerCase(c1.charValue()),
Character.toLowerCase(c2.charValue())
);
if (cmp != 0) return cmp;
return Character.compare(c1.charValue(), c2.charValue());
}
});
Now build a string from it using StringBuilder.
Most basic and brute force approach using the two for loop:
It sort the string but with the cost of O(n^2) time complexity.
public void stringSort(String str){
char[] token = str.toCharArray();
for(int i = 0; i<token.length; i++){
for(int j = i+1; j<token.length; j++){
if(token[i] > token[j]){
char temp = token[i];
token[i] = token[j];
token[j] = temp;
}
}
}
System.out.print(Arrays.toString(token));
}
public class SortCharcterInString {
public static void main(String[] args) {
String str = "Hello World";
char[] arr;
List<Character> L = new ArrayList<Character>();
for (int i = 0; i < str.length(); i++) {
arr = str.toLowerCase().toCharArray();
L.add(arr[i]);
}
Collections.sort(L);
str = L.toString();
str = str.replaceAll("\\[", "").replaceAll("\\]", "")
.replaceAll("[,]", "").replaceAll(" ", "");
System.out.println(str);
}

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)", "");

Intersection of two strings in Java

Need a Java function to find intersection of two strings. i.e. characters common to the strings.
Example:
String s1 = new String("Sychelless");
String s2 = new String("Sydney");
Using HashSet<Character>:
HashSet<Character> h1 = new HashSet<Character>(), h2 = new HashSet<Character>();
for(int i = 0; i < s1.length(); i++)
{
h1.add(s1.charAt(i));
}
for(int i = 0; i < s2.length(); i++)
{
h2.add(s2.charAt(i));
}
h1.retainAll(h2);
Character[] res = h1.toArray(new Character[0]);
This is O(m + n), which is asymptotically optimal.
Extract the characters
String.toCharArray
Put them in a Set
Find the intersection
Set.retainAll
Most basic approach:
String wordA = "Sychelless";
String wordB = "Sydney";
String common = "";
for(int i=0;i<wordA.length();i++){
for(int j=0;j<wordB.length();j++){
if(wordA.charAt(i)==wordB.charAt(j)){
common += wordA.charAt(i)+" ";
break;
}
}
}
System.out.println("common is: "+common);
More detail on saugata's response (appeared while I was writing this): -
public static void main(String[] args) {
String s1 = "Seychelles";
String s2 = "Sydney";
Set<Character> ss1 = toSet(s1);
ss1.retainAll(toSet(s2));
System.out.println(ss1);
}
public static Set<Character> toSet(String s) {
Set<Character> ss = new HashSet<Character>(s.length());
for (char c : s.toCharArray())
ss.add(Character.valueOf(c));
return ss;
}
I think the algorithm you are looking for is the problem of the longest common subsequence
Found same question here, refer this
Implementing an efficent algorithm to find the intersection of two strings
By means of Guava this task seems much easier:
String s1 = new String("Sychelless");
String s2 = new String("Sydney");
Set<String> setA = Sets.newHashSet(Splitter.fixedLength(1).split(s1));
Set<String> setB = Sets.newHashSet(Splitter.fixedLength(1).split(s2));
Sets.intersection(setA, setB);
Optimized solution:
public static String twoStrings(String s1, String s2){
HashSet<Character> stringOne = new HashSet<Character>(), stringTwo = new HashSet<Character>();
int stringOneLength = s1.length();
int stringTwoLength = s2.length();
for(int i=0; i<stringOneLength || i<stringTwoLength; i++) {
if(i < stringOneLength)
stringOne.add(s1.charAt(i));
if(i < stringTwoLength)
stringTwo.add(s2.charAt(i));
}
stringOne.retainAll(stringTwo);
return stringOne.toString();
}
I have used TreeSet. And retainAll() in TreeSet to get matched elements.
Oracle Doc:
retainAll(Collection<?> c)
Retains only the elements in this set that are contained in the
specified collection (optional operation).
String s1 = new String("Sychelless");
String s2 = new String("Sydney");
Set<Character> firstSet = new TreeSet<Character>();
for(int i = 0; i < s1.length(); i++) {
firstSet.add(s1.charAt(i));
}
Set<Character> anotherSet = new TreeSet<Character>();
for(int i = 0; i < s2.length(); i++) {
anotherSet.add(s2.charAt(i));
}
firstSet.retainAll(anotherSet);
System.out.println("Matched characters are " + firstSet.toString());//print common strings
//output > Matched characters are [S, e, y]
s1.contains(s2) returns true;
s1.indexOf(s2) returns 0.
s1.indexOf("foo") returns -1
For more sophisticated cases use class Pattern.

Categories

Resources