Find the first non repeating character in a string - java

I m writing a method to find the first non repeating character in a string. I saw this method in a previous stackoverflow question
public static char findFirstNonRepChar(String input){
char currentChar = '\0';
int len = input.length();
for(int i=0;i<len;i++){
currentChar = input.charAt(i);
if((i!=0) && (currentChar!=input.charAt(i-1)) && (i==input.lastIndexOf(currentChar))){
return currentChar;
}
}
return currentChar;
}
I came up with a solution using a hashtable where I have two for loops (not nested) where I interate through the string in one loop writing down each occurance of a letter (for example in apple, a would have 1, p would have 2, etc.) then in the second loop I interate through the hashtable to see which one has a count of 1 first. What is the benefit to the above method over what I came up with? I am new to Java does having two loops (not nested) hinder time complexity. Both these algorithms should have O(n) right? Is there another faster, less space complexity algorithm for this question than these two solutions?

public class FirstNonRepeatCharFromString {
public static void main(String[] args) {
String s = "java";
for(Character ch:s.toCharArray()) {
if(s.indexOf(ch) == s.lastIndexOf(ch)) {
System.out.println("First non repeat character = " + ch);
break;
}
}
}
}

As you asked if your code is from O(n) or not, I think it's not, because in the for loop, you are calling lastIndexOf and it's worst case is O(n). So it is from O(n^2).
About your second question: having two loops which are not nested, also makes it from O(n).
If assuming non unicode characters in your input String, and Uppercase or Lowercase characters are assumed to be different, the following would do it with o(n) and supports all ASCII codes from 0 to 255:
public static Character getFirstNotRepeatedChar(String input) {
byte[] flags = new byte[256]; //all is initialized by 0
for (int i = 0; i < input.length(); i++) { // O(n)
flags[(int)input.charAt(i)]++ ;
}
for (int i = 0; i < input.length(); i++) { // O(n)
if(flags[(int)input.charAt(i)] > 0)
return input.charAt(i);
}
return null;
}
Thanks to Konstantinos Chalkias hint about the overflow, if your input string has more than 127 occurrence of a certain character, you can change the type of flags array from byte[] to int[] or long[] to prevent the overflow of byte type.
Hope it would be helpful.

The algorithm you showed is slow: it looks for each character in the string, it basically means that for each character you spend your time checking the string twice!! Huge time loss.
The best naive O(n) solution basically holds all the characters in order of insertion (so the first can be found) and maps a mutable integer to them. When we're done, analyzing, we go through all the entries and return the first character that was registered and has a count of 1.
There are no restrictions on the characters you can use. And AtomicInteger is available with import java.util.concurrent.atomic.AtomicInteger.
Using Java 8:
public static char findFirstNonRepChar(String string) {
Map<Integer,Long> characters = string.chars().boxed()
.collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()));
return (char)(int)characters.entrySet().stream()
.filter(e -> e.getValue() == 1L)
.findFirst()
.map(Map.Entry::getKey)
.orElseThrow(() -> new RuntimeException("No unrepeated character"));
}
Non Java 8 equivalent:
public static char findFirstNonRepChar(String string) {
Map<Character, AtomicInteger> characters = new LinkedHashMap<>(); // preserves order of insertion.
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
AtomicInteger n = characters.get(c);
if (n == null) {
n = new AtomicInteger(0);
characters.put(c, n);
}
n.incrementAndGet();
}
for (Map.Entry<Character, AtomicInteger> entry: characters.entries()) {
if (entry.getValue().get() == 1) {
return entry.getKey();
}
}
throw new RuntimeException("No unrepeated character");
}

import java.util.LinkedHashMap;
import java.util.Map;
public class getFirstNonRep {
public static char get(String s) throws Exception {
if (s.length() == 0) {
System.out.println("Fail");
System.exit(0);
} else {
Map<Character, Integer> m = new LinkedHashMap<Character, Integer>();
for (int i = 0; i < s.length(); i++) {
if (m.containsKey(s.charAt(i))) {
m.put(s.charAt(i), m.get(s.charAt(i)) + 1);
} else {
m.put(s.charAt(i), 1);
}
}
for (Map.Entry<Character, Integer> hm : m.entrySet()) {
if (hm.getValue() == 1) {
return hm.getKey();
}
}
}
return 0;
}
public static void main(String[] args) throws Exception {
System.out.print(get("Youssef Zaky"));
}
}
This solution takes less space and less time, since we iterate the string only one time.

Works for any type of characters.
String charHolder; // Holds
String testString = "8uiuiti080t8xt8t";
char testChar = ' ';
int count = 0;
for (int i=0; i <= testString.length()-1; i++) {
testChar = testString.charAt(i);
for (int j=0; j < testString.length()-1; j++) {
if (testChar == testString.charAt(j)) {
count++;
}
}
if (count == 1) { break; };
count = 0;
}
System.out.println("The first not repeating character is " + testChar);

I accumulated all possible methods with string length 25'500 symbols:
private static String getFirstUniqueChar(String line) {
String result1 = null, result2 = null, result3 = null, result4 = null, result5 = null;
int length = line.length();
long start = System.currentTimeMillis();
Map<Character, Integer> chars = new LinkedHashMap<Character, Integer>();
char[] charArray1 = line.toCharArray();
for (int i = 0; i < length; i++) {
char currentChar = charArray1[i];
chars.put(currentChar, chars.containsKey(currentChar) ? chars.get(currentChar) + 1 : 1);
}
for (Map.Entry<Character, Integer> entry : chars.entrySet()) {
if (entry.getValue() == 1) {
result1 = entry.getKey().toString();
break;
}
}
long end = System.currentTimeMillis();
System.out.println("1st test:\n result: " + result1 + "\n time: " + (end - start));
start = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
String current = Character.toString(line.charAt(i));
String left = line.substring(0, i);
if (!left.contains(current)) {
String right = line.substring(i + 1);
if (!right.contains(current)) {
result2 = current;
break;
}
}
}
end = System.currentTimeMillis();
System.out.println("2nd test:\n result: " + result2 + "\n time: " + (end - start));
start = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
char currentChar = line.charAt(i);
if (line.indexOf(currentChar) == line.lastIndexOf(currentChar)) {
result3 = Character.toString(currentChar);
break;
}
}
end = System.currentTimeMillis();
System.out.println("3rd test:\n result: " + result3 + "\n time: " + (end - start));
start = System.currentTimeMillis();
char[] charArray4 = line.toCharArray();
for (int i = 0; i < length; i++) {
char currentChar = charArray4[i];
int count = 0;
for (int j = 0; j < length; j++) {
if (currentChar == charArray4[j] && i != j) {
count++;
break;
}
}
if (count == 0) {
result4 = Character.toString(currentChar);
break;
}
}
end = System.currentTimeMillis();
System.out.println("4th test:\n result: " + result4 + "\n time: " + (end - start));
start = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
char currentChar = line.charAt(i);
int count = 0;
for (int j = 0; j < length; j++) {
if (currentChar == line.charAt(j) && i != j) {
count++;
break;
}
}
if (count == 0) {
result5 = Character.toString(currentChar);
break;
}
}
end = System.currentTimeMillis();
System.out.println("5th test:\n result: " + result5 + "\n time: " + (end - start));
return result1;
}
And time results (5 times):
1st test:
result: g
time: 13, 12, 12, 12, 14
2nd test:
result: g
time: 55, 56, 59, 70, 59
3rd test:
result: g
time: 2, 3, 2, 2, 3
4th test:
result: g
time: 3, 3, 2, 3, 3
5th test:
result: g
time: 6, 5, 5, 5, 6

public static char NonReapitingCharacter(String str) {
Set<Character> s = new HashSet();
char ch = '\u0000';
for (char c : str.toCharArray()) {
if (s.add(c)) {
if (c == ch) {
break;
} else {
ch = c;
}
}
}
return ch;
}

Okay I misread the question initially so here's a new solution. I believe is this O(n). The contains(Object) of HashSet is O(1), so we can take advantage of that and avoid a second loop. Essentially if we've never seen a specific char before, we add it to the validChars as a potential candidate to be returned. The second we see it again however, we add it to the trash can of invalidChars. This prevents that char from being added again. At the end of the loop (you have to loop at least once no matter what you do), you'll have a validChars hashset with n amount of elements. If none are there, then it will return null from the Character class. This has a distinct advantage as the char class has no good way to return a 'bad' result so to speak.
public static Character findNonRepeatingChar(String x)
{
HashSet<Character> validChars = new HashSet<>();
HashSet<Character> invalidChars = new HashSet<>();
char[] array = x.toCharArray();
for (char c : array)
{
if (validChars.contains(c))
{
validChars.remove(c);
invalidChars.add(c);
}
else if (!validChars.contains(c) && !invalidChars.contains(c))
{
validChars.add(c);
}
}
return (!validChars.isEmpty() ? validChars.iterator().next() : null);
}

If you are only interested for characters in the range a-z (lowercase as OP requested in comments), you can use this method that requires a minimum extra storage of two bits per character Vs a HashMap approach.
/*
* It works for lowercase a-z
* you can scale it to add more characters
* eg use 128 Vs 26 for ASCII or 256 for extended ASCII
*/
public static char getFirstNotRepeatedChar(String input) {
boolean[] charsExist = new boolean[26];
boolean[] charsNonUnique = new boolean[26];
for (int i = 0; i < input.length(); i++) {
int index = 'z' - input.charAt(i);
if (!charsExist[index]) {
charsExist[index] = true;
} else {
charsNonUnique[index] = true;
}
}
for (int i = 0; i < input.length(); i++) {
if (!charsNonUnique['z' - input.charAt(i)])
return input.charAt(i);
}
return '?'; //example return of no character found
}

In case of two loops (not nested) the time complexity would be O(n).
The second solution mentioned in the question can be implemented as:
We can use string characters as keys to a map and maintain their count. Following is the algorithm.
1.Scan the string from left to right and construct the count map.
2.Again, scan the string from left to right and check for count of each character from the map, if you find an element who’s count is 1, return it.
package com.java.teasers.samples;
import java.util.Map;
import java.util.HashMap;
public class NonRepeatCharacter {
public static void main(String[] args) {
String yourString = "Hi this is javateasers";//change it with your string
Map<Character, Integer> characterMap = new HashMap<Character, Integer>();
//Step 1 of the Algorithm
for (int i = 0; i < yourString.length(); i++) {
Character character = yourString.charAt(i);
//check if character is already present
if(null != characterMap.get(character)){
//in case it is already there increment the count by 1.
characterMap.put(character, characterMap.get(character) + 1);
}
//in case it is for the first time. Put 1 to the count
else
characterMap.put(character, 1);
}
//Step 2 of the Algorithm
for (int i = 0; i < yourString.length(); i++) {
Character character = yourString.charAt(i);
int count = characterMap.get(character);
if(count == 1){
System.out.println("character is:" + character);
break;
}
}
}
}

public char firstNonRepeatedChar(String input) {
char out = 0;
int length = input.length();
for (int i = 0; i < length; i++) {
String sub1 = input.substring(0, i);
String sub2 = input.substring(i + 1);
if (!(sub1.contains(input.charAt(i) + "") || sub2.contains(input
.charAt(i) + ""))) {
out = input.charAt(i);
break;
}
}
return out;
}

Since LinkedHashMap keeps the order of insertion
package com.company;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
public class Main {
public static void main(String[] argh) {
Scanner sc = new Scanner(System.in);
String l = sc.nextLine();
System.out.println(firstCharNoRepeated(l));
}
private static String firstCharNoRepeated(String l) {
Map<String, Integer> chars = new LinkedHashMap();
for(int i=0; i < l.length(); i++) {
String c = String.valueOf(l.charAt(i));
if(!chars.containsKey(c)){
chars.put(c, i);
} else {
chars.remove(c);
}
}
return chars.keySet().iterator().next();
}
}

Few lines of code, works for me.
public class FirstNonRepeatingCharacter {
final static String string = "cascade";
public static void main(String[] args) {
char[] charArr = string.toCharArray();
for (int i = 0; charArr.length > i; i++) {
int count = 0;
for (int j = 0; charArr.length > j; j++) {
if (charArr[i] == charArr[j]) {
count++;
}
}
if (count == 1){
System.out.println("First Non Repeating Character is: " + charArr[i]);
break;
}
}
}
}

Constraint for this solution:
O(n) time complexity. My solution is O(2n), follow Time Complexity analysis,O(2n) => O(n)
import java.util.HashMap;
public class FindFirstNonDuplicateCharacter {
public static void main(String args[]) {
System.out.println(findFirstNonDuplicateCharacter("abacbcefd"));
}
private static char findFirstNonDuplicateCharacter(String s) {
HashMap<Character, Integer> chDupCount = new HashMap<Character, Integer>();
char[] charArr = s.toCharArray();
for (char ch: charArr) { //first loop, make the tables and counted duplication by key O(n)
if (!chDupCount.containsKey(ch)) {
chDupCount.put(ch,1);
continue;
}
int dupCount = chDupCount.get(ch)+1;
chDupCount.replace(ch, dupCount);
}
char res = '-';
for(char ch: charArr) { //second loop, get the first duplicate by count number, O(2n)
// System.out.println("key: " + ch+", value: " + chDupCount.get(ch));
if (chDupCount.get(ch) == 1) {
res = ch;
break;
}
}
return res;
}
}
Hope it help

char firstNotRepeatingCharacter(String s) {
for(int i=0; i< s.length(); i++){
if(i == s.lastIndexOf(s.charAt(i)) && i == s.indexOf(s.charAt(i))){
return s.charAt(i);
}
}
return '_';
}

String a = "sampapl";
char ar[] = a.toCharArray();
int dya[] = new int[256];
for (int i = 0; i < dya.length; i++) {
dya[i] = -1;
}
for (int i = 0; i < ar.length; i++) {
if (dya[ar[i]] != -1) {
System.out.println(ar[i]);
break;
} else {
dya[ar[i]] = ar[i];
}
}

This is solution in python:
input_str = "interesting"
#input_str = "aabbcc"
#input_str = "aaaapaabbcccq"
def firstNonRepeating(param):
counts = {}
for i in range(0, len(param)):
# Store count and index repectively
if param[i] in counts:
counts[param[i]][0] += 1
else:
counts[param[i]] = [1, i]
result_index = len(param) - 1
for x in counts:
if counts[x][0] == 1 and result_index > counts[x][1]:
result_index = counts[x][1]
return result_index
result_index = firstNonRepeating(input_str)
if result_index == len(input_str)-1:
print("no such character found")
else:
print("first non repeating charater found: " + input_str[result_index])
Output:
first non repeating charater found: r

import java.util.*;
public class Main {
public static void main(String[] args) {
String str1 = "gibblegabbler";
System.out.println("The given string is: " + str1);
for (int i = 0; i < str1.length(); i++) {
boolean unique = true;
for (int j = 0; j < str1.length(); j++) {
if (i != j && str1.charAt(i) == str1.charAt(j)) {
unique = false;
break;
}
}
if (unique) {
System.out.println("The first non repeated character in String is: " + str1.charAt(i));
break;
}
}
}
}

public class GFG {
public static void main(String[] args) {
String s = "mmjjjjmmn";
for (char c : s.toCharArray()) {
if (s.indexOf(c) == s.lastIndexOf(c)) {
System.out.println("First non repeated is:" + c);
break;
}
}
}
output = n

Non Repeated Character String in Java
public class NonRepeatedCharacter {
public static void main(String[] args) {
String s = "ffeeddbbaaclck";
for (int i = 0; i < s.length(); i++) {
boolean unique = true;
for (int j = 0; j < s.length(); j++) {
if (i != j && s.charAt(i) == s.charAt(j)) {
unique = false;
break;
}
}
if (unique) {
System.out.println("First non repeated characted in String \""
+ s + "\" is:" + s.charAt(i));
break;
}
}
}
}
Output:
First non repeated characted in String "ffeeddbbaaclck" is:l
For More Details

In this coding i use length of string to find the first non repeating letter.
package com.string.assingment3;
import java.util.Scanner;
public class FirstNonRepetedChar {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Enter a String : ");
String str = in.next();
char[] ch = str.toCharArray();
int length = ch.length;
int x = length;
for(int i=0;i<length;i++) {
x = length-i;
for(int j=i+1;j<length;j++) {
if(ch[i]!=ch[j]) {
x--;
}//if
}//inner for
if(x==1) {
System.out.println(ch[i]);
break;
}
else {
continue;
}
}//outer for
}
}// develope by NDM

In Kotlin
fun firstNonRepeating(string: String): Char?{
//Get a copy of the string
var copy = string
//Slice string into chars then convert them to string
string.map { it.toString() }.forEach {
//Replace first occurrance of that character and check if it still has it
if (copy.replaceFirst(it,"").contains(it))
//If it has the given character remove it
copy = copy.replace(it,"")
}
//Return null if there is no non-repeating character
if (copy.isEmpty())
return null
//Get the first character from what left of that string
return copy.first()
}
https://pl.kotl.in/KzL-veYNZ

public static void firstNonRepeatFirstChar(String str) {
System.out.println("The given string is: " + str);
for (int i = 0; i < str.length(); i++) {
boolean unique = true;
for (int j = 0; j < str.length(); j++) {
if (i != j && str.charAt(i) == str.charAt(j)) {
unique = false;
break;
}
}
if (unique) {
System.out.println("The first non repeated character in String is: " + str.charAt(i));
break;
}
}
}

Using Set with single for loop
public static Character firstNonRepeatedCharacter(String str) {
Character result = null;
if (str != null) {
Set<Character> set = new HashSet<>();
for (char c : str.toCharArray()) {
if (set.add(c) && result == null) {
result = c;
} else if (result != null && c == result) {
result = null;
}
}
}
return result;
}

You can achieve this in single traversal of String using LinkedHashSet as follows:
public static Character getFirstNonRepeatingCharacter(String str) {
Set<Character> result = new LinkedHashSet<>(256);
for (int i = 0; i< str.length(); ++i) {
if(!result.add(str.charAt(i))) {
result.remove(str.charAt(i));
}
}
if(result.iterator().hasNext()) {
return result.iterator().next();
}
return null;
}

For Java;
char firstNotRepeatingCharacter(String s) {
HashSet<String> hs = new HashSet<>();
StringBuilder sb =new StringBuilder(s);
for (int i = 0; i<s.length(); i++){
char c = sb.charAt(i);
if(s.indexOf(c) == i && s.indexOf(c, i+1) == -1 ) {
return c;
}
}
return '_';
}

public class FirstNonRepeatingChar {
public static void main(String[] args) {
String s = "hello world i am here";
s.chars().boxed()
.collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()))
.entrySet().stream().filter(e -> e.getValue() == 1).findFirst().ifPresent(e->System.out.println(e.getKey()));
}
}

package looping.concepts;
import java.util.Scanner;
public class Line {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter name: ");
String a = sc.nextLine();
int i = 0;
int j = 0;
for (i = 0; i < a.length(); i++) {
char ch = a.charAt(i);
int counter = 0;
// boolean repeat = false;
for (j = 0; j < a.length(); j++) {
if (ch == a.charAt(j)) {
counter++;
}
}
if (counter == 1) {
System.out.print(ch);
}
else
{
System.out.print("There is no non repeated character");
break;
}
}
}
}

import java.util.Scanner;
public class NonRepaeated1
{
public static void main(String args[])
{
String str;
char non_repeat=0;
int len,i,j,count=0;
Scanner s = new Scanner(System.in);
str = s.nextLine();
len = str.length();
for(i=0;i<len;i++)
{
non_repeat=str.charAt(i);
count=1;
for(j=0;j<len;j++)
{
if(i!=j)
{
if(str.charAt(i) == str.charAt(j))
{
count=0;
break;
}
}
}
if(count==1)
break;
}
if(count == 1)
System.out.print("The non repeated character is : " + non_repeat);
}
}

package com.test.util;
public class StringNoRepeat {
public static void main(String args[]) {
String st = "234123nljnsdfsdf41l";
String strOrig=st;
int i=0;
int j=0;
String st1="";
Character ch=' ';
boolean fnd=false;
for (i=0;i<strOrig.length(); i++) {
ch=strOrig.charAt(i);
st1 = ch.toString();
if (i==0)
st = strOrig.substring(1,strOrig.length());
else if (i == strOrig.length()-1)
st=strOrig.substring(0, strOrig.length()-1);
else
st=strOrig.substring(0, i)+strOrig.substring(i+1,strOrig.length());
if (st.indexOf(st1) == -1) {
fnd=true;
j=i;
break;
}
}
if (!fnd)
System.out.println("The first no non repeated character");
else
System.out.println("The first non repeated character is " +strOrig.charAt(j));
}
}

Related

Efficient/Fast way to get permutation of a String in java [duplicate]

What is an elegant way to find all the permutations of a string. E.g. permutation for ba, would be ba and ab, but what about longer string such as abcdefgh? Is there any Java implementation example?
public static void permutation(String str) {
permutation("", str);
}
private static void permutation(String prefix, String str) {
int n = str.length();
if (n == 0) System.out.println(prefix);
else {
for (int i = 0; i < n; i++)
permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n));
}
}
(via Introduction to Programming in Java)
Use recursion.
Try each of the letters in turn as the first letter and then find all the permutations of the remaining letters using a recursive call.
The base case is when the input is an empty string the only permutation is the empty string.
Here is my solution that is based on the idea of the book "Cracking the Coding Interview" (P54):
/**
* List permutations of a string.
*
* #param s the input string
* #return the list of permutations
*/
public static ArrayList<String> permutation(String s) {
// The result
ArrayList<String> res = new ArrayList<String>();
// If input string's length is 1, return {s}
if (s.length() == 1) {
res.add(s);
} else if (s.length() > 1) {
int lastIndex = s.length() - 1;
// Find out the last character
String last = s.substring(lastIndex);
// Rest of the string
String rest = s.substring(0, lastIndex);
// Perform permutation on the rest string and
// merge with the last character
res = merge(permutation(rest), last);
}
return res;
}
/**
* #param list a result of permutation, e.g. {"ab", "ba"}
* #param c the last character
* #return a merged new list, e.g. {"cab", "acb" ... }
*/
public static ArrayList<String> merge(ArrayList<String> list, String c) {
ArrayList<String> res = new ArrayList<>();
// Loop through all the string in the list
for (String s : list) {
// For each string, insert the last character to all possible positions
// and add them to the new list
for (int i = 0; i <= s.length(); ++i) {
String ps = new StringBuffer(s).insert(i, c).toString();
res.add(ps);
}
}
return res;
}
Running output of string "abcd":
Step 1: Merge [a] and b:
[ba, ab]
Step 2: Merge [ba, ab] and c:
[cba, bca, bac, cab, acb, abc]
Step 3: Merge [cba, bca, bac, cab, acb, abc] and d:
[dcba, cdba, cbda, cbad, dbca, bdca, bcda, bcad, dbac, bdac, badc, bacd, dcab, cdab, cadb, cabd, dacb, adcb, acdb, acbd, dabc, adbc, abdc, abcd]
Of all the solutions given here and in other forums, I liked Mark Byers the most. That description actually made me think and code it myself.
Too bad I cannot voteup his solution as I am newbie.
Anyways here is my implementation of his description
public class PermTest {
public static void main(String[] args) throws Exception {
String str = "abcdef";
StringBuffer strBuf = new StringBuffer(str);
doPerm(strBuf,0);
}
private static void doPerm(StringBuffer str, int index){
if(index == str.length())
System.out.println(str);
else { //recursively solve this by placing all other chars at current first pos
doPerm(str, index+1);
for (int i = index+1; i < str.length(); i++) {//start swapping all other chars with current first char
swap(str,index, i);
doPerm(str, index+1);
swap(str,i, index);//restore back my string buffer
}
}
}
private static void swap(StringBuffer str, int pos1, int pos2){
char t1 = str.charAt(pos1);
str.setCharAt(pos1, str.charAt(pos2));
str.setCharAt(pos2, t1);
}
}
I prefer this solution ahead of the first one in this thread because this solution uses StringBuffer. I wouldn't say my solution doesn't create any temporary string (it actually does in system.out.println where the toString() of StringBuffer is called). But I just feel this is better than the first solution where too many string literals are created. May be some performance guy out there can evalute this in terms of 'memory' (for 'time' it already lags due to that extra 'swap')
A very basic solution in Java is to use recursion + Set ( to avoid repetitions ) if you want to store and return the solution strings :
public static Set<String> generatePerm(String input)
{
Set<String> set = new HashSet<String>();
if (input == "")
return set;
Character a = input.charAt(0);
if (input.length() > 1)
{
input = input.substring(1);
Set<String> permSet = generatePerm(input);
for (String x : permSet)
{
for (int i = 0; i <= x.length(); i++)
{
set.add(x.substring(0, i) + a + x.substring(i));
}
}
}
else
{
set.add(a + "");
}
return set;
}
All the previous contributors have done a great job explaining and providing the code. I thought I should share this approach too because it might help someone too. The solution is based on (heaps' algorithm )
Couple of things:
Notice the last item which is depicted in the excel is just for helping you better visualize the logic. So, the actual values in the last column would be 2,1,0 (if we were to run the code because we are dealing with arrays and arrays start with 0).
The swapping algorithm happens based on even or odd values of current position. It's very self explanatory if you look at where the swap method is getting called.You can see what's going on.
Here is what happens:
public static void main(String[] args) {
String ourword = "abc";
String[] ourArray = ourword.split("");
permute(ourArray, ourArray.length);
}
private static void swap(String[] ourarray, int right, int left) {
String temp = ourarray[right];
ourarray[right] = ourarray[left];
ourarray[left] = temp;
}
public static void permute(String[] ourArray, int currentPosition) {
if (currentPosition == 1) {
System.out.println(Arrays.toString(ourArray));
} else {
for (int i = 0; i < currentPosition; i++) {
// subtract one from the last position (here is where you are
// selecting the the next last item
permute(ourArray, currentPosition - 1);
// if it's odd position
if (currentPosition % 2 == 1) {
swap(ourArray, 0, currentPosition - 1);
} else {
swap(ourArray, i, currentPosition - 1);
}
}
}
}
Let's use input abc as an example.
Start off with just the last element (c) in a set (["c"]), then add the second last element (b) to its front, end and every possible positions in the middle, making it ["bc", "cb"] and then in the same manner it will add the next element from the back (a) to each string in the set making it:
"a" + "bc" = ["abc", "bac", "bca"] and "a" + "cb" = ["acb" ,"cab", "cba"]
Thus entire permutation:
["abc", "bac", "bca","acb" ,"cab", "cba"]
Code:
public class Test
{
static Set<String> permutations;
static Set<String> result = new HashSet<String>();
public static Set<String> permutation(String string) {
permutations = new HashSet<String>();
int n = string.length();
for (int i = n - 1; i >= 0; i--)
{
shuffle(string.charAt(i));
}
return permutations;
}
private static void shuffle(char c) {
if (permutations.size() == 0) {
permutations.add(String.valueOf(c));
} else {
Iterator<String> it = permutations.iterator();
for (int i = 0; i < permutations.size(); i++) {
String temp1;
for (; it.hasNext();) {
temp1 = it.next();
for (int k = 0; k < temp1.length() + 1; k += 1) {
StringBuilder sb = new StringBuilder(temp1);
sb.insert(k, c);
result.add(sb.toString());
}
}
}
permutations = result;
//'result' has to be refreshed so that in next run it doesn't contain stale values.
result = new HashSet<String>();
}
}
public static void main(String[] args) {
Set<String> result = permutation("abc");
System.out.println("\nThere are total of " + result.size() + " permutations:");
Iterator<String> it = result.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
This one is without recursion
public static void permute(String s) {
if(null==s || s.isEmpty()) {
return;
}
// List containing words formed in each iteration
List<String> strings = new LinkedList<String>();
strings.add(String.valueOf(s.charAt(0))); // add the first element to the list
// Temp list that holds the set of strings for
// appending the current character to all position in each word in the original list
List<String> tempList = new LinkedList<String>();
for(int i=1; i< s.length(); i++) {
for(int j=0; j<strings.size(); j++) {
tempList.addAll(merge(s.charAt(i), strings.get(j)));
}
strings.removeAll(strings);
strings.addAll(tempList);
tempList.removeAll(tempList);
}
for(int i=0; i<strings.size(); i++) {
System.out.println(strings.get(i));
}
}
/**
* helper method that appends the given character at each position in the given string
* and returns a set of such modified strings
* - set removes duplicates if any(in case a character is repeated)
*/
private static Set<String> merge(Character c, String s) {
if(s==null || s.isEmpty()) {
return null;
}
int len = s.length();
StringBuilder sb = new StringBuilder();
Set<String> list = new HashSet<String>();
for(int i=0; i<= len; i++) {
sb = new StringBuilder();
sb.append(s.substring(0, i) + c + s.substring(i, len));
list.add(sb.toString());
}
return list;
}
Well here is an elegant, non-recursive, O(n!) solution:
public static StringBuilder[] permutations(String s) {
if (s.length() == 0)
return null;
int length = fact(s.length());
StringBuilder[] sb = new StringBuilder[length];
for (int i = 0; i < length; i++) {
sb[i] = new StringBuilder();
}
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
int times = length / (i + 1);
for (int j = 0; j < times; j++) {
for (int k = 0; k < length / times; k++) {
sb[j * length / times + k].insert(k, ch);
}
}
}
return sb;
}
One of the simple solution could be just keep swapping the characters recursively using two pointers.
public static void main(String[] args)
{
String str="abcdefgh";
perm(str);
}
public static void perm(String str)
{ char[] char_arr=str.toCharArray();
helper(char_arr,0);
}
public static void helper(char[] char_arr, int i)
{
if(i==char_arr.length-1)
{
// print the shuffled string
String str="";
for(int j=0; j<char_arr.length; j++)
{
str=str+char_arr[j];
}
System.out.println(str);
}
else
{
for(int j=i; j<char_arr.length; j++)
{
char tmp = char_arr[i];
char_arr[i] = char_arr[j];
char_arr[j] = tmp;
helper(char_arr,i+1);
char tmp1 = char_arr[i];
char_arr[i] = char_arr[j];
char_arr[j] = tmp1;
}
}
}
python implementation
def getPermutation(s, prefix=''):
if len(s) == 0:
print prefix
for i in range(len(s)):
getPermutation(s[0:i]+s[i+1:len(s)],prefix+s[i] )
getPermutation('abcd','')
This is what I did through basic understanding of Permutations and Recursive function calling. Takes a bit of time but it's done independently.
public class LexicographicPermutations {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s="abc";
List<String>combinations=new ArrayList<String>();
combinations=permutations(s);
Collections.sort(combinations);
System.out.println(combinations);
}
private static List<String> permutations(String s) {
// TODO Auto-generated method stub
List<String>combinations=new ArrayList<String>();
if(s.length()==1){
combinations.add(s);
}
else{
for(int i=0;i<s.length();i++){
List<String>temp=permutations(s.substring(0, i)+s.substring(i+1));
for (String string : temp) {
combinations.add(s.charAt(i)+string);
}
}
}
return combinations;
}}
which generates Output as [abc, acb, bac, bca, cab, cba].
Basic logic behind it is
For each character, consider it as 1st character & find the combinations of remaining characters. e.g. [abc](Combination of abc)->.
a->[bc](a x Combination of (bc))->{abc,acb}
b->[ac](b x Combination of (ac))->{bac,bca}
c->[ab](c x Combination of (ab))->{cab,cba}
And then recursively calling each [bc],[ac] & [ab] independently.
Use recursion.
when the input is an empty string the only permutation is an empty string.Try for each of the letters in the string by making it as the first letter and then find all the permutations of the remaining letters using a recursive call.
import java.util.ArrayList;
import java.util.List;
class Permutation {
private static List<String> permutation(String prefix, String str) {
List<String> permutations = new ArrayList<>();
int n = str.length();
if (n == 0) {
permutations.add(prefix);
} else {
for (int i = 0; i < n; i++) {
permutations.addAll(permutation(prefix + str.charAt(i), str.substring(i + 1, n) + str.substring(0, i)));
}
}
return permutations;
}
public static void main(String[] args) {
List<String> perms = permutation("", "abcd");
String[] array = new String[perms.size()];
for (int i = 0; i < perms.size(); i++) {
array[i] = perms.get(i);
}
int x = array.length;
for (final String anArray : array) {
System.out.println(anArray);
}
}
}
this worked for me..
import java.util.Arrays;
public class StringPermutations{
public static void main(String args[]) {
String inputString = "ABC";
permute(inputString.toCharArray(), 0, inputString.length()-1);
}
public static void permute(char[] ary, int startIndex, int endIndex) {
if(startIndex == endIndex){
System.out.println(String.valueOf(ary));
}else{
for(int i=startIndex;i<=endIndex;i++) {
swap(ary, startIndex, i );
permute(ary, startIndex+1, endIndex);
swap(ary, startIndex, i );
}
}
}
public static void swap(char[] ary, int x, int y) {
char temp = ary[x];
ary[x] = ary[y];
ary[y] = temp;
}
}
Java implementation without recursion
public Set<String> permutate(String s){
Queue<String> permutations = new LinkedList<String>();
Set<String> v = new HashSet<String>();
permutations.add(s);
while(permutations.size()!=0){
String str = permutations.poll();
if(!v.contains(str)){
v.add(str);
for(int i = 0;i<str.length();i++){
String c = String.valueOf(str.charAt(i));
permutations.add(str.substring(i+1) + c + str.substring(0,i));
}
}
}
return v;
}
Let me try to tackle this problem with Kotlin:
fun <T> List<T>.permutations(): List<List<T>> {
//escape case
if (this.isEmpty()) return emptyList()
if (this.size == 1) return listOf(this)
if (this.size == 2) return listOf(listOf(this.first(), this.last()), listOf(this.last(), this.first()))
//recursive case
return this.flatMap { lastItem ->
this.minus(lastItem).permutations().map { it.plus(lastItem) }
}
}
Core concept: Break down long list into smaller list + recursion
Long answer with example list [1, 2, 3, 4]:
Even for a list of 4 it already kinda get's confusing trying to list all the possible permutations in your head, and what we need to do is exactly to avoid that. It is easy for us to understand how to make all permutations of list of size 0, 1, and 2, so all we need to do is break them down to any of those sizes and combine them back up correctly. Imagine a jackpot machine: this algorithm will start spinning from the right to the left, and write down
return empty/list of 1 when list size is 0 or 1
handle when list size is 2 (e.g. [3, 4]), and generate the 2 permutations ([3, 4] & [4, 3])
For each item, mark that as the last in the last, and find all the permutations for the rest of the item in the list. (e.g. put [4] on the table, and throw [1, 2, 3] into permutation again)
Now with all permutation it's children, put itself back to the end of the list (e.g.: [1, 2, 3][,4], [1, 3, 2][,4], [2, 3, 1][, 4], ...)
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
public class hello {
public static void main(String[] args) throws IOException {
hello h = new hello();
h.printcomp();
}
int fact=1;
public void factrec(int a,int k){
if(a>=k)
{fact=fact*k;
k++;
factrec(a,k);
}
else
{System.out.println("The string will have "+fact+" permutations");
}
}
public void printcomp(){
String str;
int k;
Scanner in = new Scanner(System.in);
System.out.println("enter the string whose permutations has to b found");
str=in.next();
k=str.length();
factrec(k,1);
String[] arr =new String[fact];
char[] array = str.toCharArray();
while(p<fact)
printcomprec(k,array,arr);
// if incase u need array containing all the permutation use this
//for(int d=0;d<fact;d++)
//System.out.println(arr[d]);
}
int y=1;
int p = 0;
int g=1;
int z = 0;
public void printcomprec(int k,char array[],String arr[]){
for (int l = 0; l < k; l++) {
for (int b=0;b<k-1;b++){
for (int i=1; i<k-g; i++) {
char temp;
String stri = "";
temp = array[i];
array[i] = array[i + g];
array[i + g] = temp;
for (int j = 0; j < k; j++)
stri += array[j];
arr[z] = stri;
System.out.println(arr[z] + " " + p++);
z++;
}
}
char temp;
temp=array[0];
array[0]=array[y];
array[y]=temp;
if (y >= k-1)
y=y-(k-1);
else
y++;
}
if (g >= k-1)
g=1;
else
g++;
}
}
/** Returns an array list containing all
* permutations of the characters in s. */
public static ArrayList<String> permute(String s) {
ArrayList<String> perms = new ArrayList<>();
int slen = s.length();
if (slen > 0) {
// Add the first character from s to the perms array list.
perms.add(Character.toString(s.charAt(0)));
// Repeat for all additional characters in s.
for (int i = 1; i < slen; ++i) {
// Get the next character from s.
char c = s.charAt(i);
// For each of the strings currently in perms do the following:
int size = perms.size();
for (int j = 0; j < size; ++j) {
// 1. remove the string
String p = perms.remove(0);
int plen = p.length();
// 2. Add plen + 1 new strings to perms. Each new string
// consists of the removed string with the character c
// inserted into it at a unique location.
for (int k = 0; k <= plen; ++k) {
perms.add(p.substring(0, k) + c + p.substring(k));
}
}
}
}
return perms;
}
Here is a straightforward minimalist recursive solution in Java:
public static ArrayList<String> permutations(String s) {
ArrayList<String> out = new ArrayList<String>();
if (s.length() == 1) {
out.add(s);
return out;
}
char first = s.charAt(0);
String rest = s.substring(1);
for (String permutation : permutations(rest)) {
out.addAll(insertAtAllPositions(first, permutation));
}
return out;
}
public static ArrayList<String> insertAtAllPositions(char ch, String s) {
ArrayList<String> out = new ArrayList<String>();
for (int i = 0; i <= s.length(); ++i) {
String inserted = s.substring(0, i) + ch + s.substring(i);
out.add(inserted);
}
return out;
}
We can use factorial to find how many strings started with particular letter.
Example: take the input abcd. (3!) == 6 strings will start with every letter of abcd.
static public int facts(int x){
int sum = 1;
for (int i = 1; i < x; i++) {
sum *= (i+1);
}
return sum;
}
public static void permutation(String str) {
char[] str2 = str.toCharArray();
int n = str2.length;
int permutation = 0;
if (n == 1) {
System.out.println(str2[0]);
} else if (n == 2) {
System.out.println(str2[0] + "" + str2[1]);
System.out.println(str2[1] + "" + str2[0]);
} else {
for (int i = 0; i < n; i++) {
if (true) {
char[] str3 = str.toCharArray();
char temp = str3[i];
str3[i] = str3[0];
str3[0] = temp;
str2 = str3;
}
for (int j = 1, count = 0; count < facts(n-1); j++, count++) {
if (j != n-1) {
char temp1 = str2[j+1];
str2[j+1] = str2[j];
str2[j] = temp1;
} else {
char temp1 = str2[n-1];
str2[n-1] = str2[1];
str2[1] = temp1;
j = 1;
} // end of else block
permutation++;
System.out.print("permutation " + permutation + " is -> ");
for (int k = 0; k < n; k++) {
System.out.print(str2[k]);
} // end of loop k
System.out.println();
} // end of loop j
} // end of loop i
}
}
//insert each character into an arraylist
static ArrayList al = new ArrayList();
private static void findPermutation (String str){
for (int k = 0; k < str.length(); k++) {
addOneChar(str.charAt(k));
}
}
//insert one char into ArrayList
private static void addOneChar(char ch){
String lastPerStr;
String tempStr;
ArrayList locAl = new ArrayList();
for (int i = 0; i < al.size(); i ++ ){
lastPerStr = al.get(i).toString();
//System.out.println("lastPerStr: " + lastPerStr);
for (int j = 0; j <= lastPerStr.length(); j++) {
tempStr = lastPerStr.substring(0,j) + ch +
lastPerStr.substring(j, lastPerStr.length());
locAl.add(tempStr);
//System.out.println("tempStr: " + tempStr);
}
}
if(al.isEmpty()){
al.add(ch);
} else {
al.clear();
al = locAl;
}
}
private static void printArrayList(ArrayList al){
for (int i = 0; i < al.size(); i++) {
System.out.print(al.get(i) + " ");
}
}
//Rotate and create words beginning with all letter possible and push to stack 1
//Read from stack1 and for each word create words with other letters at the next location by rotation and so on
/* eg : man
1. push1 - man, anm, nma
2. pop1 - nma , push2 - nam,nma
pop1 - anm , push2 - amn,anm
pop1 - man , push2 - mna,man
*/
public class StringPermute {
static String str;
static String word;
static int top1 = -1;
static int top2 = -1;
static String[] stringArray1;
static String[] stringArray2;
static int strlength = 0;
public static void main(String[] args) throws IOException {
System.out.println("Enter String : ");
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader bfr = new BufferedReader(isr);
str = bfr.readLine();
word = str;
strlength = str.length();
int n = 1;
for (int i = 1; i <= strlength; i++) {
n = n * i;
}
stringArray1 = new String[n];
stringArray2 = new String[n];
push(word, 1);
doPermute();
display();
}
public static void push(String word, int x) {
if (x == 1)
stringArray1[++top1] = word;
else
stringArray2[++top2] = word;
}
public static String pop(int x) {
if (x == 1)
return stringArray1[top1--];
else
return stringArray2[top2--];
}
public static void doPermute() {
for (int j = strlength; j >= 2; j--)
popper(j);
}
public static void popper(int length) {
// pop from stack1 , rotate each word n times and push to stack 2
if (top1 > -1) {
while (top1 > -1) {
word = pop(1);
for (int j = 0; j < length; j++) {
rotate(length);
push(word, 2);
}
}
}
// pop from stack2 , rotate each word n times w.r.t position and push to
// stack 1
else {
while (top2 > -1) {
word = pop(2);
for (int j = 0; j < length; j++) {
rotate(length);
push(word, 1);
}
}
}
}
public static void rotate(int position) {
char[] charstring = new char[100];
for (int j = 0; j < word.length(); j++)
charstring[j] = word.charAt(j);
int startpos = strlength - position;
char temp = charstring[startpos];
for (int i = startpos; i < strlength - 1; i++) {
charstring[i] = charstring[i + 1];
}
charstring[strlength - 1] = temp;
word = new String(charstring).trim();
}
public static void display() {
int top;
if (top1 > -1) {
while (top1 > -1)
System.out.println(stringArray1[top1--]);
} else {
while (top2 > -1)
System.out.println(stringArray2[top2--]);
}
}
}
Another simple way is to loop through the string, pick the character that is not used yet and put it to a buffer, continue the loop till the buffer size equals to the string length. I like this back tracking solution better because:
Easy to understand
Easy to avoid duplication
The output is sorted
Here is the java code:
List<String> permute(String str) {
if (str == null) {
return null;
}
char[] chars = str.toCharArray();
boolean[] used = new boolean[chars.length];
List<String> res = new ArrayList<String>();
StringBuilder sb = new StringBuilder();
Arrays.sort(chars);
helper(chars, used, sb, res);
return res;
}
void helper(char[] chars, boolean[] used, StringBuilder sb, List<String> res) {
if (sb.length() == chars.length) {
res.add(sb.toString());
return;
}
for (int i = 0; i < chars.length; i++) {
// avoid duplicates
if (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]) {
continue;
}
// pick the character that has not used yet
if (!used[i]) {
used[i] = true;
sb.append(chars[i]);
helper(chars, used, sb, res);
// back tracking
sb.deleteCharAt(sb.length() - 1);
used[i] = false;
}
}
}
Input str: 1231
Output list: {1123, 1132, 1213, 1231, 1312, 1321, 2113, 2131, 2311, 3112, 3121, 3211}
Noticed that the output is sorted, and there is no duplicate result.
Recursion is not necessary, even you can calculate any permutation directly, this solution uses generics to permute any array.
Here is a good information about this algorihtm.
For C# developers here is more useful implementation.
public static void main(String[] args) {
String word = "12345";
Character[] array = ArrayUtils.toObject(word.toCharArray());
long[] factorials = Permutation.getFactorials(array.length + 1);
for (long i = 0; i < factorials[array.length]; i++) {
Character[] permutation = Permutation.<Character>getPermutation(i, array, factorials);
printPermutation(permutation);
}
}
private static void printPermutation(Character[] permutation) {
for (int i = 0; i < permutation.length; i++) {
System.out.print(permutation[i]);
}
System.out.println();
}
This algorithm has O(N) time and space complexity to calculate each permutation.
public class Permutation {
public static <T> T[] getPermutation(long permutationNumber, T[] array, long[] factorials) {
int[] sequence = generateSequence(permutationNumber, array.length - 1, factorials);
T[] permutation = generatePermutation(array, sequence);
return permutation;
}
public static <T> T[] generatePermutation(T[] array, int[] sequence) {
T[] clone = array.clone();
for (int i = 0; i < clone.length - 1; i++) {
swap(clone, i, i + sequence[i]);
}
return clone;
}
private static int[] generateSequence(long permutationNumber, int size, long[] factorials) {
int[] sequence = new int[size];
for (int j = 0; j < sequence.length; j++) {
long factorial = factorials[sequence.length - j];
sequence[j] = (int) (permutationNumber / factorial);
permutationNumber = (int) (permutationNumber % factorial);
}
return sequence;
}
private static <T> void swap(T[] array, int i, int j) {
T t = array[i];
array[i] = array[j];
array[j] = t;
}
public static long[] getFactorials(int length) {
long[] factorials = new long[length];
long factor = 1;
for (int i = 0; i < length; i++) {
factor *= i <= 1 ? 1 : i;
factorials[i] = factor;
}
return factorials;
}
}
My implementation based on Mark Byers's description above:
static Set<String> permutations(String str){
if (str.isEmpty()){
return Collections.singleton(str);
}else{
Set <String> set = new HashSet<>();
for (int i=0; i<str.length(); i++)
for (String s : permutations(str.substring(0, i) + str.substring(i+1)))
set.add(str.charAt(i) + s);
return set;
}
}
Permutation of String:
public static void main(String args[]) {
permu(0,"ABCD");
}
static void permu(int fixed,String s) {
char[] chr=s.toCharArray();
if(fixed==s.length())
System.out.println(s);
for(int i=fixed;i<s.length();i++) {
char c=chr[i];
chr[i]=chr[fixed];
chr[fixed]=c;
permu(fixed+1,new String(chr));
}
}
Here is another simpler method of doing Permutation of a string.
public class Solution4 {
public static void main(String[] args) {
String a = "Protijayi";
per(a, 0);
}
static void per(String a , int start ) {
//bse case;
if(a.length() == start) {System.out.println(a);}
char[] ca = a.toCharArray();
//swap
for (int i = start; i < ca.length; i++) {
char t = ca[i];
ca[i] = ca[start];
ca[start] = t;
per(new String(ca),start+1);
}
}//per
}
A java implementation to print all the permutations of a given string considering duplicate characters and prints only unique characters is as follow:
import java.util.Set;
import java.util.HashSet;
public class PrintAllPermutations2
{
public static void main(String[] args)
{
String str = "AAC";
PrintAllPermutations2 permutation = new PrintAllPermutations2();
Set<String> uniqueStrings = new HashSet<>();
permutation.permute("", str, uniqueStrings);
}
void permute(String prefixString, String s, Set<String> set)
{
int n = s.length();
if(n == 0)
{
if(!set.contains(prefixString))
{
System.out.println(prefixString);
set.add(prefixString);
}
}
else
{
for(int i=0; i<n; i++)
{
permute(prefixString + s.charAt(i), s.substring(0,i) + s.substring(i+1,n), set);
}
}
}
}
String permutaions using Es6
Using reduce() method
const permutations = str => {
if (str.length <= 2)
return str.length === 2 ? [str, str[1] + str[0]] : [str];
return str
.split('')
.reduce(
(acc, letter, index) =>
acc.concat(permutations(str.slice(0, index) + str.slice(index + 1)).map(val => letter + val)),
[]
);
};
console.log(permutations('STR'));
In case anyone wants to generate the permutations to do something with them, instead of just printing them via a void method:
static List<int[]> permutations(int n) {
class Perm {
private final List<int[]> permutations = new ArrayList<>();
private void perm(int[] array, int step) {
if (step == 1) permutations.add(array.clone());
else for (int i = 0; i < step; i++) {
perm(array, step - 1);
int j = (step % 2 == 0) ? i : 0;
swap(array, step - 1, j);
}
}
private void swap(int[] array, int i, int j) {
int buffer = array[i];
array[i] = array[j];
array[j] = buffer;
}
}
int[] nVector = new int[n];
for (int i = 0; i < n; i++) nVector [i] = i;
Perm perm = new Perm();
perm.perm(nVector, n);
return perm.permutations;
}

How do I display the frequency of each letter in a string?

I want my code to display each letters frequency but instead, I'm getting an ArrayIndexOutOfBoundsException. I'm having trouble spotting what I did wrong.
How can I rectify this?
Here's my code:
public static void solution(String s) {
char[] c = s.toCharArray();
int j = 0, i = 0, counter = 0;
for(i = 0; i < c.length; i++) {
counter = 0;
for(j = 0; j < c.length; j++) {
if(c[j] == c[i]) {
counter++;
}
}
}
System.out.println("The letter " + c[j] + " appears " + counter + " times");
}
public static void main(String args[]) {
String s = "abaababcdelkm";
solution(s);
}
You are accessing c[j] outside the loop you've finished: its value is equal to c.length which isn't a correct index.
You need to move the println statement one line up and change c[j] to c[i].
I would rewrite it with Stream API:
s.chars()
.mapToObj(c -> (char)c)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.forEach((k, v) -> System.out.format("The letter %c appears %d times\n", k, v));
After finishing the inner loop, j is equal to the length of c. Hence, when you are calling c[j] after the outer loop, you get this error.
To correct this, you can remove the print, and call another print to get the proper result. Although, you will get the repetitive print for each repeated character. If you want to prevent this, you can add your result in a hash map.
public static void solution(String s)
{
char[] c = s.toCharArray();
ArrayList<Character> countedChars = new ArrayList<Character>();
int j = 0, i = 0, counter = 0;
for (i = 0; i < c.length; i++)
{
if(countedChars.contains(c[i])){
continue;
}
counter = 0;
for (j = 0; j < c.length; j++)
{
if (c[j] == c[i])
{
counter++;
}
}
countedChars.add(c[i]);
System.out.println("The letter " + c[i] + " appears " + counter + " times");
}
}
public static void main(String args[])
{
String s = "abaababcdelkm";
solution(s);
}
This will do a lot better, but it would be even better if you check which letters you've already counted so they won't be counted multiple times
EDIT: Added simple example of what I mean
If you use Collections.frequency() properly you don't have to count each char.
Just create 2 lists: the 1st containing all the chars of string and the 2nd all the distinct chars of the string:
public static void solution(String s) {
ArrayList<Character> list = new ArrayList<Character>();
ArrayList<Character> listDistinct = new ArrayList<Character>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
list.add(c);
if (!listDistinct.contains(c))
listDistinct.add(c);
}
for (char c : listDistinct) {
int freq = Collections.frequency(list, c);
System.out.println("The letter " + c + " appears " + freq + " times");
}
}
You have multiple errors :
Your sysout should be into your first for loop
You search for the index 13 while printing the counter, which doesn't exists.
...
I would suggest you to use this How to count frequency of characters in a string?
Here is your code :
public static void solution(String s) {
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
Integer val = map.get(c);
if (val != null) {
map.put(c, new Integer(val + 1));
}
else {
map.put(c, 1);
}
}
System.out.println(map.toString());
}
public static void main(String args[]) {
String s = "abaababcdelkm";
solution(s);
}
public static void printFrequencyOfChars(String str) {
if (str.length() == 1) {
System.out.printf("(" + "%s, 1)", str);
} else {
Map<Character, Integer> map = new LinkedHashMap<>();
char[] chars = str.toLowerCase().toCharArray();
for (char c : chars) {
map.merge(c, 1, Integer::sum);
}
for (Map.Entry<Character, Integer> m : map.entrySet()) {
System.out.printf("%s%d ", m.getKey(), m.getValue());
}
}
}

Count Occurrence of each letter in a loop and display with letter with the most number of occurences

I'm having trouble in using this code I found on the net. my goal is to count the number of times a letter show and display the letter with the most occurrence and if there are 2 or more letters that occurred at the same number of times then they will both show up.
This is my current output:
Current Output
Here is the code i found on the net and working with:
public void fcount(String str)
{
int[] occurence = new int[255];
// Scanner scanner = new Scanner(System.in);
// str = scanner.nextLine();
// optional to put eveyting in uppercase
str = str.toUpperCase();
// convert to char
char[] digit = str.toCharArray();
// count
for(int i = 0; i < digit.length; i++)
occurence[digit[i]]++;
// find max
int max = 0; // max value
char maxValue = 0; // max index
for(int i = 0; i < occurence.length; i++)
{
// new max ?
if(occurence[i] > max) {
max = occurence[i];
maxValue = (char) i;
}
}
// result
System.out.println("Character used " + max + " times is: " + (char) maxValue);
// return "";
}
And Here is the the loop where i'm using it:
public void calpha()
{
char startUpper = 'A';
String cones = null;
for (int i = 0; i < 12; i++) {
cones = Character.toString(startUpper);
System.out.println(startUpper);
}
fcount(cones);
}
There is an error in you loop:
cones = Character.toString(startUpper);
You are just re-assigning the value of cones, so fcount receives a string containing only the last character.
A solution is
cones += Character.toString(startUpper);
You have an issue in your int[] occurence = new int[255]; statement and usage: occurence[digit[i]]++ may lead to IndexOutOfBoundsException since char type is up to 2^16
Your code can not deal with non-ANSII characters. Mine does.
import java.util.*;
class Problem {
public static void main(String args[]) {
final String input = "I see trees outside of my window.".replace(" ", "");
final List<Character> chars = new ArrayList<>(input.length());
for (final char c : input.toCharArray()) {
chars.add(c);
}
int maxFreq = 0;
final Set<Character> mostFrequentChars = new HashSet<>();
for(final char c : chars) {
final int freq = Collections.frequency(chars, c);
if (freq > maxFreq) {
mostFrequentChars.clear();
mostFrequentChars.add(c);
maxFreq = freq;
}
else {
if (freq == maxFreq) {
mostFrequentChars.add(c);
}
}
}
for (Character c : mostFrequentChars) {
System.out.println(c);
}
}
}
Try this code:
public static void main(String[] args) throws IOException {
char startUpper = 'A';
String cones = "";
for (int i = 0; i < 12; i++) {
cones += Character.toString(startUpper);
System.out.println(startUpper);
}
fcount(cones);
}
public static void fcount(String str) {
HashMap<Character, Integer> hashMap = new HashMap<Character, Integer>();
HashSet<Character> letters = new HashSet<Character>();
str = str.toUpperCase();
//Assume that string str minimium has 1 char
int max = 1;
for (int i = 0; i < str.length(); i++) {
int newValue = 1;
if (hashMap.containsKey(str.charAt(i))) {
newValue = hashMap.get(str.charAt(i)) + 1;
hashMap.put(str.charAt(i), newValue);
if (newValue>=max) {
max = newValue;
letters.add(str.charAt(i));
}
} else {
hashMap.put(str.charAt(i), newValue);
}
}
System.out.println("Character used " + max + " times is: " + Arrays.toString(letters.toArray()));
// return "";
}

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

Turn String aaaabbbbddd into a4b4d3

I'm trying to get a head start on practicing interview questions and I came across this one:
Turn String aaaabbbbddd into a4b4d3
You would basically want to convert the existing string into a string with each unique character occurrence and the number of times the character occurs.
This is my solution but I think it could be refined into something more elegant:
String s = "aaaabbbbddd";
String modified = "";
int len = s.length();
char[] c = s.toCharArray();
int count = 0;
for (int i = 0; i < len; i++) {
count = 1;
for (int j = i + 1; j < len; j++) {
if (c[i] == ' ') {
break;
}
if (c[i] == c[j]) {
count++;
c[j] = ' ';
}
}
if (c[i] != ' ') {
modified += c[i] + "" + count;
}
}
System.out.println(modified);
Does anyone have any other suggestions for a solution?
Employ a Map<Character, Integer> instead. Attempt to insert the new character into the map; if it already exists, then increment the value for that particular character.
Example:
Map<Character, Integer> countMap = new HashMap<>();
if(!countMap.containsKey('a')) {
countMap.put('a', 1);
} else {
countMap.put('a', countMap.get('a') + 1);
}
To add on to #Makoto's wonderful answer, in your situation, I would use a TreeMap instead of a HashMap. A TreeMap will allow you to print in alphabetical order. I have also added the print code to show you how it would look. It's fully runnable.
import java.util.Map;
import java.util.TreeMap;
public class MapPractice {
public static void main(String[] args) {
Map<Character, Integer> map = new TreeMap<>();
String blah = "aaaabbbbddd";
for (int i = 0; i < blah.length(); i++) {
char c = blah.charAt(i);
if (!map.containsKey(c)) {
map.put(c, 1);
} else {
map.put(c, (map.get(c) + 1));
}
}
for (Map.Entry<Character, Integer> entry: map.entrySet()) {
System.out.print(entry.getKey() + "" + entry.getValue());
}
}
}
Output with TreeMap: a4b4d3
Output with HashMap: d3b4a4
My version
StringBuilder sb = new StringBuilder();
int count = 0;
char last = s.charAt(0);
for(char c : s.toCharArray()) {
if (c == last) {
count++;
} else {
sb.append(last).append(count);
count = 0;
last = c;
}
}
if (count != 0) {
sb.append(last).append(count);
}
System.out.println(sb);
Here is the code that I tried.
I think you can't ask for a simpler code than this.
String s = "aaaabbbbddd", modified = "";
int len = s.length(), i = 0, j = i + 1, count = 1;
char[] c = s.toCharArray();
for (; i < len; i = j) {
count = 1;
for (; j < len; j++)
if (c[i] == c[j])
count++;
else {
j++;
break;
}
modified += c[i] + "" + count;
}
System.out.println(modified);
Hope you find this useful.
Method 1
Scanner scan = new Scanner(System.in);
System.out.print("Enter the string : ");
String str = scan.nextLine();
char c;
char[] charArr = str.toCharArray();
LinkedHashMap<Character,Integer> map = new LinkedHashMap<>();
for(int i = 0 ; i < charArr.length ; i++)
{
c = charArr[i];
if(map.containsKey(c) || map.containsKey(c-32))
{
if(c<97)
{
map.put(c,map.get(c)+1);
}
else
{
map.put(c,map.get(c)+1);
}
}
else
{
map.put((char)(c+32),1);
}
}
for(Map.Entry e : map.entrySet())
{
System.out.print(""+e.getKey()+""+e.getValue());
}
Method 2
Scanner scan = new Scanner(System.in);
System.out.print("Enter the string : ");
String str = scan.nextLine();
String newStr = "";
char c;
int count = 1;
char[] charArr = str.toCharArray();
for(int i = 0 ; i < charArr.length ; i++)
{
c = charArr[i];
if(i>0)
{
if ( c == charArr[i-1] || c == (char)(charArr[i-1]+32) )
{
count++;
}
else
{
if(c < 97)
{
newStr = newStr + count;
count = 1;
newStr = newStr + (char)(c+32);
}
else
{
newStr = newStr + count;
count = 1;
newStr = newStr + c;
}
}
}
else
{
if(c < 97)
{
newStr = newStr + (char)(c+32);
}
else
{
newStr = newStr + (char)c;
}
}
}
newStr = newStr + count;
System.out.print(newStr);
import java.io.*;
import java.util.*;
public class Main
{
public static void main(String[] args) {
Scanner S=new Scanner(System.in);
String in=S.next();
int count=1;
String out="";
for(int i=0;i<in.length()-1;){
out+=in.charAt(i+1);
count=1;
if(in.charAt(i)!=in.charAt(i+1)){
out+=count;
i++;
}else{
while(i<in.length()-1){
if(in.charAt(i)==in.charAt(i+1)){
count++;
i++;
}
else{
i++;
break;
}
}
out+=count;
}
}
System.out.println(out);
}
}
Here is my solution
public String countChars(String in){
LinkedHashMapMap<Character, Integer> map = new LinkedHashMap<Character, Integer>();
for(char c: in.toCharArray()){
Integer count = map.get(c);
if(count==null){
count=0;
}
count++;
map.put(c,count);
}
String out ="";
for(Entry<Character, Integer> e : map.entrySet()){
out += e.getKey()+e.getValue();
}
return out;
}

Categories