How to generate random words in solidity based on a string of letters - random

I would like to make a word generation function based on the letters of the alphabet, but I don't know how to proceed. I would like to generate 12 words
string letters public = "abcdefghijklmnopqrstuvwxyz"
But I don't understand how I could proceed in solidity to generate
For numbers, I do this
pragma solidity ^0.8.0;
contract RandomNumbers{
function random(uint number) public view returns(uint){
return uint(keccak256(abi.encodePacked(block.timestamp,block.difficulty,
msg.sender))) % number;
}
}
But for words, I don't know how I could proceed

contract MiniTest {
string public letters = "abcdefghijklmnopqrstuvwxyz";
// I needed to add this to the random function to generate a different random number
uint counter =1;
// size is length of word
function randomString(uint size) public payable returns(string memory){
bytes memory randomWord=new bytes(size);
// since we have 26 letters
bytes memory chars = new bytes(26);
chars="abcdefghijklmnopqrstuvwxyz";
for (uint i=0;i<size;i++){
uint randomNumber=random(26);
// Index access for string is not possible
randomWord[i]=chars[randomNumber];
}
return string(randomWord);
}
function random(uint number) public payable returns(uint){
counter++;
return uint(keccak256(abi.encodePacked(block.timestamp,block.difficulty,
msg.sender,counter))) % number;
}
}
I slightly changed the random function because it was generating the same random number so the result for 5 characters was like "jjjjj".
string in solidity has no index property. so we have to work with bytes and then convert it to string
Here is the proof of work:

I just improved the answer of #Yilmaz to make the functions view only from payable.
There is an additional function called roll() which outputs true or false based on chance. The 101 within roll() can be altered to 10001 to make the odds down to 0.01% or you can make it dynamic by passing a parameter in place of 101.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract Random {
//Roll Chance
function roll(uint256 number) public view returns (bool) {
uint256 d = uint256(
keccak256(abi.encodePacked(block.difficulty, block.timestamp))
) % 101;
if (d <= number) return true;
return false;
}
//Random Number Generator
function random(uint256 number, uint256 counter)
public
view
returns (uint256)
{
return
uint256(
keccak256(
abi.encodePacked(
block.timestamp,
block.difficulty,
msg.sender,
counter
)
)
) % number;
}
//Random String Generator (Max length 14)
function randomString(uint256 length) public view returns (string memory) {
require(length <= 14, "Length cannot be greater than 14");
require(length >= 1, "Length cannot be Zero");
bytes memory randomWord = new bytes(length);
// since we have 62 Characters
bytes memory chars = new bytes(62);
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for (uint256 i = 0; i < length; i++) {
uint256 randomNumber = random(62, i);
// Index access for string is not possible
randomWord[i] = chars[randomNumber];
}
return string(randomWord);
}
}
I hope this Helps.

Related

Sum consecutive numbers in a String of integers

I need to write a function when given a String of integers, it returns a String of integers where all consecutive integers are replaced with the sum of those integers.
For example:
When given: String = "144404331" the function returns "40461". You might think it would be "1120461" however we need to continue the process until there are no consecutive digits.
My solution to this is extremely long and was wondering if anyone had a recursive / intuitive solution that could be completed in a reasonable amount of time.
Method header:
String consecutiveSum(String number) {}
Yes, you can use recursive solution e.g. (c# code):
private static string consecutiveSum(string text)
{
StringBuilder sb = new StringBuilder(text.Length);
bool wantRecursiveCall = false;
char prior = '\0';
int sum = -1;
foreach (var c in text)
{
if (c != prior)
{
if (sum >= 0)
sb.Append(sum);
sum = 0;
}
else
wantRecursiveCall = true;
sum += c - '0';
prior = c;
}
sb.Append(sum);
return wantRecursiveCall ? consecutiveSum(sb.ToString()) : sb.ToString();
}

Special numbers challenge in programming

First, sorry for my bad English.
Special numbers are numbers that the sum of the digits is divisible to the number of the digit.
Example: 135 is a special number because the sum of the digits is 1+3+5 = 9, the number of the digit is 3, and 9 is divisible to 3 because 9 % 3 == 0. 2,3,9,13,17,15,225, 14825 are also special numbers.
Requirement:
Write a program that read the number n (n <= 10^6) from a file named SNUMS.INP (SNUMS.INP can contain up to 10^6 numbers) and print the result out into the file SNUMS.OUT. Number n is the order of the special number and the result will be that special number in n order (sorry I don't know how to express it).
Example: n = 3 means you have to print out the 3rd special number which is 3, n = 10 you have to print out 10th special number which is 11, n = 13 you have to print out 13th special number which is 17, n = 15 you have to print out 15th special number which is 20.
The example bellow will demonstrate the file SNUMS.INP and SNUMS.OUT (Remember: SNUMS.INP can contain up to 10^6 numbers)
SNUMS.INP:
2
14
17
22
SNUMS.OUT:
2
19
24
35
I have my own alogrithm but the the running time exceeds 1 second (my SNUMS.INP has 10^6 numbers). So I need the optimal alogrithm so that the running time will be less than or equal 1s.
Guys I decide to post my own code which is written in Java, it always take more than 4 seconds to run. Could you guys please suggest some ideas to improve or how to make it run faster
import java.util.Scanner;
import java.io.*;
public class Test
{
public static void main(String[]args) throws IOException
{
File file = new File("SNUMS.INP");
Scanner inputFile = new Scanner(file);
int order = 1;
int i = 1;
int[] special = new int[1000000+1];
// Write all 10^6 special numbers into an array named "special"
while (order <= 1000000)
{
if (specialNumber(i) == true)
{
special[order] = i;
order++;
}
i++;
}
// Write the result to file
PrintWriter outputFile = new PrintWriter("SNUMS.OUT");
outputFile.println(special[inputFile.nextInt()]);
while (inputFile.hasNext())
outputFile.println(special[inputFile.nextInt()]);
outputFile.close();
}
public static boolean specialNumber(int i)
{
// This method check whether the number is a special number
boolean specialNumber = false;
byte count=0;
long sum=0;
while (i != 0)
{
sum = sum + (i % 10);
count++;
i = i / 10;
}
if (sum % count == 0) return true;
else return false;
}
}
This is file SNUMS.INP (sample) contains 10^6 numbers if you guys want to test.
https://drive.google.com/file/d/0BwOJpa2dAZlUNkE3YmMwZmlBOTg/view?usp=sharing
I've managed to solve it in 0.6 seconds on C# 6.0 (.Net 4.6 IA-64) at Core i7 3.2 GHz with HDD 7200 rpc; hope that precompution will be fast enough at your workstation:
// Precompute beautiful numbers
private static int[] BeautifulNumbers(int length) {
int[] result = new int[length];
int index = 0;
for (int i = 1; ; ++i) {
int sum = 0;
int count = 0;
for (int v = i; v > 0; sum += v % 10, ++count, v /= 10)
;
if (sum % count == 0) {
result[index] = i;
if (++index >= result.Length)
return result;
}
}
}
...
// Test file with 1e6 items
File.WriteAllLines(#"D:\SNUMS.INP", Enumerable
.Range(1, 1000000)
.Select(index => index.ToString()));
...
Stopwatch sw = new Stopwatch();
sw.Start();
// Precomputed numbers (about 0.3 seconds to be created)
int[] data = BeautifulNumbers(1000000);
// File (about 0.3 seconds for both reading and writing)
var result = File
.ReadLines(#"D:\SNUMS.INP")
.Select(line => data[int.Parse(line) - 1].ToString());
File.WriteAllLines(#"D:\SNUMS.OUT", result);
sw.Stop();
Console.Write("Elapsed time {0}", sw.ElapsedMilliseconds);
The output vary from
Elapsed time 516
to
Elapsed time 660
with average elapsed time at about 580 milliseconds
Now that you have the metaphor of abacus implemented below, here are some hints
instead of just incrementing with 1 inside a cycle, can we incremente more aggressively? Indeed we can, but with an extra bit of care.
first, how much aggressive we can be? Looking to 11 (first special with 2 digits), it doesn't pay to just increment by 1, we can increment it by 2. Looking to 102 (special with 3 digits), we can increment it by 3. Is it natural to think we should use increments equal with the number of digits?
now the "extra bit of care" - whenever the "increment by the number of digits" causes a "carry", the naive increment breaks. Because the carry will add 1 to the sum of digits, so that we may need to subtract that one from something to keep the sum of digits well behaved.
one of the issues in the above is that we jumped quite happily at "first special with N digits", but the computer is not us to see it at a glance. Fortunately, the "first special with N digits" is easy to compute: it is 10^(N-1)+(N-1) - 10^(N-1) brings an 1 and the rest is zero, and N-1 brings the rest to make the sum of digits be the first divisible with N. Of course, this will break down if N > 10, but fortunately the problem is limited to 10^6 special numbers, which will require at most 7 digits (the millionth specual number is 6806035 - 7 digits);
so, we can detect the "first special number with N digits" and we know we should try with care to increment it by N. Can we look now better into that "extra care"?.
The code - twice as speedy as the previous one and totally "orthodox" in obtaining the data (via getters instead of direct access to data members).
Feel free to inline:
import java.util.ArrayList;
import java.util.Arrays;
public class Abacus {
static protected int pow10[]=
{1,10,100,1000, 10000, 100000, 1000000, 10000000, 100000000}
;
// the value stored for line[i] corresponds to digit[i]*pow10[i]
protected int lineValues[];
protected int sumDigits;
protected int representedNumber;
public Abacus() {
this.lineValues=new int[0];
this.sumDigits=0;
this.representedNumber=0;
}
public int getLineValue(int line) {
return this.lineValues[line];
}
public void clearUnitLine() {
this.sumDigits-=this.lineValues[0];
this.representedNumber-=this.lineValues[0];
this.lineValues[0]=0;
}
// This is how you operate the abacus in real life being asked
// to add a number of units to the line presenting powers of 10
public boolean addWithCarry(int units, int line) {
if(line-1==pow10.length) {
// don't have enough pow10 stored
pow10=Arrays.copyOf(pow10, pow10.length+1);
pow10[line]=pow10[line-1]*10;
}
if(line>=this.lineValues.length) {
// don't have enough lines for the carry
this.lineValues=Arrays.copyOf(this.lineValues, line+1);
}
int digitOnTheLine=this.lineValues[line]/pow10[line];
int carryOnTheNextLine=0;
while(digitOnTheLine+units>=10) {
carryOnTheNextLine++;
units-=10;
}
if(carryOnTheNextLine>0) {
// we have a carry, the sumDigits will be affected
// 1. the next two statememts are equiv with "set a value of zero on the line"
this.sumDigits-=digitOnTheLine;
this.representedNumber-=this.lineValues[line];
// this is the new value of the digit to set on the line
digitOnTheLine+=units;
// 3. set that value and keep all the values synchronized
this.sumDigits+=digitOnTheLine;
this.lineValues[line]=digitOnTheLine*pow10[line];
this.representedNumber+=this.lineValues[line];
// 4. as we had a carry, the next line will be affected as well.
this.addWithCarry(carryOnTheNextLine, line+1);
}
else { // we an simply add the provided value without carry
int delta=units*pow10[line];
this.lineValues[line]+=delta;
this.representedNumber+=delta;
this.sumDigits+=units;
}
return carryOnTheNextLine>0;
}
public int getSumDigits() {
return this.sumDigits;
}
public int getRepresentedNumber() {
return this.representedNumber;
}
public int getLinesCount() {
return this.lineValues.length;
}
static public ArrayList<Integer> specials(int N) {
ArrayList<Integer> ret=new ArrayList<>(N);
Abacus abacus=new Abacus();
ret.add(1);
abacus.addWithCarry(1, 0); // to have something to add to
int increment=abacus.getLinesCount();
while(ret.size()<N) {
boolean hadCarry=abacus.addWithCarry(increment, 0);
if(hadCarry) {
// need to resynch the sum for a perfect number
int newIncrement=abacus.getLinesCount();
abacus.clearUnitLine();
if(newIncrement!=increment) {
// we switched powers of 10
abacus.addWithCarry(newIncrement-1, 0);
increment=newIncrement;
}
else { // simple carry
int digitsSum=abacus.getSumDigits();
// how much we should add to the last digit to make the sumDigits
// divisible again with the increment?
int units=increment-digitsSum % increment;
if(units<increment) {
abacus.addWithCarry(units, 0);
}
}
}
ret.add(abacus.getRepresentedNumber());
}
return ret;
}
// to understand how the addWithCarry works, try the following code
static void add13To90() {
Abacus abacus; // starts with a represented number of 0
// line==1 means units of 10^1
abacus.addWithCary(9, 1); // so this should make the abacus store 90
System.out.println(abacus.getRepresentedNumber());
// line==0 means units of 10^0
abacus.addWithCarry(13, 0);
System.out.println(abacus.getRepresentedNumber()); // 103
}
static public void main(String[] args) {
int count=1000000;
long t1=System.nanoTime();
ArrayList<Integer> s1=Abacus.specials(count);
long t2=System.nanoTime();
System.out.println("t:"+(t2-t1));
}
}
Constructing the numbers from their digits is bound to be faster.
Remember the abacus? Ever used one?
import java.util.ArrayList;
public class Specials {
static public ArrayList<Integer> computeNSpecials(int N) {
ArrayList<Integer> specials = new ArrayList<>();
int abacus[] = new int[0]; // at index i we have the digit for 10^i
// This way, when we don't have enough specials,
// we simply reallocate the array and continue
while (specials.size() < N) {
// see if a carry operation is necessary
int currDigit = 0;
for (; currDigit < abacus.length && abacus[currDigit] == 9; currDigit++) {
abacus[currDigit] = 0; // a carry occurs when adding 1
}
if (currDigit == abacus.length) {
// a carry, but we don't have enough lines on the abacus
abacus = new int[abacus.length + 1];
abacus[currDigit] = 1; // we resolved the carry, all the digits below
// are 0
} else {
abacus[currDigit]++; // we resolve the carry (if there was one),
currDigit = 0; // now it's safe to continue incrementing at 10^0
}
// let's obtain the current number and the sum of the digits
int sumDigits = 0;
for (int i = 0; i<abacus.length; i++) {
sumDigits += abacus[i];
}
// is it special?
if (sumDigits % abacus.length == 0) {
// only now compute the number and collect it as special
int number = 0;
for (int i = abacus.length - 1; i >= 0; i--) {
number = 10 * number + abacus[i];
}
specials.add(number);
}
}
return specials;
}
static public void main(String[] args) {
ArrayList<Integer> specials=Specials.computeNSpecials(100);
for(int i=0; i<specials.size(); i++) {
System.out.println(specials.get(i));
}
}
}

Check if binary string can be partitioned such that each partition is a power of 5

I recently came across this question - Given a binary string, check if we can partition/split the string into 0..n parts such that each part is a power of 5. Return the minimum number of splits, if it can be done.
Examples would be:
input = "101101" - returns 1, as the string can be split once to form "101" and "101",as 101= 5^1.
input = "1111101" - returns 0, as the string itself is 5^3.
input = "100"- returns -1, as it can't be split into power(s) of 5.
I came up with this recursive algorithm:
Check if the string itself is a power of 5. if yes, return 0
Else, iterate over the string character by character, checking at every point if the number seen so far is a power of 5. If yes, add 1 to split count and check the rest of the string recursively for powers of 5 starting from step 1.
return the minimum number of splits seen so far.
I implemented the above algo in Java. I believe it works alright, but it's a straightforward recursive solution. Can this be solved using dynamic programming to improve the run time?
The code is below:
public int partition(String inp){
if(inp==null || inp.length()==0)
return 0;
return partition(inp,inp.length(),0);
}
public int partition(String inp,int len,int index){
if(len==index)
return 0;
if(isPowerOfFive(inp,index))
return 0;
long sub=0;
int count = Integer.MAX_VALUE;
for(int i=index;i<len;++i){
sub = sub*2 +(inp.charAt(i)-'0');
if(isPowerOfFive(sub))
count = Math.min(count,1+partition(inp,len,i+1));
}
return count;
}
Helper functions:
public boolean isPowerOfFive(String inp,int index){
long sub = 0;
for(int i=index;i<inp.length();++i){
sub = sub*2 +(inp.charAt(i)-'0');
}
return isPowerOfFive(sub);
}
public boolean isPowerOfFive(long val){
if(val==0)
return true;
if(val==1)
return false;
while(val>1){
if(val%5 != 0)
return false;
val = val/5;
}
return true;
}
Here is simple improvements that can be done:
Calculate all powers of 5 before start, so you could do checks faster.
Stop split input string if the number of splits is already greater than in the best split you've already done.
Here is my solution using these ideas:
public static List<String> powers = new ArrayList<String>();
public static int bestSplit = Integer.MAX_VALUE;
public static void main(String[] args) throws Exception {
// input string (5^5, 5^1, 5^10)
String inp = "110000110101101100101010000001011111001";
// calc all powers of 5 that fits in given string
for (int pow = 1; ; ++pow) {
String powStr = Long.toBinaryString((long) Math.pow(5, pow));
if (powStr.length() <= inp.length()) { // can be fit in input string
powers.add(powStr);
} else {
break;
}
}
Collections.reverse(powers); // simple heuristics, sort powers in decreasing order
// do simple recursive split
split(inp, 0, -1);
// print result
if (bestSplit == Integer.MAX_VALUE) {
System.out.println(-1);
} else {
System.out.println(bestSplit);
}
}
public static void split(String inp, int start, int depth) {
if (depth >= bestSplit) {
return; // can't do better split
}
if (start == inp.length()) { // perfect split
bestSplit = depth;
return;
}
for (String pow : powers) {
if (inp.startsWith(pow, start)) {
split(inp, start + pow.length(), depth + 1);
}
}
}
EDIT:
I also found another approach which looks like very fast one.
Calculate all powers of 5 whose string representation is shorter than input string. Save those strings in powers array.
For every string power from powers array: if power is substring of input then save its start and end indexes into the edges array (array of tuples).
Now we just need to find shortest path from index 0 to index input.length() by edges from the edges array. Every edge has the same weight, so the shortest path can be found very fast with BFS.
The number of edges in the shortest path found is exactly what you need -- minimum number of splits of the input string.
Instead of calculating all possible substrings, you can check the binary representation of the powers of 5 in search of a common pattern. Using something like:
bc <<< "obase=2; for(i = 1; i < 40; i++) 5^i"
You get:
51 = 1012
52 = 110012
53 = 11111012
54 = 10011100012
55 = 1100001101012
56 = 111101000010012
57 = 100110001001011012
58 = 10111110101111000012
59 = 1110111001101011001012
510 = 1001010100000010111110012
511 = 101110100100001110110111012
512 = 11101000110101001010010100012
513 = 10010001100001001110011100101012
514 = 1011010111100110001000001111010012
515 = 111000110101111110101001001100011012
516 = 100011100001101111001001101111110000012
517 = 10110001101000101011110000101110110001012
518 = 1101111000001011011010110011101001110110012
...
529 = 101000011000111100000111110101110011011010111001000010111110010101012
As you can see, odd powers of 5 always ends with 101 and even powers of 5 ends with the pattern 10+1 (where + means one or more occurrences).
You could put your input string in a trie and then iterate over it identifying the 10+1 pattern, once you have a match, evaluate it to check if is not a false positive.
You just have to save the value for a given string in a map. For example having if you have a string ending like this: (each letter may be a string of arbitrary size)
ABCD
You find that part A mod 5 is ok, so you try again for BCD, but find that B mod 5 is also ok, same for C and D as well as CD together. Now you should have the following results cached:
C -> 0
D -> 0
CD -> 0
BCD -> 1 # split B/CD is the best
But you're not finished with ABCD - you find that AB mod 5 is ok, so you check the resulting CD - it's already in the cache and you don't have to process it from the beginning.
In practice you just need to cache answers from partition() - either for the actual string or for the (string, start, length) tuple. Which one is better depends on how many repeating sequences you have and whether it's faster to compare the contents, or just indexes.
Given below is a solution in C++. Using dynamic programming I am considering all the possible splits and saving the best results.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int isPowerOfFive(ll n)
{
if(n == 0) return 0;
ll temp = (ll)(log(n)/log(5));
ll t = round(pow(5,temp));
if(t == n)
{
return 1;
}
else
{
return 0;
}
}
ll solve(string s)
{
vector<ll> dp(s.length()+1);
for(int i = 1; i <= s.length(); i++)
{
dp[i] = INT_MAX;
for(int j = 1; j <= i; j++)
{
if( s[j-1] == '0')
{
continue;
}
ll num = stoll(s.substr(j-1, i-j+1), nullptr, 2);
if(isPowerOfFive(num))
{
dp[i] = min(dp[i], dp[j-1]+1);
}
}
}
if(dp[s.length()] == INT_MAX)
{
return -1;
}
else
{
return dp[s.length()];
}
}
int main()
{
string s;
cin>>s;
cout<<solve(s);
}

Find the index of a given permutation in the sorted list of the permutations of a given string

We're given a string and a permutation of the string.
For example, an input string sandeep and a permutation psdenae.
Find the position of the given permutation in the sorted list of the permutations of the original string.
The total number of permutation of a given string of length n would be n! (if all characters are different), thus it would not be possible to explore all the combinations.
This question is actually like the mathematics P & C question
Find the rank of the word "stack" when arranged in dictionary order.
Given the input string as NILSU
Take a word which we have to find the rank. Take "SUNIL" for example.
Now arrange the letter of "SUNIL" in alphabetical order.
It will be. "I L N S U".
Now take the first letter. Its "I". Now check, is the letter "I" the
first letter of "SUNIL"? No. The number of words that can be formed
starting with I will be 4!, so we know that there will be 4! words
before "SUNIL".
I = 4! = 24
Now go for the second letter. Its "L". Now check once again if this
letter we want in first position? No. So the number of words can be
formed starting with "L" will be 4!.
L = 4! = 24
Now go for "N". Is this we want? No. Write down the number of words
can be formed starting with "N", once again 4!
N = 4! = 24
Now go for "S". Is this what we want? Yes. Now remove the letter from
the alphabetically ordered word. It will now be "I L N U"
Write S and check the word once again in the list. Is we want SI? No.
So the number of words can be formed starting with SI will be 3!
[S]:I-> 3! = 6
Go for L. is we want SL? No. So it will be 3!.
[S]:L-> 3! = 6
Go for N. is we want SN? No.
[S]:N-> 3! = 6
Go for SU. Is this we want? Yes. Cut the letter U from the list and
then it will be "I L N". Now try I. is we want SUI? No. So the number
of words can be formed which starts from SUI will be 2!
[SU]:I-> 2! = 2 Now go for L. Do we want "SUL". No. so the number of
words starting with SUL will be 2!.
[SU]:L-> 2! = 2
Now go for N. Is we want SUN? Yes, now remove that letter. and this
will be "I L". Do we want "SUNI"? Yes. Remove that letter. The only
letter left is "L".
Now go for L. Do we want SUNIL? Yes. SUNIL were the first options, so
we have 1!. [SUN][I][L] = 1! = 1
Now add the whole numbers we get. The sum will be.
24 + 24 + 24 + 6 + 6 + 6 + 2 + 2 + 1 = 95.
So the word SUNIL will be at 95th position if we count the words that can be created using the letters of SUNIL arranged in dictionary order.
Thus through this method you could solve this problem quite easily.
Building off #Algorithmist 's answer, and his comment to his answer, and using the principle discussed in this post for when there are repeated letters, I made the following algorithm in JavaScript that works for all letter-based words even with repeated letter instances.
function anagramPosition(string) {
var index = 1;
var remainingLetters = string.length - 1;
var frequencies = {};
var splitString = string.split("");
var sortedStringLetters = string.split("").sort();
sortedStringLetters.forEach(function(val, i) {
if (!frequencies[val]) {
frequencies[val] = 1;
} else {
frequencies[val]++;
}
})
function factorial(coefficient) {
var temp = coefficient;
var permutations = coefficient;
while (temp-- > 2) {
permutations *= temp;
}
return permutations;
}
function getSubPermutations(object, currentLetter) {
object[currentLetter]--;
var denominator = 1;
for (var key in object) {
var subPermutations = factorial(object[key]);
subPermutations !== 0 ? denominator *= subPermutations : null;
}
object[currentLetter]++;
return denominator;
}
var splitStringIndex = 0;
while (sortedStringLetters.length) {
for (var i = 0; i < sortedStringLetters.length; i++) {
if (sortedStringLetters[i] !== splitString[splitStringIndex]) {
if (sortedStringLetters[i] !== sortedStringLetters[i+1]) {
var permutations = factorial(remainingLetters);
index += permutations / getSubPermutations(frequencies, sortedStringLetters[i]);
} else {
continue;
}
} else {
splitStringIndex++;
frequencies[sortedStringLetters[i]]--;
sortedStringLetters.splice(i, 1);
remainingLetters--;
break;
}
}
}
return index;
}
anagramPosition("ARCTIC") // => 42
I didn't comment the code but I did try to make the variable names as explanatory as possible. If you run it through a debugger process using your dev tools console and throw in a few console.logs you should be able to see how it uses the formula in the above-linked S.O. post.
I tried to implement this in js. It works for string that have no repeated letters but I get a wrong count otherwise. Here is my code:
function x(str) {
var sOrdinata = str.split('').sort()
console.log('sOrdinata = '+ sOrdinata)
var str = str.split('')
console.log('str = '+str)
console.log('\n')
var pos = 1;
for(var j in str){
//console.log(j)
for(var i in sOrdinata){
if(sOrdinata[i]==str[j]){
console.log('found, position: '+ i)
sOrdinata.splice(i,1)
console.log('Nuovo sOrdinata = '+sOrdinata)
console.log('\n')
break;
}
else{
//calculate number of permutations
console.log('valore di j: '+j)
//console.log('lunghezza stringa da permutare: '+str.slice(~~j+1).length);
if(str.slice(j).length >1 ){sub = str.slice(~~j+1)}else {sub = str.slice(j)}
console.log('substring to be used for permutation: '+ sub)
prep = nrepC(sub.join(''))
console.log('prep = '+prep)
num = factorial(sub.length)
console.log('num = '+num)
den = denom(prep)
console.log('den = '+ den)
pos += num/den
console.log(num/den)
console.log('\n')
}
}
}
console.log(pos)
return pos
}
/* ------------ functions used by main --------------- */
function nrepC(str){
var obj={}
var repeats=[]
var res= [];
for(x = 0, length = str.length; x < length; x++) {
var l = str.charAt(x)
obj[l] = (isNaN(obj[l]) ? 1 : obj[l] + 1);
}
//console.log(obj)
for (var i in obj){
if(obj[i]>1) res.push(obj[i])
}
if(res.length==0){res.push(1); return res}
else return res
}
function num(vect){
var res = 1
}
function denom(vect){
var res = 1
for(var i in vect){
res*= factorial(vect[i])
}
return res
}
function factorial (n){
if (n==0 || n==1){
return 1;
}
return factorial(n-1)*n;
}
A bit too late but just as reference... You can use this C# code directly.
It will work but...
The only important thing is that usually, you should have unique values as your starting set. Otherwise you don't have n! permutations. You have something else (less than n!). I have a little doubt of any useful usage when item could be duplicate ones.
using System;
using System.Collections.Generic;
namespace WpfPermutations
{
public class PermutationOuelletLexico3<T>
{
// ************************************************************************
private T[] _sortedValues;
private bool[] _valueUsed;
public readonly long MaxIndex; // long to support 20! or less
// ************************************************************************
public PermutationOuelletLexico3(T[] sortedValues)
{
if (sortedValues.Length <= 0)
{
throw new ArgumentException("sortedValues.Lenght should be greater than 0");
}
_sortedValues = sortedValues;
Result = new T[_sortedValues.Length];
_valueUsed = new bool[_sortedValues.Length];
MaxIndex = Factorial.GetFactorial(_sortedValues.Length);
}
// ************************************************************************
public T[] Result { get; private set; }
// ************************************************************************
/// <summary>
/// Return the permutation relative to the index received, according to
/// _sortedValues.
/// Sort Index is 0 based and should be less than MaxIndex. Otherwise you get an exception.
/// </summary>
/// <param name="sortIndex"></param>
/// <returns>The result is written in property: Result</returns>
public void GetValuesForIndex(long sortIndex)
{
int size = _sortedValues.Length;
if (sortIndex < 0)
{
throw new ArgumentException("sortIndex should be greater or equal to 0.");
}
if (sortIndex >= MaxIndex)
{
throw new ArgumentException("sortIndex should be less than factorial(the lenght of items)");
}
for (int n = 0; n < _valueUsed.Length; n++)
{
_valueUsed[n] = false;
}
long factorielLower = MaxIndex;
for (int index = 0; index < size; index++)
{
long factorielBigger = factorielLower;
factorielLower = Factorial.GetFactorial(size - index - 1); // factorielBigger / inverseIndex;
int resultItemIndex = (int)(sortIndex % factorielBigger / factorielLower);
int correctedResultItemIndex = 0;
for(;;)
{
if (! _valueUsed[correctedResultItemIndex])
{
resultItemIndex--;
if (resultItemIndex < 0)
{
break;
}
}
correctedResultItemIndex++;
}
Result[index] = _sortedValues[correctedResultItemIndex];
_valueUsed[correctedResultItemIndex] = true;
}
}
// ************************************************************************
/// <summary>
/// Calc the index, relative to _sortedValues, of the permutation received
/// as argument. Returned index is 0 based.
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
public long GetIndexOfValues(T[] values)
{
int size = _sortedValues.Length;
long valuesIndex = 0;
List<T> valuesLeft = new List<T>(_sortedValues);
for (int index = 0; index < size; index++)
{
long indexFactorial = Factorial.GetFactorial(size - 1 - index);
T value = values[index];
int indexCorrected = valuesLeft.IndexOf(value);
valuesIndex = valuesIndex + (indexCorrected * indexFactorial);
valuesLeft.Remove(value);
}
return valuesIndex;
}
// ************************************************************************
}
}
My approach to the problem is sort the given permutation.
Number of swappings of the characters in the string will give us the position of the pemutation in the sorted list of permutations.
An inefficient solution would be to successively find the previous permutations until you reach a string that cannot be permuted anymore. The number of permutations it takes to reach this state is the position of the original string.
However, if you use combinatorics you can achieve the solution faster. The previous solution will produce a very slow output if string length exceeds 12.

finding if two words are anagrams of each other

I am looking for a method to find if two strings are anagrams of one another.
Ex: string1 - abcde
string2 - abced
Ans = true
Ex: string1 - abcde
string2 - abcfed
Ans = false
the solution i came up with so for is to sort both the strings and compare each character from both strings till the end of either strings.It would be O(logn).I am looking for some other efficient method which doesn't change the 2 strings being compared
Count the frequency of each character in the two strings. Check if the two histograms match. O(n) time, O(1) space (assuming ASCII) (Of course it is still O(1) space for Unicode but the table will become very large).
Get table of prime numbers, enough to map each prime to every character. So start from 1, going through line, multiply the number by the prime representing current character. Number you'll get is only depend on characters in string but not on their order, and every unique set of characters correspond to unique number, as any number may be factored in only one way. So you can just compare two numbers to say if a strings are anagrams of each other.
Unfortunately you have to use multiple precision (arbitrary-precision) integer arithmetic to do this, or you will get overflow or rounding exceptions when using this method.
For this you may use libraries like BigInteger, GMP, MPIR or IntX.
Pseudocode:
prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101}
primehash(string)
Y = 1;
foreach character in string
Y = Y * prime[character-'a']
return Y
isanagram(str1, str2)
return primehash(str1)==primehash(str2)
Create a Hashmap where key - letter and value - frequencey of letter,
for first string populate the hashmap (O(n))
for second string decrement count and remove element from hashmap O(n)
if hashmap is empty, the string is anagram otherwise not.
The steps are:
check the length of of both the words/strings if they are equal then only proceed to check for anagram else do nothing
sort both the words/strings and then compare
JAVA CODE TO THE SAME:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package anagram;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
/**
*
* #author Sunshine
*/
public class Anagram {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
// TODO code application logic here
System.out.println("Enter the first string");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s1 = br.readLine().toLowerCase();
System.out.println("Enter the Second string");
BufferedReader br2 = new BufferedReader(new InputStreamReader(System.in));
String s2 = br2.readLine().toLowerCase();
char c1[] = null;
char c2[] = null;
if (s1.length() == s2.length()) {
c1 = s1.toCharArray();
c2 = s2.toCharArray();
Arrays.sort(c1);
Arrays.sort(c2);
if (Arrays.equals(c1, c2)) {
System.out.println("Both strings are equal and hence they have anagram");
} else {
System.out.println("Sorry No anagram in the strings entred");
}
} else {
System.out.println("Sorry the string do not have anagram");
}
}
}
C#
public static bool AreAnagrams(string s1, string s2)
{
if (s1 == null) throw new ArgumentNullException("s1");
if (s2 == null) throw new ArgumentNullException("s2");
var chars = new Dictionary<char, int>();
foreach (char c in s1)
{
if (!chars.ContainsKey(c))
chars[c] = 0;
chars[c]++;
}
foreach (char c in s2)
{
if (!chars.ContainsKey(c))
return false;
chars[c]--;
}
return chars.Values.All(i => i == 0);
}
Some tests:
[TestMethod]
public void TestAnagrams()
{
Assert.IsTrue(StringUtil.AreAnagrams("anagramm", "nagaramm"));
Assert.IsTrue(StringUtil.AreAnagrams("anzagramm", "nagarzamm"));
Assert.IsTrue(StringUtil.AreAnagrams("anz121agramm", "nag12arz1amm"));
Assert.IsFalse(StringUtil.AreAnagrams("anagram", "nagaramm"));
Assert.IsFalse(StringUtil.AreAnagrams("nzagramm", "nagarzamm"));
Assert.IsFalse(StringUtil.AreAnagrams("anzagramm", "nag12arz1amm"));
}
Code to find whether two words are anagrams:
Logic explained already in few answers and few asking for the code. This solution produce the result in O(n) time.
This approach counts the no of occurrences of each character and store it in the respective ASCII location for each string. And then compare the two array counts. If it is not equal the given strings are not anagrams.
public boolean isAnagram(String str1, String str2)
{
//To get the no of occurrences of each character and store it in their ASCII location
int[] strCountArr1=getASCIICountArr(str1);
int[] strCountArr2=getASCIICountArr(str2);
//To Test whether the two arrays have the same count of characters. Array size 256 since ASCII 256 unique values
for(int i=0;i<256;i++)
{
if(strCountArr1[i]!=strCountArr2[i])
return false;
}
return true;
}
public int[] getASCIICountArr(String str)
{
char c;
//Array size 256 for ASCII
int[] strCountArr=new int[256];
for(int i=0;i<str.length();i++)
{
c=str.charAt(i);
c=Character.toUpperCase(c);// If both the cases are considered to be the same
strCountArr[(int)c]++; //To increment the count in the character's ASCII location
}
return strCountArr;
}
Using an ASCII hash-map that allows O(1) look-up for each char.
The java example listed above is converting to lower-case that seems incomplete. I have an example in C that simply initializes a hash-map array for ASCII values to '-1'
If string2 is different in length than string 1, no anagrams
Else, we update the appropriate hash-map values to 0 for each char in string1 and string2
Then for each char in string1, we update the count in hash-map. Similarily, we decrement the value of the count for each char in string2.
The result should have values set to 0 for each char if they are anagrams. if not, some positive value set by string1 remains
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAYMAX 128
#define True 1
#define False 0
int isAnagram(const char *string1,
const char *string2) {
int str1len = strlen(string1);
int str2len = strlen(string2);
if (str1len != str2len) /* Simple string length test */
return False;
int * ascii_hashtbl = (int * ) malloc((sizeof(int) * ARRAYMAX));
if (ascii_hashtbl == NULL) {
fprintf(stderr, "Memory allocation failed\n");
return -1;
}
memset((void *)ascii_hashtbl, -1, sizeof(int) * ARRAYMAX);
int index = 0;
while (index < str1len) { /* Populate hash_table for each ASCII value
in string1*/
ascii_hashtbl[(int)string1[index]] = 0;
ascii_hashtbl[(int)string2[index]] = 0;
index++;
}
index = index - 1;
while (index >= 0) {
ascii_hashtbl[(int)string1[index]]++; /* Increment something */
ascii_hashtbl[(int)string2[index]]--; /* Decrement something */
index--;
}
/* Use hash_table to compare string2 */
index = 0;
while (index < str1len) {
if (ascii_hashtbl[(int)string1[index]] != 0) {
/* some char is missing in string2 from string1 */
free(ascii_hashtbl);
ascii_hashtbl = NULL;
return False;
}
index++;
}
free(ascii_hashtbl);
ascii_hashtbl = NULL;
return True;
}
int main () {
char array1[ARRAYMAX], array2[ARRAYMAX];
int flag;
printf("Enter the string\n");
fgets(array1, ARRAYMAX, stdin);
printf("Enter another string\n");
fgets(array2, ARRAYMAX, stdin);
array1[strcspn(array1, "\r\n")] = 0;
array2[strcspn(array2, "\r\n")] = 0;
flag = isAnagram(array1, array2);
if (flag == 1)
printf("%s and %s are anagrams.\n", array1, array2);
else if (flag == 0)
printf("%s and %s are not anagrams.\n", array1, array2);
return 0;
}
let's take a question: Given two strings s and t, write a function to determine if t is an anagram of s.
For example,
s = "anagram", t = "nagaram", return true.
s = "rat", t = "car", return false.
Method 1(Using HashMap ):
public class Method1 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
System.out.println(isAnagram(a, b ));// output => true
}
private static boolean isAnagram(String a, String b) {
Map<Character ,Integer> map = new HashMap<>();
for( char c : a.toCharArray()) {
map.put(c, map.getOrDefault(c, 0 ) + 1 );
}
for(char c : b.toCharArray()) {
int count = map.getOrDefault(c, 0);
if(count == 0 ) {return false ; }
else {map.put(c, count - 1 ) ; }
}
return true;
}
}
Method 2 :
public class Method2 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
System.out.println(isAnagram(a, b));// output=> true
}
private static boolean isAnagram(String a, String b) {
int[] alphabet = new int[26];
for(int i = 0 ; i < a.length() ;i++) {
alphabet[a.charAt(i) - 'a']++ ;
}
for (int i = 0; i < b.length(); i++) {
alphabet[b.charAt(i) - 'a']-- ;
}
for( int w : alphabet ) {
if(w != 0 ) {return false;}
}
return true;
}
}
Method 3 :
public class Method3 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
System.out.println(isAnagram(a, b ));// output => true
}
private static boolean isAnagram(String a, String b) {
char[] ca = a.toCharArray() ;
char[] cb = b.toCharArray();
Arrays.sort( ca );
Arrays.sort( cb );
return Arrays.equals(ca , cb );
}
}
Method 4 :
public class AnagramsOrNot {
public static void main(String[] args) {
String a = "Protijayi";
String b = "jayiProti";
isAnagram(a, b);
}
private static void isAnagram(String a, String b) {
Map<Integer, Integer> map = new LinkedHashMap<>();
a.codePoints().forEach(code -> map.put(code, map.getOrDefault(code, 0) + 1));
System.out.println(map);
b.codePoints().forEach(code -> map.put(code, map.getOrDefault(code, 0) - 1));
System.out.println(map);
if (map.values().contains(0)) {
System.out.println("Anagrams");
} else {
System.out.println("Not Anagrams");
}
}
}
In Python:
def areAnagram(a, b):
if len(a) != len(b): return False
count1 = [0] * 256
count2 = [0] * 256
for i in a:count1[ord(i)] += 1
for i in b:count2[ord(i)] += 1
for i in range(256):
if(count1[i] != count2[i]):return False
return True
str1 = "Giniiii"
str2 = "Protijayi"
print(areAnagram(str1, str2))
Let's take another famous Interview Question: Group the Anagrams from a given String:
public class GroupAnagrams {
public static void main(String[] args) {
String a = "Gini Gina Protijayi iGin aGin jayiProti Soudipta";
Map<String, List<String>> map = Arrays.stream(a.split(" ")).collect(Collectors.groupingBy(GroupAnagrams::sortedString));
System.out.println("MAP => " + map);
map.forEach((k,v) -> System.out.println(k +" and the anagrams are =>" + v ));
/*
Look at the Map output:
MAP => {Giin=[Gini, iGin], Paiijorty=[Protijayi, jayiProti], Sadioptu=[Soudipta], Gain=[Gina, aGin]}
As we can see, there are multiple Lists. Hence, we have to use a flatMap(List::stream)
Now, Look at the output:
Paiijorty and the anagrams are =>[Protijayi, jayiProti]
Now, look at this output:
Sadioptu and the anagrams are =>[Soudipta]
List contains only word. No anagrams.
That means we have to work with map.values(). List contains all the anagrams.
*/
String stringFromMapHavingListofLists = map.values().stream().flatMap(List::stream).collect(Collectors.joining(" "));
System.out.println(stringFromMapHavingListofLists);
}
public static String sortedString(String a) {
String sortedString = a.chars().sorted()
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
return sortedString;
}
/*
* The output : Gini iGin Protijayi jayiProti Soudipta Gina aGin
* All the anagrams are side by side.
*/
}
Now to Group Anagrams in Python is again easy.We have to :
Sort the lists. Then, Create a dictionary. Now dictionary will tell us where are those anagrams are( Indices of Dictionary). Then values of the dictionary is the actual indices of the anagrams.
def groupAnagrams(words):
# sort each word in the list
A = [''.join(sorted(word)) for word in words]
dict = {}
for indexofsamewords, names in enumerate(A):
dict.setdefault(names, []).append(indexofsamewords)
print(dict)
#{'AOOPR': [0, 2, 5, 11, 13], 'ABTU': [1, 3, 4], 'Sorry': [6], 'adnopr': [7], 'Sadioptu': [8, 16], ' KPaaehiklry': [9], 'Taeggllnouy': [10], 'Leov': [12], 'Paiijorty': [14, 18], 'Paaaikpr': [15], 'Saaaabhmryz': [17], ' CNaachlortttu': [19], 'Saaaaborvz': [20]}
for index in dict.values():
print([words[i] for i in index])
if __name__ == '__main__':
# list of words
words = ["ROOPA","TABU","OOPAR","BUTA","BUAT" , "PAROO","Soudipta",
"Kheyali Park", "Tollygaunge", "AROOP","Love","AOORP", "Protijayi","Paikpara","dipSouta","Shyambazaar",
"jayiProti", "North Calcutta", "Sovabazaar"]
groupAnagrams(words)
The Output :
['ROOPA', 'OOPAR', 'PAROO', 'AROOP', 'AOORP']
['TABU', 'BUTA', 'BUAT']
['Soudipta', 'dipSouta']
['Kheyali Park']
['Tollygaunge']
['Love']
['Protijayi', 'jayiProti']
['Paikpara']
['Shyambazaar']
['North Calcutta']
['Sovabazaar']
Another Important Anagram Question : Find the Anagram occuring Max. number of times.
In the Example, ROOPA is the word which has occured maximum number of times.
Hence, ['ROOPA' 'OOPAR' 'PAROO' 'AROOP' 'AOORP'] will be the final output.
from sqlite3 import collections
from statistics import mode, mean
import numpy as np
# list of words
words = ["ROOPA","TABU","OOPAR","BUTA","BUAT" , "PAROO","Soudipta",
"Kheyali Park", "Tollygaunge", "AROOP","Love","AOORP",
"Protijayi","Paikpara","dipSouta","Shyambazaar",
"jayiProti", "North Calcutta", "Sovabazaar"]
print(".....Method 1....... ")
sortedwords = [''.join(sorted(word)) for word in words]
print(sortedwords)
print("...........")
LongestAnagram = np.array(words)[np.array(sortedwords) == mode(sortedwords)]
# Longest anagram
print("Longest anagram by Method 1:")
print(LongestAnagram)
print(".....................................................")
print(".....Method 2....... ")
A = [''.join(sorted(word)) for word in words]
dict = {}
for indexofsamewords,samewords in enumerate(A):
dict.setdefault(samewords,[]).append(samewords)
#print(dict)
#{'AOOPR': ['AOOPR', 'AOOPR', 'AOOPR', 'AOOPR', 'AOOPR'], 'ABTU': ['ABTU', 'ABTU', 'ABTU'], 'Sadioptu': ['Sadioptu', 'Sadioptu'], ' KPaaehiklry': [' KPaaehiklry'], 'Taeggllnouy': ['Taeggllnouy'], 'Leov': ['Leov'], 'Paiijorty': ['Paiijorty', 'Paiijorty'], 'Paaaikpr': ['Paaaikpr'], 'Saaaabhmryz': ['Saaaabhmryz'], ' CNaachlortttu': [' CNaachlortttu'], 'Saaaaborvz': ['Saaaaborvz']}
aa = max(dict.items() , key = lambda x : len(x[1]))
print("aa => " , aa)
word, anagrams = aa
print("Longest anagram by Method 2:")
print(" ".join(anagrams))
The Output :
.....Method 1.......
['AOOPR', 'ABTU', 'AOOPR', 'ABTU', 'ABTU', 'AOOPR', 'Sadioptu', ' KPaaehiklry', 'Taeggllnouy', 'AOOPR', 'Leov', 'AOOPR', 'Paiijorty', 'Paaaikpr', 'Sadioptu', 'Saaaabhmryz', 'Paiijorty', ' CNaachlortttu', 'Saaaaborvz']
...........
Longest anagram by Method 1:
['ROOPA' 'OOPAR' 'PAROO' 'AROOP' 'AOORP']
.....................................................
.....Method 2.......
aa => ('AOOPR', ['AOOPR', 'AOOPR', 'AOOPR', 'AOOPR', 'AOOPR'])
Longest anagram by Method 2:
AOOPR AOOPR AOOPR AOOPR AOOPR
Well you can probably improve the best case and average case substantially just by checking the length first, then a quick checksum on the digits (not something complex, as that will probably be worse order than the sort, just a summation of ordinal values), then sort, then compare.
If the strings are very short the checksum expense will be not greatly dissimilar to the sort in many languages.
How about this?
a = "lai d"
b = "di al"
sorteda = []
sortedb = []
for i in a:
if i != " ":
sorteda.append(i)
if c == len(b):
for x in b:
c -= 1
if x != " ":
sortedb.append(x)
sorteda.sort(key = str.lower)
sortedb.sort(key = str.lower)
print sortedb
print sorteda
print sortedb == sorteda
How about Xor'ing both the strings??? This will definitely be of O(n)
char* arr1="ab cde";
int n1=strlen(arr1);
char* arr2="edcb a";
int n2=strlen(arr2);
// to check for anagram;
int c=0;
int i=0, j=0;
if(n1!=n2)
printf("\nNot anagram");
else {
while(i<n1 || j<n2)
{
c^= ((int)arr1[i] ^ (int)arr2[j]);
i++;
j++;
}
}
if(c==0) {
printf("\nAnagram");
}
else printf("\nNot anagram");
}
static bool IsAnagram(string s1, string s2)
{
if (s1.Length != s2.Length)
return false;
else
{
int sum1 = 0;
for (int i = 0; i < s1.Length; i++)
sum1 += (int)s1[i]-(int)s2[i];
if (sum1 == 0)
return true;
else
return false;
}
}
For known (and small) sets of valid letters (e.g. ASCII) use a table with counts associated with each valid letter. First string increments counts, second string decrements counts. Finally iterate through the table to see if all counts are zero (strings are anagrams) or there are non-zero values (strings are not anagrams). Make sure to convert all characters to uppercase (or lowercase, all the same) and to ignore white space.
For a large set of valid letters, such as Unicode, do not use table but rather use a hash table. It has O(1) time to add, query and remove and O(n) space. Letters from first string increment count, letters from second string decrement count. Count that becomes zero is removed form the hash table. Strings are anagrams if at the end hash table is empty. Alternatively, search terminates with negative result as soon as any count becomes negative.
Here is the detailed explanation and implementation in C#: Testing If Two Strings are Anagrams
If strings have only ASCII characters:
create an array of 256 length
traverse the first string and increment counter in the array at index = ascii value of the character. also keep counting characters to find length when you reach end of string
traverse the second string and decrement counter in the array at index = ascii value of the character. If the value is ever 0 before decrementing, return false since the strings are not anagrams. also, keep track of the length of this second string.
at the end of the string traversal, if lengths of the two are equal, return true, else, return false.
If string can have unicode characters, then use a hash map instead of an array to keep track of the frequency. Rest of the algorithm remains same.
Notes:
calculating length while adding characters to array ensures that we traverse each string only once.
Using array in case of an ASCII only string optimizes space based on the requirement.
I guess your sorting algorithm is not really O(log n), is it?
The best you can get is O(n) for your algorithm, because you have to check every character.
You might use two tables to store the counts of each letter in every word, fill it with O(n) and compare it with O(1).
It seems that the following implementation works too, can you check?
int histogram[256] = {0};
for (int i = 0; i < strlen(str1); ++i) {
/* Just inc and dec every char count and
* check the histogram against 0 in the 2nd loop */
++histo[str1[i]];
--histo[str2[i]];
}
for (int i = 0; i < 256; ++i) {
if (histo[i] != 0)
return 0; /* not an anagram */
}
return 1; /* an anagram */
/* Program to find the strings are anagram or not*/
/* Author Senthilkumar M*/
Eg.
Anagram:
str1 = stackoverflow
str2 = overflowstack
Not anagram:`enter code here`
str1 = stackforflow
str2 = stacknotflow
int is_anagram(char *str1, char *str2)
{
int l1 = strlen(str1);
int l2 = strlen(str2);
int s1 = 0, s2 = 0;
int i = 0;
/* if both the string are not equal it is not anagram*/
if(l1 != l2) {
return 0;
}
/* sum up the character in the strings
if the total sum of the two strings is not equal
it is not anagram */
for( i = 0; i < l1; i++) {
s1 += str1[i];
s2 += str2[i];
}
if(s1 != s2) {
return 0;
}
return 1;
}
If both strings are of equal length proceed, if not then the strings are not anagrams.
Iterate each string while summing the ordinals of each character. If the sums are equal then the strings are anagrams.
Example:
public Boolean AreAnagrams(String inOne, String inTwo) {
bool result = false;
if(inOne.Length == inTwo.Length) {
int sumOne = 0;
int sumTwo = 0;
for(int i = 0; i < inOne.Length; i++) {
sumOne += (int)inOne[i];
sumTwo += (int)inTwo[i];
}
result = sumOne == sumTwo;
}
return result;
}
implementation in Swift 3:
func areAnagrams(_ str1: String, _ str2: String) -> Bool {
return dictionaryMap(forString: str1) == dictionaryMap(forString: str2)
}
func dictionaryMap(forString str: String) -> [String : Int] {
var dict : [String : Int] = [:]
for var i in 0..<str.characters.count {
if let count = dict[str[i]] {
dict[str[i]] = count + 1
}else {
dict[str[i]] = 1
}
}
return dict
}
//To easily subscript characters
extension String {
subscript(i: Int) -> String {
return String(self[index(startIndex, offsetBy: i)])
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
/**
* --------------------------------------------------------------------------
* Finding Anagrams in the given dictionary. Anagrams are words that can be
* formed from other words Ex :The word "words" can be formed using the word
* "sword"
* --------------------------------------------------------------------------
* Input : if choose option 2 first enter no of word want to compare second
* enter word ex:
*
* Enter choice : 1:To use Test Cases 2: To give input 2 Enter the number of
* words in dictionary
* 6
* viq
* khan
* zee
* khan
* am
*
* Dictionary : [ viq khan zee khan am]
* Anagrams 1:[khan, khan]
*
*/
public class Anagrams {
public static void main(String args[]) {
// User Input or just use the testCases
int choice;
#SuppressWarnings("resource")
Scanner scan = new Scanner(System.in);
System.out.println("Enter choice : \n1:To use Test Cases 2: To give input");
choice = scan.nextInt();
switch (choice) {
case 1:
testCaseRunner();
break;
case 2:
userInput();
default:
break;
}
}
private static void userInput() {
#SuppressWarnings("resource")
Scanner scan = new Scanner(System.in);
System.out.println("Enter the number of words in dictionary");
int number = scan.nextInt();
String dictionary[] = new String[number];
//
for (int i = 0; i < number; i++) {
dictionary[i] = scan.nextLine();
}
printAnagramsIn(dictionary);
}
/**
* provides a some number of dictionary of words
*/
private static void testCaseRunner() {
String dictionary[][] = { { "abc", "cde", "asfs", "cba", "edcs", "name" },
{ "name", "mane", "string", "trings", "embe" } };
for (int i = 0; i < dictionary.length; i++) {
printAnagramsIn(dictionary[i]);
}
}
/**
* Prints the set of anagrams found the give dictionary
*
* logic is sorting the characters in the given word and hashing them to the
* word. Data Structure: Hash[sortedChars] = word
*/
private static void printAnagramsIn(String[] dictionary) {
System.out.print("Dictionary : [");// + dictionary);
for (String each : dictionary) {
System.out.print(each + " ");
}
System.out.println("]");
//
Map<String, ArrayList<String>> map = new LinkedHashMap<String, ArrayList<String>>();
// review comment: naming convention: dictionary contains 'word' not
// 'each'
for (String each : dictionary) {
char[] sortedWord = each.toCharArray();
// sort dic value
Arrays.sort(sortedWord);
//input word
String sortedString = new String(sortedWord);
//
ArrayList<String> list = new ArrayList<String>();
if (map.keySet().contains(sortedString)) {
list = map.get(sortedString);
}
list.add(each);
map.put(sortedString, list);
}
// print anagram
int i = 1;
for (String each : map.keySet()) {
if (map.get(each).size() != 1) {
System.out.println("Anagrams " + i + ":" + map.get(each));
i++;
}
}
}
}
I just had an interview and 'SolutionA' was basically my solution.
Seems to hold.
It might also work to sum all characters, or the hashCodes of each character, but it would still be at least O(n).
/**
* Using HashMap
*
* O(a + b + b + b) = O(a + 3*b) = O( 4n ) if a and b are equal. Meaning O(n) in total.
*/
public static final class SolutionA {
//
private static boolean isAnagram(String a, String b) {
if ( a.length() != b.length() ) return false;
HashMap<Character, Integer> aa = toHistogram(a);
HashMap<Character, Integer> bb = toHistogram(b);
return isHistogramsEqual(aa, bb);
}
private static HashMap<Character, Integer> toHistogram(String characters) {
HashMap<Character, Integer> histogram = new HashMap<>();
int i = -1; while ( ++i < characters.length() ) {
histogram.compute(characters.charAt(i), (k, v) -> {
if ( v == null ) v = 0;
return v+1;
});
}
return histogram;
}
private static boolean isHistogramsEqual(HashMap<Character, Integer> a, HashMap<Character, Integer> b) {
for ( Map.Entry<Character, Integer> entry : b.entrySet() ) {
Integer aa = a.get(entry.getKey());
Integer bb = entry.getValue();
if ( !Objects.equals(aa, bb) ) {
return false;
}
}
return true;
}
public static void main(String[] args) {
System.out.println(isAnagram("abc", "cba"));
System.out.println(isAnagram("abc", "cbaa"));
System.out.println(isAnagram("abcc", "cba"));
System.out.println(isAnagram("abcd", "cba"));
System.out.println(isAnagram("twelve plus one", "eleven plus two"));
}
}
I've provided a hashCode() based implementation as well. Seems to hold as well.
/**
* Using hashCode()
*
* O(a + b) minimum + character.hashCode() calculation, the latter might be cheap though. Native implementation.
*
* Risk for collision albeit small.
*/
public static final class SolutionB {
public static void main(String[] args) {
System.out.println(isAnagram("abc", "cba"));
System.out.println(isAnagram("abc", "cbaa"));
System.out.println(isAnagram("abcc", "cba"));
System.out.println(isAnagram("abcd", "cba"));
System.out.println(isAnagram("twelve plus one", "eleven plus two"));
}
private static boolean isAnagram(String a, String b) {
if ( a.length() != b.length() ) return false;
return toHashcode(a) == toHashcode(b);
}
private static long toHashcode(String str) {
long sum = 0; int i = -1; while ( ++i < str.length() ) {
sum += Objects.hashCode( str.charAt(i) );
}
return sum;
}
}
in java we can also do it like this and its very simple logic
import java.util.*;
class Anagram
{
public static void main(String args[]) throws Exception
{
Boolean FLAG=true;
Scanner sc= new Scanner(System.in);
System.out.println("Enter 1st string");
String s1=sc.nextLine();
System.out.println("Enter 2nd string");
String s2=sc.nextLine();
int i,j;
i=s1.length();
j=s2.length();
if(i==j)
{
for(int k=0;k<i;k++)
{
for(int l=0;l<i;l++)
{
if(s1.charAt(k)==s2.charAt(l))
{
FLAG=true;
break;
}
else
FLAG=false;
}
}
}
else
FLAG=false;
if(FLAG)
System.out.println("Given Strings are anagrams");
else
System.out.println("Given Strings are not anagrams");
}
}
How about converting into the int value of the character and sum up :
If the value of sum are equals then they are anagram to each other.
def are_anagram1(s1, s2):
return [False, True][sum([ord(x) for x in s1]) == sum([ord(x) for x in s2])]
s1 = 'james'
s2 = 'amesj'
print are_anagram1(s1,s2)
This solution works only for 'A' to 'Z' and 'a' to 'z'.

Resources