Arranging word to formpalindrome - java

Hello i´ve been trying to form palindromes from this input:
String[] text ={"ivcci", "oyotta", "cecarar","bbb","babbbb"};
getPalindrome(text);
and i need to rearrange all words in array to produce this output
civic
-1
rececar
bbb
bbabb
the method expects to receive an array of Strings like
public static String getPalindrome(String[] text){}
"returning -1 means i.g "oyotta" in array can´t form a palíndrome
i´ve been testing this code and it works but i.g "cecarar" is not producing "racecar", as im a bit new in java i used an String intead an array of Strings, can anybody help to write this code properly please?
Thanks a lot!
public static String getPalindrome(String s) {
if (s == null)
return null;
Map<Character, Integer> letters = new HashMap<Character, Integer>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (!letters.containsKey(c))
letters.put(c, 1);
else
letters.put(c, letters.get(c) + 1);
}
char[] result = new char[s.length()];
int i = 0, j = result.length - 1;
Character middle = null;
for (Entry<Character, Integer> e : letters.entrySet()) {
int val = e.getValue();
char c = e.getKey();
if (val % 2 != 0) {
if (middle == null && s.length() % 2 != 0) {
middle = c;
val--;
} else
return "-1";
}
for (int k = 0; k < val / 2; k++) {
result[i++] = c;
result[j--] = c;
}
}
if (middle != null)
result[result.length / 2] = middle;
return new String(result);
}

In order for a set of characters to be able to produce a palindrome, only one of the letters can be repeated an odd number of times, so you can first weed that out.
Without writing actual code for you, here is the algorithm I would use:
Create a map of characters to a counter. Possible to do int[] counts = new int[26];
Go through each character in the input string, and increment the count: ++counts[Character.toLower(c)-'a'];
Then go through each character, and see if its odd if (counts[i] & 1 != 0) { if (oddIndex != -1) { return -1; } oddIndex=i; } This will return -1 if there is two or more odd counts.
Then, you can create a StringBuilder, and start with the oddIndex in the middle, if it exists.
Then go through the counts, and add count[i]/2 to the front and back of your string builder.
That'll give you a symmetric string from the original inputs.
Now, if you actually need words, then you'll have to have a dictionary of palindromes. You can actually preprocess all the palindromes to have a map of "sorted character string"=>"palindrome"
class PalindromeChecker
{
final Map<String, String> palindromes = new HashMap<String, String>();
public PalindromeChecker(Iterable<String> allPalindromes) {
for (String palindrome: allPalindromes) {
char[] chars = palindrome.getChars();
Arrays.sort(chars);
palindromes.put(String.valueOf(chars), palindromes);
}
}
public String getPalindrome(String input) {
char[] chars = input.getChars();
Arrays.sort(chars);
return palindromes.get(String.valueOf(chars));
}
}

As other users pointed out, a string can be rearranged as a palindrome only if there is at most one character that appears an odd number of times.
Once you have confirmed that a string can be converted to a palindrome, you can construct the palindrome as follows (this is just one of many methods of course):
place at the sides of the string all the pairs of characters that you can get
place at the middle of the string the single character that is left out, in case there is such a character.
Example:
public class Palindromes {
public static void main(String[] args) {
String[] text = {"ivcci", "oyotta", "cecarar","bbb","babbbb"};
for(String str : text){
evaluatePalindrome(str);
}
}
private static void evaluatePalindrome(String str){
PalindromeCandidate pc = new PalindromeCandidate(str);
if(pc.isPalindrome()){
System.out.println(pc.getPalindrome());
} else {
System.out.println("-1");
}
}
}
public class PalindromeCandidate {
private final CharacterCount characterCount;
public PalindromeCandidate(String originalString) {
this.characterCount = new CharacterCount(originalString);
}
public boolean isPalindrome(){
Collection<Integer> counts = characterCount.asMap().values();
int oddCountOccurrences = 0;
for(Integer count : counts){
oddCountOccurrences += (count%2);
}
return (oddCountOccurrences <= 1);
}
public String getPalindrome(){
if(!isPalindrome()){
throw new RuntimeException("Cannot be rearranged as a palindrome.");
}
Map<Character, Integer> counts = characterCount.asMap();
StringBuilder leftSide = new StringBuilder();
StringBuilder middle = new StringBuilder();
for(Character ch : counts.keySet()){
int occurrences = counts.get(ch);
while(occurrences > 1){
leftSide.append(ch);
occurrences -= 2;
}
if(occurrences > 0){
middle.append(ch);
}
}
StringBuilder rightSide = new StringBuilder(leftSide).reverse();
return leftSide.append(middle).append(rightSide).toString();
}
}
/**
* Thin wrapper around a Map<Character, Integer>. Used for counting occurences
* of characters.
*/
public class CharacterCount {
private final Map<Character, Integer> map;
public CharacterCount(String str) {
this.map = new HashMap<>();
for(Character ch : str.toCharArray()){
increment(ch);
}
}
private void increment(Character ch){
this.map.put(ch, getCount(ch) + 1);
}
private Integer getCount(Character ch){
if(map.containsKey(ch)){
return map.get(ch);
} else {
return 0;
}
}
public Map<Character, Integer> asMap(){
return new HashMap<>(map);
}
}

Related

Anagrams in java

package intials;
public class Anagrams {
public static void main(String[] args) {
String a = "cat";
String b = "act";
boolean isAnagram = false;
for (int i = 0; i < a.length(); i++) {
char c = a.charAt(i);
isAnagram = false;
for (int j = 0; j < b.length(); j++) {
if (b.charAt(j) == c) {
isAnagram = true;
break;
}
}
if (!isAnagram) {
break;
}
}
if (isAnagram) {
System.out.println("is anagram");
} else {
System.out.println("is not anagram");
}
}
}
Please tell me what is wrong in this code.
Also tell me what should be the changes should I make
A easy way to check if two words are anagram is to transform them in array, sort them and compare.
public boolean areAnagram(string str1, string str2)
{
// Transform strings in arrays
String[] arr1 = str1.split("");
String[] arr2 = str2.split("");
// Check if they have the same length
if (arr1.length != arr2.length)
return false;
// Sort array
Arrays.sort(arr1);
Arrays.sort(arr2);
// Compare value
for (int i = 0; i < arr1.length; i++)
if (arr1[i] != arr2[i])
return false;
return true;
}
boolean test = areAnagram("toto", "otot");
This is comparatively better for large characters range :
static boolean isAnagram(String text1, String text2){
if (text1.length() != text2.length())
return false;
// If you want to ignore case sensitivity of characters
text1 = text1.toLowerCase();
text2 = text2.toLowerCase();
Set<Character> set1 = new HashSet();
Set<Character> set2 = new HashSet();
for (int i = 0; i < text1.length(); i++) {
set1.add(text1.charAt(i));
set2.add(text2.charAt(i));
}
return set1.equals(set2);
}
First, the anagrams should have equal lengths, if this condition is not met, the words are not anagrams.
Next, as mentioned in the comments, not only the characters but their frequencies should be compared, that is, a map Map<Character, Integer> needs to be created containing frequency of each character in a string.
For one string the frequencies may be counted with + sign, and for the other with - sign. If all values in the map are 0, the words are anagrams.
The implementation may look as follows (using Map::merge to calculate frequencies and Stream::allMatch to detect the anagram):
public static boolean isAnagram(String a, String b) {
if (a.length() != b.length()) {
return false;
}
Map<Character, Integer> frequencies = new HashMap<>();
for (int i = 0, n = a.length(); i < n; i++) {
frequencies.merge(Character.toLowerCase(a.charAt(i)), 1, Integer::sum);
frequencies.merge(Character.toLowerCase(b.charAt(i)), -1, Integer::sum);
}
return frequencies.values().stream().allMatch(x -> x == 0);
}
Tests
String[][] tests = {
{"act", "tact"},
{"acta", "tact"},
{"Raca", "arca"}
};
for(String[] t : tests) {
System.out.printf("Are '%s' and '%s' anagrams? %s%n", t[0], t[1], isAnagram(t[0], t[1]));
}
Output
Are 'act' and 'tact' anagrams? false
Are 'acta' and 'tact' anagrams? false
Are 'Raca' and 'arca' anagrams? true
This solution is faster with the time complexity of O(n). However, it needs extra space for the counting array. At 256 integers, for ASCII that's not too bad. But increasing CHARACTER_RANGE to support multiple-byte character sets such as UTF-8, this would become very memory hungry. Therefore, it's only really practical when the number of possible characters is in a small range.
class Anagram {
static int CHARACTER_RANGE= 256;
static boolean isAnagram(String text1, String text2){
if (text1.length() != text2.length())
return false;
// if want to consider case sensitivity of char
//char str1[] = text1.toCharArray();
//char str2[] = text2.toCharArray();
// if don't want to consider case sensitivity of char
char str1[] = text1.toLowerCase().toCharArray();
char str2[] = text2.toLowerCase().toCharArray();
int count1[] = new int[CHARACTER_RANGE];
Arrays.fill(count1, 0);
int count2[] = new int[CHARACTER_RANGE];
Arrays.fill(count2, 0);
int i;
for (i = 0; i < str1.length && i < str2.length; i++) {
count1[str1[i]]++;
count2[str2[i]]++;
}
for (i = 0; i < CHARACTER_RANGE; i++)
if (count1[i] != count2[i])
return false;
return true;
}
}

Splitting this string to get the max count to a corresponding character

I am currently implementing Run Length Encoding for text compression and my algorithm does return Strings of the following form:
Let's say we have a string as input
"AAAAABBBBCCCCCCCC"
then my algorithm returns
"1A2A3A4A5A1B2B3B4B1C2C3C4C5C6C7C8C"
Now I want to apply Java String split to solve this, because I want to get the highest number corresponding to character. For our example it would be
"5A4B8C"
My function can be seen below
public String getStrfinal(){
String result = "";
int counter = 1;
StringBuilder sb = new StringBuilder();
sb.append("");
for (int i=0;i<str.length()-1;i++) {
char c = str.charAt(i);
if (str.charAt(i)==str.charAt(i+1)) {
counter++;
sb.append(counter);
sb.append(c);
}
else {
counter = 1;
continue;
}
}
result = sb.toString();
return result;
}
public static String getStrfinal(){
StringBuilder sb = new StringBuilder();
char last = 0;
int count = 0;
for(int i = 0; i < str.length(); i++) {
if(i > 0 && last != str.charAt(i)) {
sb.append(count + "" + last);
last = 0;
count = 1;
}
else {
count++;
}
last = str.charAt(i);
}
sb.append(count + "" + last);
return sb.toString();
}
Here is one possible solution. It starts with the raw string and simply iterates thru the string.
public static void main(String[] args) {
String input = "AAAABBBCCCCCCCDDDEAAFBBCD";
int index = 0;
StringBuilder sb = new StringBuilder();
while (index < input.length()) {
int count = 0;
char c = input.charAt(index);
for (; index < input.length(); index++) {
if (c != input.charAt(index)) {
count++;
}
else {
break;
}
}
sb.append(Integer.toString(count));
sb.append(c);
count = 0;
}
System.out.println(sb.toString());
}
But one problem with this method and others is what happens if there are digits in the text? For example. What if the string is AAABB999222AAA which would compress to 3A2B39323A. That could also mean AAABB followed by 39 3's and 23 A's
Instead of string Buffer you can use a map it will be much easier and clean to do so.
public static void main(String[] args) {
String input = "AAAAABBBBCCCCCCCCAAABBBDDCCCC";
int counter=1;
for(int i=1; i<input.length(); i++) {
if(input.charAt(i-1)==input.charAt(i)) {
counter=counter+1;
}else if(input.charAt(i-1)!=input.charAt(i)){
System.out.print(counter+Character.toString(input.charAt(i-1)));
counter=1;
}if(i==input.length()-1){
System.out.print(counter+Character.toString(input.charAt(i)));
}
}
}
This will gives
5A4B8C3A3B2D4C
UPDATES
I Agree with #WJS if the string contains number the out put becomes messy
hence if the System.out in above code will be exchange with below i.e.
System.out.print(Character.toString(input.charAt(i-1))+"="+counter+" ");
then for input like
AAAAABBBBCCCCCCCCAAABBBDD556677CCCCz
we get out put as below
A=5 B=4 C=8 A=3 B=3 D=2 5=2 6=2 7=2 C=4 z=1
This is one of the possible solutions to your question. We can use a LinkedHashMap data structure which is similar to HashMap but it also maintains the order. So, we can traverse the string and store the occurrence of each character as Key-value pair into the map and retrieve easily with its maximum occurrence.
public String getStrFinal(String str){
if(str==null || str.length()==0) return str;
LinkedHashMap<Character,Integer> map = new LinkedHashMap<>();
StringBuilder sb=new StringBuilder(); // to store the final string
for(char ch:str.toCharArray()){
map.put(ch,map.getOrDefault(ch,0)+1); // put the count for each character
}
for(Map.Entry<Character,Integer> entry:map.entrySet()){ // iterate the map again and append each character's occurence into stringbuilder
sb.append(entry.getValue());
sb.append(entry.getKey());
}
System.out.println("String = " + sb.toString()); // here you go, we got the final string
return sb.toString();
}

Algorithm translate a number to String [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I need to design an algorithm where each number is encoded to an alphabet, for example:
1=A, 2=B, 3=C...26=Z
Given a set of numbers, I have to translate them to a combination of strings. For example:
123 can be translated to - ABC(123), AW(1 23) and LC(12 3)
Write an algorithm to find the combinations for number - 123123123.
Now here is what I wrote and I find it inefficient because of multiple "for" loops. Is there any better way I can rewrite this algorithm?
public class ValidCombinations {
Map<Integer, String> mapping = new HashMap<Integer, String>();
public void run() {
String s = "123123123";
/*Convert String to int[]*/
char[] cArray = s.toCharArray();
int[] input = new int[cArray.length];
for (int i=0; i<cArray.length; i++) {
input[i] = Character.getNumericValue(cArray[i]);
}
Set<String> output = new HashSet<String>();
for (int i='A'; i<='Z'; i++) {
mapping.put(i - 'A' + 1, String.valueOf((char)i));
}
for (int i=0; i<input.length; i++) {
if (mapping.containsKey(input[i])) {
output.add(precombine(i, input) + mapping.get(input[i]) + postcombine(i, input));
if (i+1<input.length) {
if (mapping.containsKey(input[i]*10 + input[i+1])) {
output.add(precombine(i, input) + mapping.get(input[i]*10 + input[i+1]) + postcombine(i+1, input));
}
}
}
}
System.out.println(output);
}
public String precombine(int i, int[] input) {
String residue="";
for (int m=0; m<i; m++) {
residue += mapping.get(input[m]);
}
return residue;
}
public String postcombine(int i, int[] input) {
String residue="";
for (int k=i+1; k<input.length; k++) {
residue += mapping.get(input[k]);
}
return residue;
}
public static void main(String[] args) {
ValidCombinations v = new ValidCombinations();
v.run();
}
}
For '123' - [ABC, AW, LC]
For '123123123' - [LCABCABC, AWABCABC, ABCAWABC, ABCLCABC, ABCABCLC, ABCABCABC, ABCABCAW]
This problem is crying out for recursion. Here's a quick and dirty implementation that takes the input "number" in as a string and uses substring() to consume the digits. You could adapt it to use numerical methods to get the first (or first two) decimal digits from an integer if you prefer.
If you choose to work directly from an int, it would probably be easier to start at the end (working with the least-significant-digits) than at the beginning -- lastDigit = number % 10; otherDigits = number / 10
public List<String> encodings(String number) {
List<String> out = new ArrayList<>();
addEncodings("", number, out);
return out;
}
private void addEncodings(String prefix, String number, List<String> out) {
if (number.length() == 0) {
out.add(prefix);
} else {
addParsingNDigits(1, prefix, number, out);
addParsingNDigits(2, prefix, number, out);
}
}
private void addParsingNDigits(int digits, String prefix, String number, List<String> out) {
if (number.length() >= digits) {
char encodedChar = parseChars(number, digits);
if (encodedChar >= 'A' && encodedChar <= 'Z') {
addEncodings(prefix + encodedChar, number.substring(digits), out);
}
}
}
private char parseChars(String number, int length) {
int intVal = Integer.parseInt(number.substring(0, length));
return (char) ('A' + intVal - 1);
}
I don't think your solution will find all possible encodings -- I think you need some sort of stack to solve it. The solution above implicitly uses the execution stack, because of recursive method calls. Another solution could explicitly place objects representing "todo" calculations onto a stack data structure in the heap:
private static class StackItem {
public StackItem(String prefix, String number) {
this.prefix = prefix;
this.number = number;
}
public String prefix;
public String number;
}
public List<String> encodings(String number) {
List<String> results = new ArrayList<>();
Stack<StackItem> stack = new Stack<>();
stack.push(new StackItem("", number));
while (!stack.isEmpty()) {
StackItem current = stack.pop();
if (current.number.equals("")) {
results.add(current.prefix);
} else {
addToStackTakingNChars(2, current, stack);
addToStackTakingNChars(1, current, stack);
}
}
return results;
}
private void addToStackTakingNChars(int n, StackItem current, Stack<StackItem> stack) {
if (current.number.length() >= n) {
char c = parseChars(current.number, n);
if (c >= 'A' && c <= 'Z') {
stack.push(new StackItem(current.prefix + c, current.number.substring(n)));
}
}
}
Although "println debugging" is generally a bad habit, it would probably be a good learning exercise to run these examples with some println()s to observe how it works.
I think you could split the String in the middle (recursively), search for all combinations in both substrings and build the cross product. To not miss any combinations we have to also build the cross product for the two substrings you get by splitting in the middle with an offset of one. Something like this:
private static int[] values;
public static final Set<String> solve(String s) {
values = new int[s.length()];
for (int i = 0; i < values.length; i++)
values[i] = s.charAt(i) - '0';
return solve(0, values.length);
}
private static final Set<String> solve(int start, int len) {
Set<String> ret = new HashSet<>();
if (len == 1) {
ret.add("" + ((char)(values[start] - 1 + 'A')));
} else if (len == 2) {
ret.add("" + ((char)(values[start] - 1 + 'A')) +
((char)(values[start + 1] - 1 + 'A')));
int n = values[start] * 10 + values[start + 1];
if (n <= 26)
ret.add("" + ((char)(n - 1 + 'A')));
} else {
int next = start + len / 2;
cross(solve(start, next - start), solve(next, start + len - next), ret);
cross(solve(start, next - start + 1), solve(next + 1, start + len - next - 1), ret);
}
return ret;
}
private static final void cross(Set<String> a, Set<String> b, Set<String> target) {
for (Iterator<String> itr = a.iterator(); itr.hasNext();) {
String s = itr.next();
for (Iterator<String> itr2 = b.iterator(); itr2.hasNext();) {
target.add(s + itr2.next());
}
}
}
Btw. the solution for "123123123" are the following 27 strings: LCABCAW, LCABCLC, ABCLCABC, ABCLCAW, ABCAWLC, AWLCABC, ABCAWAW, ABCAWABC, ABCLCLC, ABCABCABC, LCAWLC, LCAWAW, AWABCLC, LCAWABC, AWABCAW, LCLCAW, AWABCABC, LCLCLC, LCLCABC, LCABCABC, AWAWLC, AWAWABC, AWAWAW, ABCABCLC, ABCABCAW, AWLCAW, AWLCLC.
Why not just use the ascii value?
All you would need to do would be to convert the number to a String Integer.toString(num) and then run a for-loop through the .length() of the String and pull the .charAt(i) from the String convert that back to an int and then add 16 to it. Then you would just need to cast to a char. like so:
int a = 123;
String str = Integer.toString(a);
char[] chars = new char[str.length()];
for(int i=0,n=str.length();i<n;i++){
chars[i] = (char)(str.charAt(i)+16);
}
String message = String.valueOf(chars);
This problem can be done in o(fib(n+2)) time with a standard DP algorithm.
We have exactly n sub problems and button up we can solve each problem in o(fib(i)) time.
Summing the series gives fib (n+2).
If you consider the question carefullly you see that it is a fibunacci series.
I took a standart code and just changed it a bit to fit our conditions.
The space is obviously bound to the size of all solutions o(fib(n)).
Consider this code:
Map<Integer, String> mapping = new HashMap<Integer, String>();
List<String > iterative_fib_sequence(int input) {
int length = Math.floor(Math.log10(Math.abs(input))) + 1;
if (length <= 1)
{
if (length==0)
{
return "";
}
else//input is a-j
{
return mapping.get(input);
}
}
List<String> b = new List<String>();
List<String> a = new List<String>(mapping.get(input.substring(0,0));
List<String> c = new List<String>();
for (int i = 1; i < length; ++i)
{
int dig2Prefix = input.substring(i-1, i); //Get a letter with 2 digit (k-z)
if (mapping.contains(dig2Prefix))
{
String word2Prefix = mapping.get(dig2Prefix);
foreach (String s in b)
{
c.Add(s.append(word2Prefix));
}
}
int dig1Prefix = input.substring(i, i); //Get a letter with 1 digit (a-j)
String word1Prefix = mapping.get(dig1Prefix);
foreach (String s in a)
{
c.Add(s.append(word1Prefix));
}
b = a;
a = c;
c = new List<String>();
}
return a;
}

String sort descending order using java based on number of times character repeated

Here i have two strings that prints each character occurred how many times but i want that result in descending order.
public static void main(String[] args) {
TreeMap tm = new TreeMap();
String s = "ajklfajdlkfajsdklfjalljaklsdfjaklsdjf";
int[] counts = new int[128];
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch < 128) {
counts[ch]++;
} else {
System.out.println("out of range");
}
}
for (char c = 0; c < 128; c++) {
if (counts[c] != 0) {
tm.put(counts[c], c);
// System.out.println(c + " occured " + counts[c] + "times");
}
}
for(int i=0;i<tm.size();i++){
System.out.println(tm.get(i));
}
}
This code giving output as:null,null,null,s,d but i need ouput as: j l a f k d s .please guide me.
My answer is probably rather too like the others but I tried to keep to the spirit of the original code, they were just quicker at writing it.
package uk.co.puce4.charactercount;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.TreeSet;
public class CharacterCount {
public static void main(String[] args)
{
TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();
String s = "ajklfajdlkfajsdklfjalljaklsdfjaklsdjf";
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
int count = 1;
if(tm.containsKey(ch)){
count=tm.get(ch) + 1;
}
tm.put(ch, count);
}
TreeSet<CharItem> ts = new TreeSet<CharItem>();
Iterator<Character> it = tm.descendingKeySet().iterator();
while (it.hasNext()){
char ch = (char) it.next();
int count = tm.get(ch);
CharItem ci= new CharItem(ch, count);
ts.add(ci);
}
Iterator<CharItem> it2 = ts.iterator();
while(it2.hasNext()){
CharItem ci=it2.next();
System.out.println(ci.getCh() + " occured " + ci.getCount() + " times");
}
}
}
class CharItem implements Comparable<CharItem>{
private int count;
private char ch;
public CharItem(char c, int i){
count = i;
ch = c;
}
public char getCh() {
return this.ch;
}
public int getCount() {
return this.count;
}
#Override
public int compareTo(CharItem b) {
return b.count - this.count ;
}
}
There are a few problems with your approach:
You have a TreeMap that maps from char count to char. If multiple chars occur with the same count, you'll loose all but 1 of the chars.
You use the get method of TreeMap which means you're getting a char that have occurs i times instead of the value of the i-th entry in the map.
Here's an alternative for you:
Create a Container class that has fields for the char and the count.
Use TreeSet instead of TreeMap.
Code:
public class StringMap {
public static void main(String[] args) {
TreeSet<Container> ts = new TreeSet<>();
String s = "ajklfajdlkfajsdklfjalljaklsdfjaklsdjf";
int[] counts = new int[128];
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch < 128) {
counts[ch]++;
} else {
System.out.println("out of range");
}
}
for (char c = 0; c < 128; c++) {
if (counts[c] != 0) {
ts.add(new Container(c, counts[c]));
}
}
for (Container c : ts.descendingSet()) {
System.out.println(c.character);
}
}
}
class Container implements Comparable<Container> {
Container(char c, int count) {
this.character = c;
this.count = count;
}
char character;
int count;
#Override
public int compareTo(Container o) {
int result = Integer.compare(count, o.count);
return result == 0 ? Character.compare(character, o.character) : result;
}
#Override
public boolean equals(Object o) {
return o instanceof Container && ((Container)o).character == character;
}
}
Your approach is correct, but there are a few minor changes to make.
First you should explicitly state the types in generic collections:
TreeMap<Integer, Set<Characters>>
You want to map a count to a set of characters, since there may be two or more characters that appear the same number of times. Otherwise inserting into the map will overwrite the previous count -> char mapping.
Second you want to append your character to the end of a count -> char set if it already exists in the map. The reason is explained above.
Third, a TreeMap of Integers sorts ascending, so refer to the javadoc to see how to get a descending view of your TreeMap.
Java TreeMap
Finally, to iterate over a map, you can loop over the entrySet() or values(). Again, checking the javadocs is your best friend.
public static void main(String[] args) {
TreeMap<Integer, Set<Character>> tm = new TreeMap<Integer, Set<Character>>();
String s = "ajklfajdlkfajsdklfjalljaklsdfjaklsdjf";
int[] counts = new int[128];
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch < 128) {
counts[ch]++;
} else {
System.out.println("out of range");
}
}
for (char c = 0; c < 128; c++) {
if (counts[c] != 0) {
if (tm.contains(counts[c])) {
// Collision, there's already a character that appeared
// this number of times
tm.get(counts[c]).add(c);
} else {
Set<Character> charSet = new HashSet<Character>();
charSet.add(c);
tm.put(counts[c], charSet);
}
}
}
NavigableMap<Integer, Set<Character>> descendingMap = tm.descendingMap();
for (Map.Entry<Integer, Set<Character>> entry : descendingMap.entrySet()) {
//int count = entry.getKey();
Set<Character> chars = entry.getValue();
for (char c : chars) {
System.out.println(c);
}
}
}
}
Updated to use Set instead of list for efficiency.

Checking if two strings are permutations of each other

How to determine if two strings are permutations of each other
Sort the two strings's characters.
Compare the results to see if they're identical.
Edit:
The above method is reasonably efficient - O(n*log(n)) and, as others have shown, very easy to implement using the standard Java API. Even more efficient (but also more work) would be counting and comparing the occurrence of each character, using the char value as index into an array of counts.
I do not thing there is an efficient way to do it recursively. An inefficient way (O(n^2), worse if implemented straightforwardly) is this:
If both strings consist of one identical character, return true
Otherwise:
remove one character from the first string
Look through second string for occurrence of this character
If not present, return false
Otherwise, remove said character and apply algorithm recursively to the remainders of both strings.
To put #Michael Borgwardt's words in to code:
public boolean checkAnagram(String str1, String str2) {
if (str1.length() != str2.length())
return false;
char[] a = str1.toCharArray();
char[] b = str2.toCharArray();
Arrays.sort(a);
Arrays.sort(b);
return Arrays.equals(a, b);
}
Create a Hashmap with the characters of the first string as keys and the number of occurances as value; then go through the second string and for each character, look up the hash table and decrement the number if it is greater than zero. If you don't find an entry or if it is already 0, the strings are not a permutation of each other. Obviously, the string must have the same length.
Linear Time solution in HashMap. Traverse and put first String in HashMap, keep the count of each character. Traverse second String and if it is already in the hashmap decrease the count by 1. At the end if all character were in the string the value in hashmap will be 0 for each character.
public class StringPermutationofEachOther {
public static void main(String[] args)
{
String s1= "abc";
String s2 ="bbb";
System.out.println(perm(s1,s2));
}
public static boolean perm(String s1, String s2)
{ HashMap<Character, Integer> map = new HashMap<Character, Integer>();
int count =1;
if(s1.length()!=s2.length())
{
return false;
}
for(Character c: s1.toCharArray())
{
if(!map.containsKey(c))
map.put(c, count);
else
map.put(c, count+1);
}
for(Character c: s2.toCharArray())
{
if(!map.containsKey(c))
return false;
else
map.put(c, count-1);
}
for(Character c: map.keySet())
{
if(map.get(c)!=0)
return false;
}
return true;
}
}
You can try to use XOR, if one string is a permeation of the other, they should have essentially identical chars. The only difference is just the order of chars. Therefore using XOR trick can help you get rid of the order and focus only on the chars.
public static boolean isPermutation(String s1, String s2){
if (s1.length() != s2.length()) return false;
int checker = 0;
for(int i = 0; i < s1.length();i++ ){
checker ^= s1.charAt(i) ^ s2.charAt(i);
}
return checker == 0;
}
Sort the 2 strings by characters and compare if they're the same (O(n log n) time, O(n) space), or
Tally the character frequency of the 2 strings and compare if they're the same (O(n) time, O(n) space).
You might take a look at String.toCharArray and Arrays.sort
First you check the lengths (n), if they are not same, they cannot be permutations of each other. Now create two HashMap<Character, Integer>. Iterate over each string and put the number of times each character occur in the string. E.g. if the string is aaaaa, the map will have just one element with key a and value 5. Now check if the two maps are identical. This is an O(n) algorithm.
EDIT with code snippet :
boolean checkPermutation(String str1, String str2) {
char[] chars1 = str1.toCharArray();
char[] chars2 = str2.toCharArray();
Map<Character, Integer> map1 = new HashMap<Character, Integer>();
Map<Character, Integer> map2 = new HashMap<Character, Integer>();
for (char c : chars1) {
int occ = 1;
if (map1.containsKey(c) {
occ = map1.get(c);
occ++;
}
map1.put(c, occ);
}
// now do the same for chars2 and map2
if (map1.size() != map2.size()) {
return false;
}
for (char c : map1.keySet()) {
if (!map2.containsKey(c) || map1.get(c) != map2.get(c)) {
return false;
}
}
return true;
}
I'm working on a Java library that should simplify your task. You can re-implement this algorithm using only two method calls:
boolean arePermutationsOfSameString(String s1, String s2) {
s1 = $(s1).sort().join();
s2 = $(s2).sort().join();
return s1.equals(s2);
}
testcase
#Test
public void stringPermutationCheck() {
// true cases
assertThat(arePermutationsOfSameString("abc", "acb"), is(true));
assertThat(arePermutationsOfSameString("bac", "bca"), is(true));
assertThat(arePermutationsOfSameString("cab", "cba"), is(true));
// false cases
assertThat(arePermutationsOfSameString("cab", "acba"), is(false));
assertThat(arePermutationsOfSameString("cab", "acbb"), is(false));
// corner cases
assertThat(arePermutationsOfSameString("", ""), is(true));
assertThat(arePermutationsOfSameString("", null), is(true));
assertThat(arePermutationsOfSameString(null, ""), is(true));
assertThat(arePermutationsOfSameString(null, null), is(true));
}
PS
In the case you can clone the souces at bitbucket.
I did this, and it works well and quickly:
public static boolean isPermutation(String str1, String str2)
{
char[] x = str1.toCharArray();
char[] y = str2.toCharArray();
Arrays.sort(x);
Arrays.sort(y);
if(Arrays.equals(x, y))
return true;
return false;
}
public boolean isPermutationOfOther(String str, String other){
if(str == null || other == null)
return false;
if(str.length() != other.length())
return false;
Map<Character, Integer> characterCount = new HashMap<Character, Integer>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
int count = 1;
if(characterCount.containsKey(c)){
int k = characterCount.get(c);
count = count+k;
}
characterCount.put(c, count);
}
for (int i = 0; i < other.length(); i++) {
char c = other.charAt(i);
if(!characterCount.containsKey(c)){
return false;
}
int count = characterCount.get(c);
if(count == 1){
characterCount.remove(c);
}else{
characterCount.put(c, --count);
}
}
return characterCount.isEmpty();
}
Variation on other approaches but this one uses 2 int arrays to track the chars, no sorting, and you only need to do 1 for loop over the strings. The for loop I do over the int arrays to test the permutation is a constant, hence not part of N.
Memory is constant.
O(N) run time.
// run time N, no sorting, assume 256 ASCII char set
public static boolean isPermutation(String v1, String v2) {
int length1 = v1.length();
int length2 = v2.length();
if (length1 != length2)
return false;
int s1[] = new int[256];
int s2[] = new int[256];
for (int i = 0; i < length1; ++i) {
int charValue1 = v1.charAt(i);
int charValue2 = v2.charAt(i);
++s1[charValue1];
++s2[charValue2];
}
for (int i = 0; i < s1.length; ++i) {
if (s1[i] != s2[i])
return false;
}
return true;
}
}
Unit Tests
#Test
public void testIsPermutation_Not() {
assertFalse(Question3.isPermutation("abc", "bbb"));
}
#Test
public void testIsPermutation_Yes() {
assertTrue(Question3.isPermutation("abc", "cba"));
assertTrue(Question3.isPermutation("abcabcabcabc", "cbacbacbacba"));
}
If we do the initial length check, to determine if the two strings are of the same length or not,
public boolean checkIfPermutation(String str1, String str2) {
if(str1.length()!=str2.length()){
return false;
}
int str1_sum = getSumOfChars(str1);
int str2_sum = getSumOfChars(str2);
if (str1_sum == str2_sum) {
return true;
}
return false;
}
public int getSumOfChars(String str){
int sum = 0;
for (int i = 0; i < str.length(); i++) {
sum += str.charAt(i);
}
return sum;
}
The obligatory Guava one-liner:
boolean isAnagram(String s1, String s2) {
return ImmutableMultiset.copyOf(Chars.asList(s1.toCharArray())).equals(ImmutableMultiset.copyOf(Chars.asList(s2.toCharArray())));
}
(Just for fun. I don't recommend submitting this for your assignment.)
As you requested, here's a complete solution using recursion.
Now all you have to do is:
Figure out what language this is
Translate it to Java.
Good luck :-)
proc isAnagram(s1, s2);
return {s1, s2} = {''} or
(s2 /= '' and
(exists c = s1(i) |
s2(1) = c and
isAnagram(s1(1..i-1) + s1(i+1..), s2(2..))));
end isAnagram;
I did it using C#
bool Arepermutations(string string1, string string2)
{
char[] str1 = string1.ToCharArray();
char[] str2 = string2.ToCharArray();
if (str1.Length !=str2.Length)
return false;
Array.Sort(str1);
Array.Sort(str2);
if (str1.Where((t, i) => t!= str2[i]).Any())
{
return false;
}
return true;
}
public boolean permitation(String s,String t){
if(s.length() != t.length()){
return false;
}
int[] letters = new int[256];//Assumes that the character set is ASCII
char[] s_array = s.toCharArray();
for(char c:s_array){ /////count number of each char in s
letters[c]++;
}
for(int i=0;i<t.length();i++){
int c = (int)t.charAt(i);
if(--letters[c]<0){
return false;
}
}
return true;
}
import java.io.*;
public class permute
{
public static String sort(String s)
{
char[] str = s.toCharArray();
java.util.Arrays.sort(str);
return new String(str);
}
public static boolean permutation(String s,String t)
{
if(s.length()!=t.length())
{
return false;
}
return sort(s).equals(sort(t));
}
public static void main(String[] args) throws IOException
{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String string = null;
boolean x=true;
System.out.println("Input String:");
string = bf.readLine();
System.out.println("Input another String:");
String result = bf.readLine();
String resultant = sort(string);
if(x==permutation(result,resultant))
{
System.out.println("String"+" "+"("+result+")"+"is a permutation of String"+" "+"("+string+")");
}
else
{
System.out.println("Sorry No anagram found");
}
}
}
public class TwoStrgPermutation {
public int checkForUnique(String s1, String s2)
{
int[] array1 = new int[256];
int[] array2 = new int[256];
array1 = arrayStringCounter(array1,s1);
array2 = arrayStringCounter(array2,s2);
if(Arrays.equals(array1, array2))
return 0;
else
return 1;
}
public int[] arrayStringCounter(int[] array,String s)
{
int val;
for(int i=0;i<s.length();i++)
{
val = (int)s.charAt(i);
array[val]++;
}
return array;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
InputStreamReader in = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(in);
TwoStrgPermutation obj = new TwoStrgPermutation();
try {
String string1 = br.readLine();
String string2 = br.readLine();
int len1 = string1.length();
int len2 = string2.length();
if(len1==len2)
{
int result = obj.checkForUnique(string1,string2);
if (result == 0){
System.out.println("yes it is a permutation");
}
else if (result >0)
{
System.out.println("no it is not");
}
}
else
{
System.out.println("no it is not");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
>>>def isPermutation = lambda x, y: set([i for i in x]) == set([j for j in x])
>>>isPermutation("rasp", "spar")
>>>True
This is an O(N) solution, in which N is the length of the shorter string.
It has a disadvantage, which is that only ASCII characters are acceptable.
If we want better applicability, we may substitute a hash table for the int charNums[].
But it also means C wouldn't be a good choice, coz' there is no standard hash table implementation for C.
int is_permutation(char *s1, char *s2)
{
if ((NULL == s1) ||
(NULL == s2)) {
return false;
}
int static const
_capacity = 256; // Assumption
int
charNums[_capacity] = {0};
char
*cRef1 = s1,
*cRef2 = s2;
while ('\0' != *cRef1 && '\0' != *cRef2) {
charNums[*cRef1] += 1;
charNums[*cRef2] -= 1;
cRef1++;
cRef2++;
}
if ('\0' != *cRef1 || '\0' != *cRef2) {
return false;
}
for (int i = 0; i < _capacity; i++) {
if (0 != charNums[i]) {
return false;
}
}
return true;
}
Create two methods:
1. First method takes a string and returns a sorted string:
public String sort(String str) {
char char_set[] = str.toCharArray();
Arrays.sort(char_set);
return new String(char_set);
}
2. Second method takes two strings and return a boolean:
`public boolean sort(String x, String y) {
if (x.length() != y.length()) {
System.out.println("false");
return false;
}
System.out.println(sort(x).equals(sort(y)));
return sort(x).equals(sort(y));
}`
It can be done by using a Dictionary in C#. A basic implementation is like :
private static bool IsPermutation(string str1, string str2)
{
if (str1.Length != str2.Length)
return false;
var dictionary = new Dictionary<char, int>();
foreach(var x in str1)
{
if (dictionary.ContainsKey(x))
dictionary[x] += 1;
else
dictionary.Add(x, 1);
}
foreach (var y in str2)
{
if (dictionary.ContainsKey(y))
{
if (dictionary[y] > 0)
dictionary[y] -= 1;
else
return false;
}
else
return false;
}
foreach(var el in dictionary)
{
if (el.Value != 0)
return false;
}
return true;
}
Time Complexity is O(n), linear solution.
public static boolean isPermutation(String s1, String s2) {
if (s1.length() != s2.length()) {
return false;
}else if(s1.length()==0 ){
return true;
}
else if(s1.length()==1){
return s1.equals(s2);
}
char[] s = s1.toCharArray();
char[] t = s2.toCharArray();
for (int i = 0; i < s.length; i++) {
for (int j = 0; j < t.length; j++) {
if (s.length == s1.length() && (i == 0 && j == t.length - 1) && s[i] != t[j]) {
return false;
}
if (s[i] == t[j]) {
String ss = new String(s);
String tt = new String(t);
s = (ss.substring(0, i) + ss.substring(i + 1, s.length)).toCharArray();
t = (tt.substring(0, j) + tt.substring(j + 1, t.length)).toCharArray();
System.out.println(new String(s));
System.out.println(new String(t));
i = 0;
j = 0;
}
}
}
return s[0]==t[0] ;
}
This solution works for any charset. With an O(n) complexity.
The output for: isPermutation("The Big Bang Theory", "B B T Tehgiangyroeh")
he Big Bang Theory
B B Tehgiangyroeh
e Big Bang Theory
B B Tegiangyroeh
Big Bang Theory
B B Tgiangyroeh
Big Bang Theory
BB Tgiangyroeh
ig Bang Theory
B Tgiangyroeh
g Bang Theory
B Tgangyroeh
Bang Theory
B Tangyroeh
Bang Theory
B Tangyroeh
Bng Theory
B Tngyroeh
Bg Theory
B Tgyroeh
B Theory
B Tyroeh
BTheory
BTyroeh
Bheory
Byroeh
Beory
Byroe
Bory
Byro
Bry
Byr
By
By
B
B
true
Best Way to do this is by sorting the two strings first and then compare them. It's not the most efficient way but it's clean and is bound to the runtime of the sorting routine been used.
boolean arePermutation(String s1, String s2) {
if(s1.lenght() != s2.lenght()) {
return false;
}
return mySort(s1).equals(mySort(s2));
}
String mySort(String s) {
Char letters[] = s.toCharArray();
Arrays.sort(letters);
return new String(letters);
}
String str= "abcd";
String str1 ="dcazb";
int count=0;
char s[]= str.toCharArray();
char s1[]= str1.toCharArray();
for(char c:s)
{
count = count+(int)c ;
}
for(char c1:s1)
{
count=count-(int)c1;
}
if(count==0)
System.out.println("String are Anagram");
else
System.out.println("String are not Anagram");
}
Here is a simple program I wrote that gives the answer in O(n) for time complexity and O(1) for space complexity. It works by mapping every character to a prime number and then multiplying together all of the characters in the string's prime mappings together. If the two strings are permutations then they should have the same unique characters each with the same number of occurrences.
Here is some sample code that accomplishes this:
// maps keys to a corresponding unique prime
static Map<Integer, Integer> primes = generatePrimes(255); // use 255 for
// ASCII or the
// number of
// possible
// characters
public static boolean permutations(String s1, String s2) {
// both strings must be same length
if (s1.length() != s2.length())
return false;
// the corresponding primes for every char in both strings are multiplied together
int s1Product = 1;
int s2Product = 1;
for (char c : s1.toCharArray())
s1Product *= primes.get((int) c);
for (char c : s2.toCharArray())
s2Product *= primes.get((int) c);
return s1Product == s2Product;
}
private static Map<Integer, Integer> generatePrimes(int n) {
Map<Integer, Integer> primes = new HashMap<Integer, Integer>();
primes.put(0, 2);
for (int i = 2; primes.size() < n; i++) {
boolean divisible = false;
for (int v : primes.values()) {
if (i % v == 0) {
divisible = true;
break;
}
}
if (!divisible) {
primes.put(primes.size(), i);
System.out.println(i + " ");
}
}
return primes;
}
Based on the comment on this solution, https://stackoverflow.com/a/31709645/697935 here's that approach, revised.
private static boolean is_permutation(String s1, String s2) {
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
int count = 1;
if(s1.length()!=s2.length()) {
return false;
}
for(Character c: s1.toCharArray()) {
if(!map.containsKey(c)) {
map.put(c, 1);
}
else {
map.put(c, map.get(c) + 1);
}
}
for(Character c: s2.toCharArray()) {
if(!map.containsKey(c)) {
return false;
}
else {
map.put(c, map.get(c) - 1);
}
}
for(Character c: map.keySet()) {
if(map.get(c) != 0) { return false; }
}
return true;
}
bool is_permutation1(string str1, string str2) {
sort(str1.begin(), str1.end());
sort(str2.begin(), str2.end());
for (int i = 0; i < str1.length(); i++) {
if (str1[i] != str2[i]) {
return false;
}
}
return true;
}
I wanted to give a recursive solution for this problem as I did not find any answer which was recursive. I think that this code seems to be tough but if you'll try to understand it you'll see the beauty of this code. Recursion is sometimes hard to understand but good to use! This method returns all the permutations of the entered String 's' and keeps storing them in the array 'arr[]'. The value of 't' initially is blank "" .
import java.io.*;
class permute_compare2str
{
static String[] arr= new String [1200];
static int p=0;
void permutation(String s,String t)
{
if (s.length()==0)
{
arr[p++]=t;
return;
}
for(int i=0;i<s.length();i++)
permutation(s.substring(0,i)+s.substring(i+1),t+s.charAt(i));
}
public static void main(String kr[])throws IOException
{
int flag = 0;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter the first String:");
String str1 = br.readLine();
System.out.println("Enter the second String:");
String str2 = br.readLine();
new permute_compare2str().permutation(str1,"");
for(int i = 0; i < p; ++i)
{
if(arr[i].equals(str2))
{
flag = 1;
break;
}
}
if(flag == 1)
System.out.println("True");
else
{
System.out.println("False");
return;
}
}
}
One limitation that I can see is that the length of the array is fixed and so will not be able to return values for a large String value 's'. Please alter the same as per the requirements. There are other solutions to this problem as well.
I have shared this code because you can actually use this to get the permutations of a string printed directly without the array as well.
HERE:
void permutations(String s, String t)
{
if (s.length()==0)
{
System.out.print(t+" ");
return;
}
for(int i=0;i<s.length();i++)
permutations(s.substring(0,i)+s.substring(i+1),t+s.charAt(i));
}
Value of 's' is the string whose permutations is needed and value of 't' is again empty "".
Reference: Introduction to Programming in Java

Categories

Resources