Common characters in n strings - java

I m trying to make a function that prints the number of characters common in given n strings. (note that characters may be used multiple times)
I am struggling to perform this operation on n strings However I did it for 2 strings without any characters repeated more than once.
I have posted my code.
public class CommonChars {
public static void main(String[] args) {
String str1 = "abcd";
String str2 = "bcde";
StringBuffer sb = new StringBuffer();
// get unique chars from both the strings
str1 = uniqueChar(str1);
str2 = uniqueChar(str2);
int count = 0;
int str1Len = str1.length();
int str2Len = str2.length();
for (int i = 0; i < str1Len; i++) {
for (int j = 0; j < str2Len; j++) {
// found match stop the loop
if (str1.charAt(i) == str2.charAt(j)) {
count++;
sb.append(str1.charAt(i));
break;
}
}
}
System.out.println("Common Chars Count : " + count + "\nCommon Chars :" +
sb.toString());
}
public static String uniqueChar(String inputString) {
String outputstr="",temp="";
for(int i=0;i<inputstr.length();i++) {
if(temp.indexOf(inputstr.charAt(i))<0) {
temp+=inputstr.charAt(i);
}
}
System.out.println("completed");
return temp;
}
}
3
abcaa
bcbd
bgc
3
their may be chances that a same character can be present multiple times in
a string and you are not supposed to eliminate those characters instead
check the no. of times they are repeated in other strings. for eg
3
abacd
aaxyz
aatre
output should be 2
it will be better if i get solution in java

You have to convert all Strings to Set of Characters and retain all from the first one. Below solution has many places which could be optimised but you should understand general idea.
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) {
List<String> input = Arrays.asList("jonas", "ton", "bonny");
System.out.println(findCommonCharsFor(input));
}
public static Collection<Character> findCommonCharsFor(List<String> strings) {
if (strings == null || strings.isEmpty()) {
return Collections.emptyList();
}
Set<Character> commonChars = convertStringToSetOfChars(strings.get(0));
strings.stream().skip(1).forEach(s -> commonChars.retainAll(convertStringToSetOfChars(s)));
return commonChars;
}
private static Set<Character> convertStringToSetOfChars(String string) {
if (string == null || string.isEmpty()) {
return Collections.emptySet();
}
Set<Character> set = new HashSet<>(string.length() + 10);
for (char c : string.toCharArray()) {
set.add(c);
}
return set;
}
}
Above code prints:
[n, o]

A better strategy for your problem is to use this method:
public int[] countChars(String s){
int[] count = new int[26];
for(char c: s.toCharArray()){
count[c-'a']++;
}
return count;
}
Now if you have n Strings (String[] strings) just find the min of common chars for each letter:
int[][] result = new int[n][26]
for(int i = 0; i<strings.length;i++){
result[i] = countChars(s);
}
// now if you sum the min common chars for each counter you are ready
int commonChars = 0;
for(int i = 0; i< 26;i++){
int min = result[0][i];
for(int i = 1; i< n;i++){
if(min>result[j][i]){
min = result[j][i];
}
}
commonChars+=min;
}

Get list of characters for each string:
List<Character> chars1 = s1.chars() // list of chars for first string
.mapToObj(c -> (char) c)
.collect(Collectors.toList());
List<Character> chars2 = s2.chars() // list of chars for second string
.mapToObj(c -> (char) c)
.collect(Collectors.toList());
Then use retainAll method:
chars1.retainAll(chars2); // retain in chars1 only the chars that are contained in the chars2 also
System.out.println(chars1.size());
If you want to get number of unique chars just use Collectors.toSet() instead of toList()

Well if one goes for hashing:
public static int uniqueChars(String first, String second) {
boolean[] hash = new boolean[26];
int count = 0;
//reduce first string to unique letters
for (char c : first.toLowerCase().toCharArray()) {
hash[c - 'a'] = true;
}
//reduce to unique letters in both strings
for(char c : second.toLowerCase().toCharArray()){
if(hash[c - 'a']){
count++;
hash[c - 'a'] = false;
}
}
return count;
}
This is using bucketsort which gives a n+m complexity but needs the 26 buckets(the "hash" array).
Imo one can't do better in regards of complexity as you need to look at every letter at least once which sums up to n+m.
Insitu the best you can get is imho somewhere in the range of O(n log(n) ) .
Your aproach is somewhere in the league of O(n²)
Addon: if you need the characters as a String(in essence the same as above with count is the length of the String returned):
public static String uniqueChars(String first, String second) {
boolean[] hash = new boolean[26];
StringBuilder sb = new StringBuilder();
for (char c : first.toLowerCase().toCharArray()) {
hash[c - 'a'] = true;
}
for(char c : second.toLowerCase().toCharArray()){
if(hash[c - 'a']){
sb.append(c);
hash[c - 'a'] = false;
}
}
return sb.toString();
}

public static String getCommonCharacters(String... words) {
if (words == null || words.length == 0)
return "";
Set<Character> unique = words[0].chars().mapToObj(ch -> (char)ch).collect(Collectors.toCollection(TreeSet::new));
for (String word : words)
unique.retainAll(word.chars().mapToObj(ch -> (char)ch).collect(Collectors.toSet()));
return unique.stream().map(String::valueOf).collect(Collectors.joining());
}
Another variant without creating temporary Set and using Character.
public static String getCommonCharacters(String... words) {
if (words == null || words.length == 0)
return "";
int[] arr = new int[26];
boolean[] tmp = new boolean[26];
for (String word : words) {
Arrays.fill(tmp, false);
for (int i = 0; i < word.length(); i++) {
int pos = Character.toLowerCase(word.charAt(i)) - 'a';
if (tmp[pos])
continue;
tmp[pos] = true;
arr[pos]++;
}
}
StringBuilder buf = new StringBuilder(26);
for (int i = 0; i < arr.length; i++)
if (arr[i] == words.length)
buf.append((char)('a' + i));
return buf.toString();
}
Demo
System.out.println(getCommonCharacters("abcd", "bcde")); // bcd

Related

implement basic string compression

I am working on question 1.5 from the book Cracking The Coding interview. The problem is to take a string "aabcccccaaa" and turn it into a2b1c5a3.
If the compressed string is not smaller than the original string, then return the original string.
My code is below. I used an ArrayList because I would not know how long the compressed string would be.
My output is [a, 2, b, 1, c, 5], aabc, []. When the program gets to the end of string, it doesn't have a character to compare the last character too.
import java.util.*;
import java.io.*;
public class stringCompression {
public static void main(String[] args) {
String a = "aabcccccaaa";
String b = "aabc";
String v = "aaaa";
check(a);
System.out.println("");
check(b);
System.out.println("");
check(v);
}
public static void check(String g){
ArrayList<Character> c = new ArrayList<Character>();
int count = 1;
int i = 0;
int h = g.length();
for(int j = i + 1; j < g.length(); j++)
{
if(g.charAt(i) == g.charAt(j)){
count++;
}
else {
c.add(g.charAt(i));
c.add((char)( '0' + count));
i = j;
count = 1;
}
}
if(c.size() == g.length()){
System.out.print(g);
}
else{
System.out.print(c);
}
}
}
In the last loop you're not adding the result to the array. When j = g.length() still needs to add the current char and count to the array. So you could check the next value of j before increment it:
for(int j = i + 1; j < g.length(); j++)
{
if(g.charAt(i) == g.charAt(j)){
count++;
}
else {
c.add(g.charAt(i));
c.add((char)( '0' + count));
i = j;
count = 1;
}
if((j + 1) = g.length()){
c.add(g.charAt(i));
c.add((char)( '0' + count));
}
}
I would use a StringBuilder rather than an ArrayList to build your compressed String. When you start compressing, the first character should already be added to the result. The count of the character will be added once you've encountered a different character. When you've reached the end of the String you should just be appending the remaining count to the result for the last letter.
public static void main(String[] args) throws Exception {
String[] data = new String[] {
"aabcccccaaa",
"aabc",
"aaaa"
};
for (String d : data) {
System.out.println(compress(d));
}
}
public static String compress(String str) {
StringBuilder compressed = new StringBuilder();
// Add first character to compressed result
char currentChar = str.charAt(0);
compressed.append(currentChar);
// Always have a count of 1
int count = 1;
for (int i = 1; i < str.length(); i++) {
char nextChar = str.charAt(i);
if (currentChar == nextChar) {
count++;
} else {
// Append the count of the current character
compressed.append(count);
// Set the current character and count
currentChar = nextChar;
count = 1;
// Append the new current character
compressed.append(currentChar);
}
}
// Append the count of the last character
compressed.append(count);
// If the compressed string is not smaller than the original string, then return the original string
return (compressed.length() < str.length() ? compressed.toString() : str);
}
Results:
a2b1c5a3
aabc
a4
You have two errors:
one that Typo just mentioned, because your last character was not added;
and another one, if the original string is shorter like "abc" with only three chars: "a1b1c1" has six chars (the task is "If the compressed string is not smaller than the original string, then return the original string.")
You have to change your if statement, ask for >= instead of ==
if(c.size() >= g.length()){
System.out.print(g);
} else {
System.out.print(c);
}
Use StringBuilder and then iterate on the input string.
private static string CompressString(string inputString)
{
var count = 1;
var compressedSb = new StringBuilder();
for (var i = 0; i < inputString.Length; i++)
{
// Check if we are at the end
if(i == inputString.Length - 1)
{
compressedSb.Append(inputString[i] + count.ToString());
break;
}
if (inputString[i] == inputString[i + 1])
count++;
else
{
compressedSb.Append(inputString[i] + count.ToString());
count = 1;
}
}
var compressedString = compressedSb.ToString();
return compressedString.Length > inputString.Length ? inputString : compressedString;
}

permutations of a string using iteration

I'm trying to find permutation of a given string, but I want to use iteration. The recursive solution I found online and I do understand it, but converting it to an iterative solution is really not working out. Below I have attached my code. I would really appreciate the help:
public static void combString(String s) {
char[] a = new char[s.length()];
//String temp = "";
for(int i = 0; i < s.length(); i++) {
a[i] = s.charAt(i);
}
for(int i = 0; i < s.length(); i++) {
String temp = "" + a[i];
for(int j = 0; j < s.length();j++) {
//int k = j;
if(i != j) {
System.out.println(j);
temp += s.substring(0,j) + s.substring(j+1,s.length());
}
}
System.out.println(temp);
}
}
Following up on my related question comment, here's a Java implementation that does what you want using the Counting QuickPerm Algorithm:
public static void combString(String s) {
// Print initial string, as only the alterations will be printed later
System.out.println(s);
char[] a = s.toCharArray();
int n = a.length;
int[] p = new int[n]; // Weight index control array initially all zeros. Of course, same size of the char array.
int i = 1; //Upper bound index. i.e: if string is "abc" then index i could be at "c"
while (i < n) {
if (p[i] < i) { //if the weight index is bigger or the same it means that we have already switched between these i,j (one iteration before).
int j = ((i % 2) == 0) ? 0 : p[i];//Lower bound index. i.e: if string is "abc" then j index will always be 0.
swap(a, i, j);
// Print current
System.out.println(join(a));
p[i]++; //Adding 1 to the specific weight that relates to the char array.
i = 1; //if i was 2 (for example), after the swap we now need to swap for i=1
}
else {
p[i] = 0;//Weight index will be zero because one iteration before, it was 1 (for example) to indicate that char array a[i] swapped.
i++;//i index will have the option to go forward in the char array for "longer swaps"
}
}
}
private static String join(char[] a) {
StringBuilder builder = new StringBuilder();
builder.append(a);
return builder.toString();
}
private static void swap(char[] a, int i, int j) {
char temp = a[i];
a[i] = a[j];
a[j] = temp;
}
List<String> results = new ArrayList<String>();
String test_str = "abcd";
char[] chars = test_str.toCharArray();
results.add(new String("" + chars[0]));
for(int j=1; j<chars.length; j++) {
char c = chars[j];
int cur_size = results.size();
//create new permutations combing char 'c' with each of the existing permutations
for(int i=cur_size-1; i>=0; i--) {
String str = results.remove(i);
for(int l=0; l<=str.length(); l++) {
results.add(str.substring(0,l) + c + str.substring(l));
}
}
}
System.out.println("Number of Permutations: " + results.size());
System.out.println(results);
Example:
if we have 3 character string e.g. "abc", we can form permuations as below.
1) construct a string with first character e.g. 'a' and store that in results.
char[] chars = test_str.toCharArray();
results.add(new String("" + chars[0]));
2) Now take next character in string (i.e. 'b') and insert that in all possible positions of previously contsructed strings in results. Since we have only one string in results ("a") at this point, doing so gives us 2 new strings 'ba', 'ab'. Insert these newly constructed strings in results and remove "a".
for(int i=cur_size-1; i>=0; i--) {
String str = results.remove(i);
for(int l=0; l<=str.length(); l++) {
results.add(str.substring(0,l) + c + str.substring(l));
}
}
3) Repeat 2) for every character in the given string.
for(int j=1; j<chars.length; j++) {
char c = chars[j];
....
....
}
This gives us "cba", "bca", "bac" from "ba" and "cab", "acb" and "abc" from "ab"
Work queue allows us to create an elegant iterative solution for this problem.
static List<String> permutations(String string) {
List<String> permutations = new LinkedList<>();
Deque<WorkUnit> workQueue = new LinkedList<>();
// We need to permutate the whole string and haven't done anything yet.
workQueue.add(new WorkUnit(string, ""));
while (!workQueue.isEmpty()) { // Do we still have any work?
WorkUnit work = workQueue.poll();
// Permutate each character.
for (int i = 0; i < work.todo.length(); i++) {
String permutation = work.done + work.todo.charAt(i);
// Did we already build a complete permutation?
if (permutation.length() == string.length()) {
permutations.add(permutation);
} else {
// Otherwise what characters are left?
String stillTodo = work.todo.substring(0, i) + work.todo.substring(i + 1);
workQueue.add(new WorkUnit(stillTodo, permutation));
}
}
}
return permutations;
}
A helper class to hold partial results is very simple.
/**
* Immutable unit of work
*/
class WorkUnit {
final String todo;
final String done;
WorkUnit(String todo, String done) {
this.todo = todo;
this.done = done;
}
}
You can test the above piece of code by wrapping them in this class.
import java.util.*;
public class AllPermutations {
public static void main(String... args) {
String str = args[0];
System.out.println(permutations(str));
}
static List<String> permutations(String string) {
...
}
}
class WorkUnit {
...
}
Try it by compiling and running.
$ javac AllPermutations.java; java AllPermutations abcd
The below implementation can also be easily tweaked to return a list of permutations in reverse order by using a LIFO stack of work instead of a FIFO queue.
import java.util.List;
import java.util.Set;
import java.util.ArrayList;
import java.util.HashSet;
public class Anagrams{
public static void main(String[] args)
{
String inpString = "abcd";
Set<String> combs = getAllCombs(inpString);
for(String comb : combs)
{
System.out.println(comb);
}
}
private static Set<String> getAllCombs(String inpString)
{
Set<String> combs = new HashSet<String>();
if( inpString == null | inpString.isEmpty())
return combs;
combs.add(inpString.substring(0,1));
Set<String> tempCombs = new HashSet<String>();
for(char a : inpString.substring(1).toCharArray())
{
tempCombs.clear();
tempCombs.addAll(combs);
combs.clear();
for(String comb : tempCombs)
{
combs.addAll(getCombs(comb,a));
}
}
return combs;
}
private static Set<String> getCombs(String comb, char a) {
Set<String> combs = new HashSet<String>();
for(int i = 0 ; i <= comb.length(); i++)
{
String temp = comb.substring(0, i) + a + comb.substring(i);
combs.add(temp);
//System.out.println(temp);
}
return combs;
}
}
Just posting my approach to the problem:
import java.util.ArrayDeque;
import java.util.Queue;
public class PermutationIterative {
public static void main(String[] args) {
permutationIterative("abcd");
}
private static void permutationIterative(String str) {
Queue<String> currentQueue = null;
int charNumber = 1;
for (char c : str.toCharArray()) {
if (currentQueue == null) {
currentQueue = new ArrayDeque<>(1);
currentQueue.add(String.valueOf(c));
} else {
int currentQueueSize = currentQueue.size();
int numElements = currentQueueSize * charNumber;
Queue<String> nextQueue = new ArrayDeque<>(numElements);
for (int i = 0; i < currentQueueSize; i++) {
String tempString = currentQueue.remove();
for (int j = 0; j < charNumber; j++) {
int n = tempString.length();
nextQueue.add(tempString.substring(0, j) + c + tempString.substring(j, n));
}
}
currentQueue = nextQueue;
}
charNumber++;
}
System.out.println(currentQueue);
}
}
package vishal villa;
import java.util.Scanner;
public class Permutation {
static void result( String st, String ans)
{
if(st.length() == 0)
System.out.println(ans +" ");
for(int i = 0; i<st.length(); i++)
{
char ch = st.charAt(i);
String r = st.substring(0, i) + st.substring(i + 1);
result(r, ans + ch);
}
}
public static void main(String[] args)
{
Scanner Sc = new Scanner(System.in);
System.out.println("enter the string");
String st = Sc.nextLine();
Permutation p = new Permutation();
p.result(st,"" );
}
}
// Java program to print all permutations of a
// given string.
public class Permutation
{
public static void main(String[] args)
{
String str = "ABC";
int n = str.length();
Permutation permutation = new Permutation();
permutation.permute(str, 0, n-1);
}
/**
* permutation function
* #param str string to calculate permutation for
* #param s starting index
* #param e end index
*/
private void permute(String str, int s, int e)
{
if (s == e)
System.out.println(str);
else
{
for (int i = s; i <= s; i++)
{
str = swap(str,l,i);
permute(str, s+1, e);
str = swap(str,l,i);
}
}
}
/**
* Swap Characters at position
* #param a string value
* #param i position 1
* #param j position 2
* #return swapped string
*/
public String swap(String a, int i, int j)
{
char temp;
char[] charArray = a.toCharArray();
temp = charArray[i] ;
charArray[i] = charArray[j];
charArray[j] = temp;
return String.valueOf(charArray);
}
}

How to count frequency of characters in a string?

I need to write some kind of loop that can count the frequency of each letter in a string.
For example: "aasjjikkk" would count 2 'a', 1 's', 2 'j', 1 'i', 3 'k'. Ultimately id like these to end up in a map with the character as the key and the count as the value. Any good idea how to do this?
You can use a java Map and map a char to an int. You can then iterate over the characters in the string and check if they have been added to the map, if they have, you can then increment its value.
For example:
Map<Character, Integer> map = new HashMap<Character, Integer>();
String s = "aasjjikkk";
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
Integer val = map.get(c);
if (val != null) {
map.put(c, val + 1);
}
else {
map.put(c, 1);
}
}
At the end you will have a count of all the characters you encountered and you can extract their frequencies from that.
Alternatively, you can use Bozho's solution of using a Multiset and counting the total occurences.
Using the stream API as of JDK-8:
Map<Character, Long> frequency =
str.chars()
.mapToObj(c -> (char)c)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
or if you want the keys as Integers:
Map<Character, Integer> frequency =
str.chars()
.mapToObj(c -> (char)c)
.collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(c -> 1)));
Another variant:
Map<Character, Integer> frequency =
str.chars()
.mapToObj(c -> (char)c)
.collect(Collectors.toMap(Function.identity(), c -> 1, Math::addExact));
A concise way to do this is:
Map<Character,Integer> frequencies = new HashMap<>();
for (char ch : input.toCharArray())
frequencies.put(ch, frequencies.getOrDefault(ch, 0) + 1);
We use a for-each to loop through every character. The frequencies.getOrDefault() gets value if key is present or returns(as default) its second argument.
You can use a Multiset (from guava). It will give you the count for each object. For example:
Multiset<Character> chars = HashMultiset.create();
for (int i = 0; i < string.length(); i++) {
chars.add(string.charAt(i));
}
Then for each character you can call chars.count('a') and it returns the number of occurrences
Here is another solution, dodgy as it may be.
public char getNumChar(String s) {
char[] c = s.toCharArray();
String alphabet = "abcdefghijklmnopqrstuvwxyz";
int[] countArray = new int[26];
for (char x : c) {
for (int i = 0; i < alphabet.length(); i++) {
if (alphabet.charAt(i) == x) {
countArray[i]++;
}
}
}
java.util.HashMap<Integer, Character> countList = new java.util.HashMap<Integer, Character>();
for (int i = 0; i < 26; i++) {
countList.put(countArray[i], alphabet.charAt(i));
}
java.util.Arrays.sort(countArray);
int max = countArray[25];
return countList.get(max);
}
Since there was no Java 8 solution, thought of posting one. Also, this solution is much neater, readable and concise than some of the other solutions mentioned here.
String string = "aasjjikkk";
Map<Character, Long> characterFrequency = string.chars() // creates an IntStream
.mapToObj(c -> (char) c) // converts the IntStream to Stream<Character>
.collect(Collectors.groupingBy(c -> c, Collectors.counting())); // creates a
// Map<Character, Long>
// where the Long is
// the frequency
Well, two ways come to mind and it depends on your preference:
Sort the array by characters. Then, counting each character becomes trivial. But you will have to make a copy of the array first.
Create another integer array of size 26 (say freq) and str is the array of characters.
for(int i = 0; i < str.length; i ++)
freq[str[i] - 'a'] ++; //Assuming all characters are in lower case
So the number of 'a' 's will be stored at freq[0] and the number of 'z' 's will be at freq[25]
Here is a solution:
Define your own Pair:
public class Pair
{
private char letter;
private int count;
public Pair(char letter, int count)
{
this.letter = letter;
this.count= count;
}
public char getLetter(){return key;}
public int getCount(){return count;}
}
Then you could do:
public static Pair countCharFreq(String s)
{
String temp = s;
java.util.List<Pair> list = new java.util.ArrayList<Pair>();
while(temp.length() != 0)
{
list.add(new Pair(temp.charAt(0), countOccurrences(temp, temp.charAt(0))));
temp.replaceAll("[" + temp.charAt(0) +"]","");
}
}
public static int countOccurrences(String s, char c)
{
int count = 0;
for(int i = 0; i < s.length(); i++)
{
if(s.charAt(i) == c) count++;
}
return count;
}
String s = "aaaabbbbcccddddd";
Map<Character, Integer> map = new HashMap<>();
Using one line in Java8
s.chars().forEach(e->map.put((char)e, map.getOrDefault((char)e, 0) + 1));
You can use a CharAdapter and a CharBag from Eclipse Collections and avoid boxing to Character and Integer.
CharBag bag = Strings.asChars("aasjjikkk").toBag();
Assert.assertEquals(2, bag.occurrencesOf('a'));
Assert.assertEquals(1, bag.occurrencesOf('s'));
Assert.assertEquals(2, bag.occurrencesOf('j'));
Assert.assertEquals(1, bag.occurrencesOf('i'));
Assert.assertEquals(3, bag.occurrencesOf('k'));
Note: I am a committer for Eclipse Collections.
There is one more option and it looks quite nice.
Since java 8 there is new method merge java doc
public static void main(String[] args) {
String s = "aaabbbcca";
Map<Character, Integer> freqMap = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
Character c = s.charAt(i);
freqMap.merge(c, 1, (a, b) -> a + b);
}
freqMap.forEach((k, v) -> System.out.println(k + " and " + v));
}
Or even cleaner with ForEach
for (Character c : s.toCharArray()) {
freqMapSecond.merge(c, 1, Integer::sum);
}
package com.rishi.zava;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class ZipString {
public static void main(String arg[]) {
String input = "aaaajjjgggtttssvvkkllaaiiikk";
int len = input.length();
Map<Character, Integer> zip = new HashMap<Character, Integer>();
for (int j = 0; len > j; j++) {
int count = 0;
for (int i = 0; len > i; i++) {
if (input.charAt(j) == input.charAt(i)) {
count++;
}
}
zip.put(input.charAt(j), count);
}
StringBuffer myValue = new StringBuffer();
String myMapKeyValue = "";
for (Entry<Character, Integer> entry : zip.entrySet()) {
myMapKeyValue = Character.toString(entry.getKey()).concat(
Integer.toString(entry.getValue()));
myValue.append(myMapKeyValue);
}
System.out.println(myValue);
}
}
Input = aaaajjjgggtttssvvkkllaaiiikk
Output = a6s2t3v2g3i3j3k4l2
If this does not need to be super-fast just create an array of integers, one integer for each letter (only alphabetic so 2*26 integers? or any binary data possible?). go through the string one char at a time, get the index of the responsible integer (e.g. if you only have alphabetic chars you can have 'A' be at index 0 and get that index by subtracting any 'A' to 'Z' by 'A' just as an example of how you can get reasonably fast indices) and increment the value in that index.
There are various micro-optimizations to make this faster (if necessary).
You can use a Hashtable with each character as the key and the total count becomes the value.
Hashtable<Character,Integer> table = new Hashtable<Character,Integer>();
String str = "aasjjikkk";
for( c in str ) {
if( table.get(c) == null )
table.put(c,1);
else
table.put(c,table.get(c) + 1);
}
for( elem in table ) {
println "elem:" + elem;
}
This is similar to xunil154's answer, except that a string is made a char array and a linked hashmap is used to maintain the insertion order of the characters.
String text = "aasjjikkk";
char[] charArray = text.toCharArray();
Map<Character, Integer> freqList = new LinkedHashMap<Character, Integer>();
for(char key : charArray) {
if(freqList.containsKey(key)) {
freqList.put(key, freqList.get(key) + 1);
} else
freqList.put(key, 1);
}
import java.util.*;
class Charfrequency
{
public static void main(String a[]){
Scanner sc=new Scanner(System.in);
System.out.println("Enter Your String :");
String s1=sc.nextLine();
int count,j=1;
char var='a';
char ch[]=s1.toCharArray();
while(j<=26)
{
count=0;
for(int i=0; i<s1.length(); i++)
{
if(ch[i]==var || ch[i]==var-32)
{
count++;
}
}
if(count>0){
System.out.println("Frequency of "+var+" is "+count);
}
var++;
j++;
}
}
}
The shorted possible code using a HashMap. (With no forceful line saves)
private static Map<Character, Integer> findCharacterFrequency(String str) {
Map<Character, Integer> map = new HashMap<>();
for (char ch : str.toCharArray()) {
/* Using getOrDefault(), since Java1.8 */
map.put(ch, map.getOrDefault(ch, 0) + 1);
}
return map;
}
Please try the given code below, hope it will helpful to you,
import java.util.Scanner;
class String55 {
public static int frequency(String s1,String s2)
{
int count=0;
char ch[]=s1.toCharArray();
char ch1[]=s2.toCharArray();
for (int i=0;i<ch.length-1; i++)
{
int k=i;
int j1=i+1;
int j=0;
int j11=j;
int j2=j+1;
{
while(k<ch.length && j11<ch1.length && ch[k]==ch1[j11])
{
k++;
j11++;
}
int l=k+j1;
int m=j11+j2;
if( l== m)
{
count=1;
count++;
}
}
}
return count;
}
public static void main (String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("enter the pattern");
String s1=sc.next();
System.out.println("enter the String");
String s2=sc.next();
int res=frequency(s1, s2);
System.out.println("FREQUENCY==" +res);
}
}
SAMPLE OUTPUT:
enter the pattern
man
enter the String
dhimanman
FREQUENCY==2
Thank-you.Happy coding.
package com.dipu.string;
import java.util.HashMap;
import java.util.Map;
public class RepetativeCharInString {
public static void main(String[] args) {
String data = "aaabbbcccdddffffrss";
char[] charArray = data.toCharArray();
Map<Character, Integer> map = new HashMap<>();
for (char c : charArray) {
if (map.containsKey(c)) {
map.put(c, map.get(c) + 1);
} else {
map.put(c, 1);
}
}
System.out.println(map);
}
}
*import java.util.ArrayList;
import java.util.Collections;
public class Freq {
public static void main(String[] args) {
// TODO Auto-generated method stub
String temp="zsaaqaaaaaaaabbbbbcc";
List<String> temp1= new ArrayList<String> ();
ArrayList<Integer>freq=new ArrayList<Integer>();
for(int i=0;i<temp.length()-1;i++)
{
temp1.add(Character.toString(temp.charAt(i)));
}
Set<String> uniqset=new HashSet<String>(temp1);
for(String s:uniqset)
{
freq.add(Collections.frequency(temp1, s));
System.out.println(s+" -->>"+Collections.frequency(temp1, s));
}
}
}
------Output-------
a -->>10
b -->>5
c -->>1
q -->>1
s -->>1
z -->>1
Use collections frequency method to count frequency of char*
Uffh. Don't you think this is the simplest solution?
char inputChar = '|';
int freq = "|fd|fdfd|f dfd|fd".replaceAll("[^" + inputChar +"]", "").length();
System.out.println("freq " + freq);
We can use frequency method of Collections class for this.
Split the string into string array. Use HashSet to remove duplicates and check frequency of each object in HashSet using frequency method of Collections
void usingCollections(){
String input = "cuttack";
String [] stringArray = input.split("");
Set<String> s = new HashSet(Arrays.asList(stringArray));
for(String abc : s){
System.out.println (abc + ":"+Collections.frequency(Arrays.asList(stringArray),abc));
}
}
This is more Effective way to count frequency of characters in a string
public class demo {
public static void main(String[] args) {
String s = "babdcwertyuiuygf";
Map<Character, Integer> map = new TreeMap<>();
s.chars().forEach(e->map.put((char)e, map.getOrDefault((char)e, 0) + 1));
StringBuffer myValue = new StringBuffer();
String myMapKeyValue = "";
for (Map.Entry<Character, Integer> entry : map.entrySet()) {
myMapKeyValue = Character.toString(entry.getKey()).concat(
Integer.toString(entry.getValue()));
myValue.append(myMapKeyValue);
}
System.out.println(myValue);
}
}
Another way using map merge method
Map<Character, Integer> map = new HashMap<>();
String s = "aasjjikkk";
for (int i = 0; i < s.length(); i++) {
map.merge(s.charAt(i), 1, (l, r) -> l + r);
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
public class FrequenceyOfCharacters {
public static void main(String[] args) {
System.out.println("Please enter the string to count each character frequencey: ");
Scanner sc=new Scanner(System.in);
String s =sc.nextLine();
String input = s.replaceAll("\\s",""); // To remove space.
frequenceyCount(input);
}
private static void frequenceyCount(String input) {
Map<Character,Integer> hashCount=new HashMap<>();
Character c;
for(int i=0; i<input.length();i++)
{
c =input.charAt(i);
if(hashCount.get(c)!=null){
hashCount.put(c, hashCount.get(c)+1);
}else{
hashCount.put(c, 1);
}
}
Iterator it = hashCount.entrySet().iterator();
System.out.println("char : frequency");
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
System.out.println(pairs.getKey() + " : " + pairs.getValue());
it.remove();
}
}
}
import java.io.FileInputStream;
import java.util.HashSet;
import java.util.Iterator;
public class CountFrequencyOfCharater {
public static void main(String args[]) throws Exception
{
HashSet hs=new HashSet();
String str="hey how are you?";
char arr[]=new char[str.length()];
for(int i=0;i<str.length();i++)
{
arr[i]=str.charAt(i);
}
for(int j=0;j<str.length();j++)
{
int c=0;
for(int k=0;k<str.length();k++)
{
if(arr[j]==arr[k])
c++;
}
hs.add(arr[j]+"="+c+",");
}
Iterator it=hs.iterator();
while(it.hasNext())
{
System.out.print(it.next());
}
}
}
#From C language
#include<stdio.h>`
#include <string.h>`
int main()
{
char s[1000];
int i,j,k,count=0,n;
printf("Enter the string : ");
gets(s);
for(j=0;s[j];j++);
n=j;
printf(" frequency count character in string:\n");
for(i=0;i<n;i++)
{
count=1;
if(s[i])
{
for(j=i+1;j<n;j++)
{
if(s[i]==s[j])
{
count++;
s[j]='\0';
}
}
printf(" '%c' = %d \n",s[i],count);
}
}
return 0;
}

Removing duplicates from a String in Java

I am trying to iterate through a string in order to remove the duplicates characters.
For example the String aabbccdef should become abcdef
and the String abcdabcd should become abcd
Here is what I have so far:
public class test {
public static void main(String[] args) {
String input = new String("abbc");
String output = new String();
for (int i = 0; i < input.length(); i++) {
for (int j = 0; j < output.length(); j++) {
if (input.charAt(i) != output.charAt(j)) {
output = output + input.charAt(i);
}
}
}
System.out.println(output);
}
}
What is the best way to do this?
Convert the string to an array of char, and store it in a LinkedHashSet. That will preserve your ordering, and remove duplicates. Something like:
String string = "aabbccdefatafaz";
char[] chars = string.toCharArray();
Set<Character> charSet = new LinkedHashSet<Character>();
for (char c : chars) {
charSet.add(c);
}
StringBuilder sb = new StringBuilder();
for (Character character : charSet) {
sb.append(character);
}
System.out.println(sb.toString());
Using Stream makes it easy.
noDuplicates = Arrays.asList(myString.split(""))
.stream()
.distinct()
.collect(Collectors.joining());
Here is some more documentation about Stream and all you can do with
it :
https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
The 'description' part is very instructive about the benefits of Streams.
Try this simple solution:
public String removeDuplicates(String input){
String result = "";
for (int i = 0; i < input.length(); i++) {
if(!result.contains(String.valueOf(input.charAt(i)))) {
result += String.valueOf(input.charAt(i));
}
}
return result;
}
I would use the help of LinkedHashSet. Removes dups (as we are using a Set, maintains the order as we are using linked list impl). This is kind of a dirty solution. there might be even a better way.
String s="aabbccdef";
Set<Character> set=new LinkedHashSet<Character>();
for(char c:s.toCharArray())
{
set.add(Character.valueOf(c));
}
Create a StringWriter. Run through the original string using charAt(i) in a for loop. Maintain a variable of char type keeping the last charAt value. If you iterate and the charAt value equals what is stored in that variable, don't add to the StringWriter. Finally, use the StringWriter.toString() method and get a string, and do what you need with it.
Here is an improvement to the answer by Dave.
It uses HashSet instead of the slightly more costly LinkedHashSet, and reuses the chars buffer for the result, eliminating the need for a StringBuilder.
String string = "aabbccdefatafaz";
char[] chars = string.toCharArray();
Set<Character> present = new HashSet<>();
int len = 0;
for (char c : chars)
if (present.add(c))
chars[len++] = c;
System.out.println(new String(chars, 0, len)); // abcdeftz
Java 8 has a new String.chars() method which returns a stream of characters in the String. You can use stream operations to filter out the duplicate characters like so:
String out = in.chars()
.mapToObj(c -> Character.valueOf((char) c)) // bit messy as chars() returns an IntStream, not a CharStream (which doesn't exist)
.distinct()
.map(Object::toString)
.collect(Collectors.joining(""));
String input = "AAAB";
String output = "";
for (int index = 0; index < input.length(); index++) {
if (input.charAt(index % input.length()) != input
.charAt((index + 1) % input.length())) {
output += input.charAt(index);
}
}
System.out.println(output);
but you cant use it if the input has the same elements, or if its empty!
Code to remove the duplicate characters in a string without using any additional buffer. NOTE: One or two additional variables are fine. An extra array is not:
import java.util.*;
public class Main{
public static char[] removeDupes(char[] arr){
if (arr == null || arr.length < 2)
return arr;
int len = arr.length;
int tail = 1;
for(int x = 1; x < len; x++){
int y;
for(y = 0; y < tail; y++){
if (arr[x] == arr[y]) break;
}
if (y == tail){
arr[tail] = arr[x];
tail++;
}
}
return Arrays.copyOfRange(arr, 0, tail);
}
public static char[] bigArr(int len){
char[] arr = new char[len];
Random r = new Random();
String alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!##$%^&*()-=_+[]{}|;:',.<>/?`~";
for(int x = 0; x < len; x++){
arr[x] = alphabet.charAt(r.nextInt(alphabet.length()));
}
return arr;
}
public static void main(String args[]){
String result = new String(removeDupes(new char[]{'a', 'b', 'c', 'd', 'a'}));
assert "abcd".equals(result) : "abcda should return abcd but it returns: " + result;
result = new String(removeDupes(new char[]{'a', 'a', 'a', 'a'}));
assert "a".equals(result) : "aaaa should return a but it returns: " + result;
result = new String(removeDupes(new char[]{'a', 'b', 'c', 'a'}));
assert "abc".equals(result) : "abca should return abc but it returns: " + result;
result = new String(removeDupes(new char[]{'a', 'a', 'b', 'b'}));
assert "ab".equals(result) : "aabb should return ab but it returns: " + result;
result = new String(removeDupes(new char[]{'a'}));
assert "a".equals(result) : "a should return a but it returns: " + result;
result = new String(removeDupes(new char[]{'a', 'b', 'b', 'a'}));
assert "ab".equals(result) : "abba should return ab but it returns: " + result;
char[] arr = bigArr(5000000);
long startTime = System.nanoTime();
System.out.println("2: " + new String(removeDupes(arr)));
long endTime = System.nanoTime();
long duration = (endTime - startTime);
System.out.println("Program took: " + duration + " nanoseconds");
System.out.println("Program took: " + duration/1000000000 + " seconds");
}
}
How to read and talk about the above code:
The method called removeDupes takes an array of primitive char called arr.
arr is returned as an array of primitive characters "by value". The arr passed in is garbage collected at the end of Main's member method removeDupes.
The runtime complexity of this algorithm is O(n) or more specifically O(n+(small constant)) the constant being the unique characters in the entire array of primitive chars.
The copyOfRange does not increase runtime complexity significantly since it only copies a small constant number of items. The char array called arr is not stepped all the way through.
If you pass null into removeDupes, the method returns null.
If you pass an empty array of primitive chars or an array containing one value, that unmodified array is returned.
Method removeDupes goes about as fast as physically possible, fully utilizing the L1 and L2 cache, so Branch redirects are kept to a minimum.
A 2015 standard issue unburdened computer should be able to complete this method with an primitive char array containing 500 million characters between 15 and 25 seconds.
Explain how this code works:
The first part of the array passed in is used as the repository for the unique characters that are ultimately returned. At the beginning of the function the answer is: "the characters between 0 and 1" as between 0 and tail.
We define the variable y outside of the loop because we want to find the first location where the array index that we are looking at has been duplicated in our repository. When a duplicate is found, it breaks out and quits, the y==tail returns false and the repository is not contributed to.
when the index x that we are peeking at is not represented in our repository, then we pull that one and add it to the end of our repository at index tail and increment tail.
At the end, we return the array between the points 0 and tail, which should be smaller or equal to in length to the original array.
Talking points exercise for coder interviews:
Will the program behave differently if you change the y++ to ++y? Why or why not.
Does the array copy at the end represent another 'N' pass through the entire array making runtime complexity O(n*n) instead of O(n) ? Why or why not.
Can you replace the double equals comparing primitive characters with a .equals? Why or why not?
Can this method be changed in order to do the replacements "by reference" instead of as it is now, "by value"? Why or why not?
Can you increase the efficiency of this algorithm by sorting the repository of unique values at the beginning of 'arr'? Under which circumstances would it be more efficient?
public class RemoveRepeated4rmString {
public static void main(String[] args) {
String s = "harikrishna";
String s2 = "";
for (int i = 0; i < s.length(); i++) {
Boolean found = false;
for (int j = 0; j < s2.length(); j++) {
if (s.charAt(i) == s2.charAt(j)) {
found = true;
break; //don't need to iterate further
}
}
if (found == false) {
s2 = s2.concat(String.valueOf(s.charAt(i)));
}
}
System.out.println(s2);
}
}
public static void main(String a[]){
String name="Madan";
System.out.println(name);
StringBuilder sb=new StringBuilder(name);
for(int i=0;i<name.length();i++){
for(int j=i+1;j<name.length();j++){
if(name.charAt(i)==name.charAt(j)){
sb.deleteCharAt(j);
}
}
}
System.out.println("After deletion :"+sb+"");
}
import java.util.Scanner;
public class dublicate {
public static void main(String... a) {
System.out.print("Enter the String");
Scanner Sc = new Scanner(System.in);
String st=Sc.nextLine();
StringBuilder sb=new StringBuilder();
boolean [] bc=new boolean[256];
for(int i=0;i<st.length();i++)
{
int index=st.charAt(i);
if(bc[index]==false)
{
sb.append(st.charAt(i));
bc[index]=true;
}
}
System.out.print(sb.toString());
}
}
To me it looks like everyone is trying way too hard to accomplish this task. All we are concerned about is that it copies 1 copy of each letter if it repeats. Then because we are only concerned if those characters repeat one after the other the nested loops become arbitrary as you can just simply compare position n to position n + 1. Then because this only copies things down when they're different, to solve for the last character you can either append white space to the end of the original string, or just get it to copy the last character of the string to your result.
String removeDuplicate(String s){
String result = "";
for (int i = 0; i < s.length(); i++){
if (i + 1 < s.length() && s.charAt(i) != s.charAt(i+1)){
result = result + s.charAt(i);
}
if (i + 1 == s.length()){
result = result + s.charAt(i);
}
}
return result;
}
String str1[] ="Hi helloo helloo oooo this".split(" ");
Set<String> charSet = new LinkedHashSet<String>();
for (String c: str1)
{
charSet.add(c);
}
StringBuilder sb = new StringBuilder();
for (String character : charSet)
{
sb.append(character);
}
System.out.println(sb.toString());
I think working this way would be more easy,,,
Just pass a string to this function and the job is done :) .
private static void removeduplicate(String name)
{ char[] arr = name.toCharArray();
StringBuffer modified =new StringBuffer();
for(char a:arr)
{
if(!modified.contains(Character.toString(a)))
{
modified=modified.append(Character.toString(a)) ;
}
}
System.out.println(modified);
}
public class RemoveDuplicatesFromStingsMethod1UsingLoops {
public static void main(String[] args) {
String input = new String("aaabbbcccddd");
String output = "";
for (int i = 0; i < input.length(); i++) {
if (!output.contains(String.valueOf(input.charAt(i)))) {
output += String.valueOf(input.charAt(i));
}
}
System.out.println(output);
}
}
output: abcd
You can't. You can create a new String that has duplicates removed. Why aren't you using StringBuilder (or StringBuffer, presumably)?
You can run through the string and store the unique characters in a char[] array, keeping track of how many unique characters you've seen. Then you can create a new String using the String(char[], int, int) constructor.
Also, the problem is a little ambiguous—does “duplicates” mean adjacent repetitions? (In other words, what should happen with abcab?)
Oldschool way (as we wrote such a tasks in Apple ][ Basic, adapted to Java):
int i,j;
StringBuffer str=new StringBuffer();
Scanner in = new Scanner(System.in);
System.out.print("Enter string: ");
str.append(in.nextLine());
for (i=0;i<str.length()-1;i++){
for (j=i+1;j<str.length();j++){
if (str.charAt(i)==str.charAt(j))
str.deleteCharAt(j);
}
}
System.out.println("Removed non-unique symbols: " + str);
Here is another logic I'd like to share. You start comparing from midway of the string length and go backward.
Test with:
input = "azxxzy";
output = "ay";
String removeMidway(String input){
cnt = cnt+1;
StringBuilder str = new StringBuilder(input);
int midlen = str.length()/2;
for(int i=midlen-1;i>0;i--){
for(int j=midlen;j<str.length()-1;j++){
if(str.charAt(i)==str.charAt(j)){
str.delete(i, j+1);
midlen = str.length()/2;
System.out.println("i="+i+",j="+j+ ",len="+ str.length() + ",midlen=" + midlen+ ", after deleted = " + str);
}
}
}
return str.toString();
}
Another possible solution, in case a string is an ASCII string, is to maintain an array of 256 boolean elements to denote ASCII character appearance in a string. If a character appeared for the first time, we keep it and append to the result. Otherwise just skip it.
public String removeDuplicates(String input) {
boolean[] chars = new boolean[256];
StringBuilder resultStringBuilder = new StringBuilder();
for (Character c : input.toCharArray()) {
if (!chars[c]) {
resultStringBuilder.append(c);
chars[c] = true;
}
}
return resultStringBuilder.toString();
}
This approach will also work with Unicode string. You just need to increase chars size.
Solution using JDK7:
public static String removeDuplicateChars(final String str){
if (str == null || str.isEmpty()){
return str;
}
final char[] chArray = str.toCharArray();
final Set<Character> set = new LinkedHashSet<>();
for (char c : chArray) {
set.add(c);
}
final StringBuilder sb = new StringBuilder();
for (Character character : set) {
sb.append(character);
}
return sb.toString();
}
String str = "eamparuthik#gmail.com";
char[] c = str.toCharArray();
String op = "";
for(int i=0; i<=c.length-1; i++){
if(!op.contains(c[i] + ""))
op = op + c[i];
}
System.out.println(op);
public static String removeDuplicateChar(String str){
char charArray[] = str.toCharArray();
StringBuilder stringBuilder= new StringBuilder();
for(int i=0;i<charArray.length;i++){
int index = stringBuilder.toString().indexOf(charArray[i]);
if(index <= -1){
stringBuilder.append(charArray[i]);
}
}
return stringBuilder.toString();
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class RemoveDuplicacy
{
public static void main(String args[])throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter any word : ");
String s = br.readLine();
int l = s.length();
char ch;
String ans=" ";
for(int i=0; i<l; i++)
{
ch = s.charAt(i);
if(ch!=' ')
ans = ans + ch;
s = s.replace(ch,' '); //Replacing all occurrence of the current character by a space
}
System.out.println("Word after removing duplicate characters : " + ans);
}
}
public static void main(String[] args) {
int i,j;
StringBuffer str=new StringBuffer();
Scanner in = new Scanner(System.in);
System.out.print("Enter string: ");
str.append(in.nextLine());
for (i=0;i<str.length()-1;i++)
{
for (j=1;j<str.length();j++)
{
if (str.charAt(i)==str.charAt(j))
str.deleteCharAt(j);
}
}
System.out.println("Removed String: " + str);
}
This is improvement on solution suggested by #Dave. Here, I am implementing in single loop only.
Let's reuse the return of set.add(T item) method and add it simultaneously in StringBuffer if add is successfull
This is just O(n). No need to make a loop again.
String string = "aabbccdefatafaz";
char[] chars = string.toCharArray();
StringBuilder sb = new StringBuilder();
Set<Character> charSet = new LinkedHashSet<Character>();
for (char c : chars) {
if(charSet.add(c) ){
sb.append(c);
}
}
System.out.println(sb.toString()); // abcdeftz
Simple solution is to iterate through the given string and put each unique character into another string(in this case, a variable result ) if this string doesn't contain that particular character.Finally return result string as output.
Below is working and tested code snippet for removing duplicate characters from the given string which has O(n) time complexity .
private static String removeDuplicate(String s) {
String result="";
for (int i=0 ;i<s.length();i++) {
char ch = s.charAt(i);
if (!result.contains(""+ch)) {
result+=""+ch;
}
}
return result;
}
If the input is madam then output will be mad.
If the input is anagram then output will be angrm
Hope this helps.
Thanks
For the simplicity of the code- I have taken hardcore input, one can take input by using Scanner class also
public class KillDuplicateCharInString {
public static void main(String args[]) {
String str= "aaaabccdde ";
char arr[]= str.toCharArray();
int n = arr.length;
String finalStr="";
for(int i=0;i<n;i++) {
if(i==n-1){
finalStr+=arr[i];
break;
}
if(arr[i]==arr[i+1]) {
continue;
}
else {
finalStr+=arr[i];
}
}
System.out.println(finalStr);
}
}
public static void main (String[] args)
{
Scanner sc = new Scanner(System.in);
String s = sc.next();
String str = "";
char c;
for(int i = 0; i < s.length(); i++)
{
c = s.charAt(i);
str = str + c;
s = s.replace(c, ' ');
if(i == s.length() - 1)
{
System.out.println(str.replaceAll("\\s", ""));
}
}
}
package com.st.removeduplicate;
public class RemoveDuplicate {
public static void main(String[] args) {
String str1="shushil",str2="";
for(int i=0; i<=str1.length()-1;i++) {
int count=0;
for(int j=0;j<=i;j++) {
if(str1.charAt(i)==str1.charAt(j))
count++;
if(count >1)
break;
}
if(count==1)
str2=str2+str1.charAt(i);
}
System.out.println(str2);
}
}

function to remove duplicate characters in a string

The following code is trying to remove any duplicate characters in a string. I'm not sure if the code is right. Can anybody help me work with the code (i.e whats actually happening when there is a match in characters)?
public static void removeDuplicates(char[] str) {
if (str == null) return;
int len = str.length;
if (len < 2) return;
int tail = 1;
for (int i = 1; i < len; ++i) {
int j;
for (j = 0; j < tail; ++j) {
if (str[i] == str[j]) break;
}
if (j == tail) {
str[tail] = str[i];
++tail;
}
}
str[tail] = 0;
}
The function looks fine to me. I've written inline comments. Hope it helps:
// function takes a char array as input.
// modifies it to remove duplicates and adds a 0 to mark the end
// of the unique chars in the array.
public static void removeDuplicates(char[] str) {
if (str == null) return; // if the array does not exist..nothing to do return.
int len = str.length; // get the array length.
if (len < 2) return; // if its less than 2..can't have duplicates..return.
int tail = 1; // number of unique char in the array.
// start at 2nd char and go till the end of the array.
for (int i = 1; i < len; ++i) {
int j;
// for every char in outer loop check if that char is already seen.
// char in [0,tail) are all unique.
for (j = 0; j < tail; ++j) {
if (str[i] == str[j]) break; // break if we find duplicate.
}
// if j reachs tail..we did not break, which implies this char at pos i
// is not a duplicate. So we need to add it our "unique char list"
// we add it to the end, that is at pos tail.
if (j == tail) {
str[tail] = str[i]; // add
++tail; // increment tail...[0,tail) is still "unique char list"
}
}
str[tail] = 0; // add a 0 at the end to mark the end of the unique char.
}
Your code is, I'm sorry to say, very C-like.
A Java String is not a char[]. You say you want to remove duplicates from a String, but you take a char[] instead.
Is this char[] \0-terminated? Doesn't look like it because you take the whole .length of the array. But then your algorithm tries to \0-terminate a portion of the array. What happens if the arrays contains no duplicates?
Well, as it is written, your code actually throws an ArrayIndexOutOfBoundsException on the last line! There is no room for the \0 because all slots are used up!
You can add a check not to add \0 in this exceptional case, but then how are you planning to use this code anyway? Are you planning to have a strlen-like function to find the first \0 in the array? And what happens if there isn't any? (due to all-unique exceptional case above?).
What happens if the original String/char[] contains a \0? (which is perfectly legal in Java, by the way, see JLS 10.9 An Array of Characters is Not a String)
The result will be a mess, and all because you want to do everything C-like, and in place without any additional buffer. Are you sure you really need to do this? Why not work with String, indexOf, lastIndexOf, replace, and all the higher-level API of String? Is it provably too slow, or do you only suspect that it is?
"Premature optimization is the root of all evils". I'm sorry but if you can't even understand what the original code does, then figuring out how it will fit in the bigger (and messier) system will be a nightmare.
My minimal suggestion is to do the following:
Make the function takes and returns a String, i.e. public static String removeDuplicates(String in)
Internally, works with char[] str = in.toCharArray();
Replace the last line by return new String(str, 0, tail);
This does use additional buffers, but at least the interface to the rest of the system is much cleaner.
Alternatively, you can use StringBuilder as such:
static String removeDuplicates(String s) {
StringBuilder noDupes = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
String si = s.substring(i, i + 1);
if (noDupes.indexOf(si) == -1) {
noDupes.append(si);
}
}
return noDupes.toString();
}
Note that this is essentially the same algorithm as what you had, but much cleaner and without as many little corner cases, etc.
Given the following question :
Write code to remove the duplicate characters in a string without
using any additional buffer. NOTE: One or two additional variables
are fine. An extra copy of the array is not.
Since one or two additional variables are fine but no buffer is allowed, you can simulate the behaviour of a hashmap by using an integer to store bits instead. This simple solution runs at O(n), which is faster than yours. Also, it isn't conceptually complicated and in-place :
public static void removeDuplicates(char[] str) {
int map = 0;
for (int i = 0; i < str.length; i++) {
if ((map & (1 << (str[i] - 'a'))) > 0) // duplicate detected
str[i] = 0;
else // add unique char as a bit '1' to the map
map |= 1 << (str[i] - 'a');
}
}
The drawback is that the duplicates (which are replaced with 0's) will not be placed at the end of the str[] array. However, this can easily be fixed by looping through the array one last time. Also, an integer has the capacity for only regular letters.
private static String removeDuplicateCharactersFromWord(String word) {
String result = new String("");
for (int i = 0; i < word.length(); i++) {
if (!result.contains("" + word.charAt(i))) {
result += "" + word.charAt(i);
}
}
return result;
}
This is my solution.
The algorithm is mainly the same as the one in the book "Cracking the code interview" where this exercise comes from, but I tried to improve it a bit and make the code more understandable:
public static void removeDuplicates(char[] str) {
// if string has less than 2 characters, it can't contain
// duplicate values, so there's nothing to do
if (str == null || str.length < 2) {
return;
}
// variable which indicates the end of the part of the string
// which is 'cleaned' (all duplicates removed)
int tail = 0;
for (int i = 0; i < str.length; i++) {
boolean found = false;
// check if character is already present in
// the part of the array before the current char
for (int j = 0; j < i; j++) {
if (str[j] == str[i]) {
found = true;
break;
}
}
// if char is already present
// skip this one and do not copy it
if (found) {
continue;
}
// copy the current char to the index
// after the last known unique char in the array
str[tail] = str[i];
tail++;
}
str[tail] = '\0';
}
One of the important requirements from the book is to do it in-place (as in my solution), which means that no additional data structure should be used as a helper while processing the string. This improves performance by not wasting memory unnecessarily.
char[] chars = s.toCharArray();
HashSet<Character> charz = new HashSet<Character>();
for(Character c : s.toCharArray() )
{
if(!charz.contains(c))
{
charz.add(c);
//System.out.print(c);
}
}
for(Character c : charz)
{
System.out.print(c);
}
public String removeDuplicateChar(String nonUniqueString) {
String uniqueString = "";
for (char currentChar : nonUniqueString.toCharArray()) {
if (!uniqueString.contains("" + currentChar)) {
uniqueString += currentChar;
}
}
return uniqueString;
}
public static void main (String [] args)
{
String s = "aabbbeeddsfre";//sample string
String temp2="";//string with no duplicates
HashMap<Integer,Character> tc = new HashMap<Integer,Character>();//create a hashmap to store the char's
char [] charArray = s.toCharArray();
for (Character c : charArray)//for each char
{
if (!tc.containsValue(c))//if the char is not already in the hashmap
{
temp2=temp2+c.toString();//add the char to the output string
tc.put(c.hashCode(),c);//and add the char to the hashmap
}
}
System.out.println(temp2);//final string
}
instead of HashMap I think we can use Set too.
I understand that this is a Java question, but since I have a nice solution which could inspire someone to convert this into Java, by all means. Also I like answers where multiple language submissions are available to common problems.
So here is a Python solution which is O(n) and also supports the whole ASCII range. Of course it does not treat 'a' and 'A' as the same:
I am using 8 x 32 bits as the hashmap:
Also input is a string array using dedup(list('some string'))
def dedup(str):
map = [0,0,0,0,0,0,0,0]
for i in range(len(str)):
ascii = ord(str[i])
slot = ascii / 32
bit = ascii % 32
bitOn = map[slot] & (1 << bit)
if bitOn:
str[i] = ''
else:
map[slot] |= 1 << bit
return ''.join(str)
also a more pythonian way to do this is by using a set:
def dedup(s):
return ''.join(list(set(s)))
Substringing method. Concatenation is done with .concat() to avoid allocation additional memory for left hand and right hand of +.
Note: This removes even duplicate spaces.
private static String withoutDuplicatesSubstringing(String s){
for(int i = 0; i < s.length(); i++){
String sub = s.substring(i+1);
int index = -1;
while((index = sub.toLowerCase().indexOf(Character.toLowerCase(s.charAt(i)))) > -1 && !sub.isEmpty()){
sub = sub.substring(0, index).concat(sub.substring(index+1, sub.length()));
}
s = s.substring(0, i+1).concat(sub);
}
return s;
}
Test case:
String testCase1 = "nanananaa! baaaaatmaan! batman!";
Output:
na! btm
Question: Remove Duplicate characters in a string
Method 1 :(Python)
import collections
a = "GiniGinaProtijayi"
aa = collections.OrderedDict().fromkeys(a)
print(''.join(aa))
Method 2 :(Python)
a = "GiniGinaProtijayi"
list = []
aa = [ list.append(ch) for ch in a if ch not in list]
print( ''.join(list))
IN Java:
class test2{
public static void main(String[] args) {
String a = "GiniGinaProtijayi";
List<Character> list = new ArrayList<>();
for(int i = 0 ; i < a.length() ;i++) {
char ch = a.charAt(i);
if( list.size() == 0 ) {list.add(ch);}
if(!list.contains(ch)) {list.add(ch) ;}
}//for
StringBuffer sbr = new StringBuffer();
for( char ch : list) {sbr.append(ch);}
System.out.println(sbr);
}//main
}//end
This would be much easier if you just looped through the array and added all new characters to a list, then retruned that list.
With this approach, you need to reshuffle the array as you step through it and eventually redimension it to the appropriate size in the end.
String s = "Javajk";
List<Character> charz = new ArrayList<Character>();
for (Character c : s.toCharArray()) {
if (!(charz.contains(Character.toUpperCase(c)) || charz
.contains(Character.toLowerCase(c)))) {
charz.add(c);
}
}
ListIterator litr = charz.listIterator();
while (litr.hasNext()) {
Object element = litr.next();
System.err.println(":" + element);
} }
this will remove the duplicate if the character present in both the case.
public class RemoveDuplicateInString {
public static void main(String[] args) {
String s = "ABCDDCA";
RemoveDuplicateInString rs = new RemoveDuplicateInString();
System.out.println(rs.removeDuplicate(s));
}
public String removeDuplicate(String s) {
String retn = null;
boolean[] b = new boolean[256];
char[] ch = s.toCharArray();
for (int i = 0; i < ch.length; i++) {
if (b[ch[i]]) {
ch[i]=' ';
}
else {
b[ch[i]] = true;
}
}
retn = new String(ch);
return retn;
}
}
/* program to remove the duplicate character in string */
/* Author senthilkumar M*/
char *dup_remove(char *str)
{
int i = 0, j = 0, l = strlen(str);
int flag = 0, result = 0;
for(i = 0; i < l; i++) {
result = str[i] - 'a';
if(flag & (1 << result)) {
*/* if duplicate found remove & shift the array*/*
for(j = i; j < l; j++) {
str[j] = str[j+1];
}
i--;
l--; /* duplicates removed so string length reduced by 1 character*/
continue;
}
flag |= (1 << result);
}
return str;
}
public class RemoveCharsFromString {
static String testcase1 = "No, I am going to Noida";
static String testcase2 = "goings";
public static void main(String args[])throws StringIndexOutOfBoundsException{
RemoveCharsFromString testInstance= new RemoveCharsFromString();
String result = testInstance.remove(testcase1,testcase2);
System.out.println(result);
}
//write your code here
public String remove(String str, String str1)throws StringIndexOutOfBoundsException
{ String result=null;
if (str == null)
return "";
try
{
for (int i = 0; i < str1.length (); i++)
{
char ch1=str1.charAt(i);
for(int j=0;j<str.length();j++)
{
char ch = str.charAt (j);
if (ch == ch1)
{
String s4=String.valueOf(ch);
String s5= str.replaceAll(s4, "");
str=s5;
}
}
}
}
catch(Exception e)
{
}
result=str;
return result;
}
}
public static void main(String[] args) {
char[] str = { 'a', 'b', 'a','b','c','e','c' };
for (int i = 1; i < str.length; i++) {
for (int j = 0; j < i; j++) {
if (str[i] == str[j]) {
str[i] = ' ';
}
}
}
System.out.println(str);
}
An improved version for using bitmask to handle 256 chars:
public static void removeDuplicates3(char[] str)
{
long map[] = new long[] {0, 0, 0 ,0};
long one = 1;
for (int i = 0; i < str.length; i++)
{
long chBit = (one << (str[i]%64));
int n = (int) str[i]/64;
if ((map[n] & chBit ) > 0) // duplicate detected
str[i] = 0;
else // add unique char as a bit '1' to the map
map[n] |= chBit ;
}
// get rid of those '\0's
int wi = 1;
for (int i=1; i<str.length; i++)
{
if (str[i]!=0) str[wi++] = str[i];
}
// setting the rest as '\0'
for (;wi<str.length; wi++) str[wi] = 0;
}
Result: "##1!!ASDJasanwAaw.,;..][,[]==--0" ==> "#1!ASDJasnw.,;][=-0" (double quotes not included)
This function removes duplicate from string inline. I have used C# as a coding language and the duplicates are removed inline
public static void removeDuplicate(char[] inpStr)
{
if (inpStr == null) return;
if (inpStr.Length < 2) return;
for (int i = 0; i < inpStr.Length; ++i)
{
int j, k;
for (j = 1; j < inpStr.Length; j++)
{
if (inpStr[i] == inpStr[j] && i != j)
{
for (k = j; k < inpStr.Length - 1; k++)
{
inpStr[k] = inpStr[k + 1];
}
inpStr[k] = ' ';
}
}
}
Console.WriteLine(inpStr);
}
(Java) Avoiding usage of Map, List data structures:
private String getUniqueStr(String someStr) {
StringBuilder uniqueStr = new StringBuilder();
if(someStr != null) {
for(int i=0; i <someStr.length(); i++) {
if(uniqueStr.indexOf(String.valueOf(someStr.charAt(i))) == -1) {
uniqueStr.append(someStr.charAt(i));
}
}
}
return uniqueStr.toString();
}
package com.java.exercise;
public class RemoveCharacter {
/**
* #param args
*/
public static void main(String[] args) {
RemoveCharacter rem = new RemoveCharacter();
char[] ch=rem.GetDuplicates("JavavNNNNNNC".toCharArray());
char[] desiredString="JavavNNNNNNC".toCharArray();
System.out.println(rem.RemoveDuplicates(desiredString, ch));
}
char[] GetDuplicates(char[] input)
{
int ctr=0;
char[] charDupl=new char[20];
for (int i = 0; i <input.length; i++)
{
char tem=input[i];
for (int j= 0; j < i; j++)
{
if (tem == input[j])
{
charDupl[ctr++] = input[j];
}
}
}
return charDupl;
}
public char[] RemoveDuplicates(char[] input1, char []input2)
{
int coutn =0;
char[] out2 = new char[10];
boolean flag = false;
for (int i = 0; i < input1.length; i++)
{
for (int j = 0; j < input2.length; j++)
{
if (input1[i] == input2[j])
{
flag = false;
break;
}
else
{
flag = true;
}
}
if (flag)
{
out2[coutn++]=input1[i];
flag = false;
}
}
return out2;
}
}
Yet another solution, seems to be the most concise so far:
private static String removeDuplicates(String s)
{
String x = new String(s);
for(int i=0;i<x.length()-1;i++)
x = x.substring(0,i+1) + (x.substring(i+1)).replace(String.valueOf(x.charAt(i)), "");
return x;
}
I have written a piece of code to solve the problem.
I have checked with certain values, got the required output.
Note: It's time consuming.
static void removeDuplicate(String s) {
char s1[] = s.toCharArray();
Arrays.sort(s1); //Sorting is performed, a to z
//Since adjacent values are compared
int myLength = s1.length; //Length of the character array is stored here
int i = 0; //i refers to the position of original char array
int j = 0; //j refers to the position of char array after skipping the duplicate values
while(i != myLength-1 ){
if(s1[i]!=s1[i+1]){ //Compares two adjacent characters, if they are not the same
s1[j] = s1[i]; //if not same, then, first adjacent character is stored in s[j]
s1[j+1] = s1[i+1]; //Second adjacent character is stored in s[j+1]
j++; //j is incremented to move to next location
}
i++; //i is incremented
}
//the length of s is i. i>j
String s4 = new String (s1); //Char Array to String
//s4[0] to s4[j+1] contains the length characters after removing the duplicate
//s4[j+2] to s4[i] contains the last set of characters of the original char array
System.out.println(s4.substring(0, j+1));
}
Feel free to run my code with your inputs. Thanks.
public class RemoveRepeatedCharacters {
/**
* This method removes duplicates in a given string in one single pass.
* Keeping two indexes, go through all the elements and as long as subsequent characters match, keep
* moving the indexes in opposite directions. When subsequent characters don't match, copy value at higher index
* to (lower + 1) index.
* Time Complexity = O(n)
* Space = O(1)
*
*/
public static void removeDuplicateChars(String text) {
char[] ch = text.toCharArray();
int i = 0; //first index
for(int j = 1; j < ch.length; j++) {
while(i >= 0 && j < ch.length && ch[i] == ch[j]) {
i--;
j++;
System.out.println("i = " + i + " j = " + j);
}
if(j < ch.length) {
ch[++i] = ch[j];
}
}
//Print the final string
for(int k = 0; k <= i; k++)
System.out.print(ch[k]);
}
public static void main(String[] args) {
String text = "abccbdeefgg";
removeDuplicateChars(text);
}
}
public class StringRedundantChars {
/**
* #param args
*/
public static void main(String[] args) {
//initializing the string to be sorted
String sent = "I love painting and badminton";
//Translating the sentence into an array of characters
char[] chars = sent.toCharArray();
System.out.println("Before Sorting");
showLetters(chars);
//Sorting the characters based on the ASCI character code.
java.util.Arrays.sort(chars);
System.out.println("Post Sorting");
showLetters(chars);
System.out.println("Removing Duplicates");
stripDuplicateLetters(chars);
System.out.println("Post Removing Duplicates");
//Sorting to collect all unique characters
java.util.Arrays.sort(chars);
showLetters(chars);
}
/**
* This function prints all valid characters in a given array, except empty values
*
* #param chars Input set of characters to be displayed
*/
private static void showLetters(char[] chars) {
int i = 0;
//The following loop is to ignore all white spaces
while ('\0' == chars[i]) {
i++;
}
for (; i < chars.length; i++) {
System.out.print(" " + chars[i]);
}
System.out.println();
}
private static char[] stripDuplicateLetters(char[] chars) {
// Basic cursor that is used to traverse through the unique-characters
int cursor = 0;
// Probe which is used to traverse the string for redundant characters
int probe = 1;
for (; cursor < chars.length - 1;) {
// Checking if the cursor and probe indices contain the same
// characters
if (chars[cursor] == chars[probe]) {
System.out.println("Removing char : " + chars[probe]);
// Please feel free to replace the redundant character with
// character. I have used '\0'
chars[probe] = '\0';
// Pushing the probe to the next character
probe++;
} else {
// Since the probe has traversed the chars from cursor it means
// that there were no unique characters till probe.
// Hence set cursor to the probe value
cursor = probe;
// Push the probe to refer to the next character
probe++;
}
}
System.out.println();
return chars;
}
}
This is my solution
public static String removeDup(String inputString){
if (inputString.length()<2) return inputString;
if (inputString==null) return null;
char[] inputBuffer=inputString.toCharArray();
for (int i=0;i<inputBuffer.length;i++){
for (int j=i+1;j<inputBuffer.length;j++){
if (inputBuffer[i]==inputBuffer[j]){
inputBuffer[j]=0;
}
}
}
String result=new String(inputBuffer);
return result;
}
Well I came up with the following solution.
Keeping in mind that S and s are not duplicates. Also I have just one hard coded value.. But the code works absolutely fine.
public static String removeDuplicate(String str)
{
StringBuffer rev = new StringBuffer();
rev.append(str.charAt(0));
for(int i=0; i< str.length(); i++)
{
int flag = 0;
for(int j=0; j < rev.length(); j++)
{
if(str.charAt(i) == rev.charAt(j))
{
flag = 0;
break;
}
else
{
flag = 1;
}
}
if(flag == 1)
{
rev.append(str.charAt(i));
}
}
return rev.toString();
}
I couldn't understand the logic behind the solution so I wrote my simple solution:
public static void removeDuplicates(char[] str) {
if (str == null) return; //If the string is null return
int length = str.length; //Getting the length of the string
if (length < 2) return; //Return if the length is 1 or smaller
for(int i=0; i<length; i++){ //Loop through letters on the array
int j;
for(j=i+1;j<length;j++){ //Loop through letters after the checked letters (i)
if (str[j]==str[i]){ //If you find duplicates set it to 0
str[j]=0;
}
}
}
}
Using guava you can just do something like Sets.newHashSet(charArray).toArray();
If you are not using any libraries, you can still use new HashSet<Char>() and add your char array there.
#include <iostream>
#include <string>
using namespace std;
int main() {
// your code goes here
string str;
cin >> str;
long map = 0;
for(int i =0; i < str.length() ; i++){
if((map & (1L << str[i])) > 0){
str[i] = 0;
}
else{
map |= 1L << str[i];
}
}
cout << str;
return 0;
}

Categories