Checking if a word is a sub-Anagram of another (Java) - java

The words "unsold" & "silo" are sub-anagrams of the word "insidiously". That is, they can be spelt using only letters from "insidiously". There are obviously many more, and this concept is the basis of a word game found in 'The Australian' newspaper.
I'm trying to write a program that takes two arguments - a word, and another that might be a sub-anagram of this word and returns true if it is. So far this is what I've got:
public boolean isAnswer(String word, String base)
ArrayList<Character> characters = new ArrayList<>();
for(char x : base.toCharArray)
{
characters.add(x)
}
for(char y : word.toCharArray)
{
if(characters.contains(x))
{
characters.remove(x)
}
else
{
return false;
}
return true;
}
It does work, but if I'm looping through every word in the English dictionary this will be extremely taxing on memory. How can I do this without creating an ArrayList local variable?

If you want to make your existing program better consider using a SET instead of a LIST as it will
Eliminate the duplicate additions in your characters collection, saving space.
Save you some iterations in the next loop, saving time.
EDIT
However this optimization may not work in conditions pointed out by one of the comments.
EX - when an base has only "ab" & the word has "aab"

I would suggest you to go for a java.util.Set to avoid unnecessary iterations. Please find the code below:
private static boolean isSubAnagram() {
String str = "insidiously";
String anagram = "siloy";
Set<Character> set = new HashSet<Character>();
for(int i = 0 ; i < str.length() ; ++i){
set.add(new Character(str.charAt(i)));
}
int count = 0;
for(int i = 0 ; i < anagram.length() ; ++i){
if(set.contains(anagram.charAt(i))){
++count;
}
}
return count == anagram.length();
}
If the letter count in the base string and the so called sub anagram needs to be same then go for:
private static boolean isSubAnagram() {
String str = "insidiously";
String anagram = "siloyl";
List<Character> list = new ArrayList<Character>();
for(int i = 0 ; i < str.length() ; ++i){
list.add(new Character(str.charAt(i)));
}
for(int i = 0 ; i < anagram.length() ; ++i){
char curChar = anagram.charAt(i);
if(list.contains(curChar)){
list.remove(new Character(curChar));
continue;
}else{
return false;
}
}
return true;
}

One optimisation might be to first ensure that the word is not longer than the base.
public boolean isAnswer(String word, String base)
{
if (word.length() > base.length()) return false;
//...
}
I suspect if the words are exactly the same length, there may be a faster way than comparing all of the characters:
public boolean isAnswer(String word, String base)
{
if (word.length() > base.length()) {
return false;
}
else if (word.length() == base.length()) {
return isFullAnagram(); // I'll leave the implementation of this up to you
}
//...
}
The next step in optimising this would be to ensure you're not naively trying every word in the dictionary:
// Don't do this
public static void main(String... args)
{
String base = "something";
for (final String word : dictionary)
{
if (isAnswer(word, base)) // do something
}
}
// Don't do this
You have a big advantage in that any dictionary text file worth its salt will be pre-sorted. A basic optimisation would be to chunk your dictionary into 26 files - one for words starting with each letter - and skip any files which can't possibly match.
public static void main(String... args)
{
String base = "something";
Set<Characters> characters = // populate with chars from base
for (final Section section : dictionary)
{
if (characters.contains(section.getChar())
{
for (final String word : section)
{
if (isAnswer(word, base)) // do something
}
}
}
}
The next thing I would do is to look at parallelising this process. A basic approach would be to run each section on its own thread (so you're looking at up to about 12 threads for most common English words).
public static void main(String... args)
{
String base = "something";
Set<Characters> characters = // populate with chars from base
for (final Section section : dictionary)
{
if (characters.contains(section.getChar())
{
startMyThread(section, base);
}
}
}
You could get the threads to return a Future that you can check at the end. I'll leave that detail up to you.
A library like CUDA allows you to use very high concurrency by pushing computation to the GPU. You could have hundreds of threads running simultaneously. I'm not sure what a good strategy would look like in this case.
I'm working on the assumption that you'll only have to deal with the 26 letters of the Roman alphabet. Every such game I've seen in newspapers avoids words with diacritics: café, fiancée, naïve etc.

I believe this would be the solution that should run fast and consume the smallest amount of memory:
public class Snippet {
public static void main(String[] args) {
System.out.println(isAnswer("unsold", "insidiously"));
System.out.println(isAnswer("silo", "insidiously"));
System.out.println(isAnswer("silk", "insidiously"));
}
public static boolean isAnswer(String word, String base) {
char[] baseCharArr = base.toCharArray();
for (int wi = 0; wi < word.length(); wi++) {
boolean contains = false;
char wchar = word.charAt(wi);
for (int bi = 0; bi < baseCharArr.length; bi++) {
if (baseCharArr[bi]==wchar) {
baseCharArr[bi]='_'; // to not use this letter anymore we delete it using some sign that is non valid to from a word.
contains=true;
break;
}
}
if (!contains) {
return false;
}
}
return true;
}
}

Your code miss many {},;, () , It can't clearly compilet and work ^^, and i changed the order of the "if" and how to add all the base
public boolean isAnswer(String word, String base) {
ArrayList<Character> characters = new ArrayList<>();
characters.addAll(Arrays.asList(base.toCharArray()));
for (char y : word.toCharArray()) {
if (!characters.contains(y)) {
return false;
}
characters.remove(y);
}
return true;
}

You could directly replace in base. this is not very efficient and creates a lot of String objects but it is very easy to read:
public boolean isAnswer(String word, String base)
{
for (char ch : word.toCharArray())
{
base = base.replaceFirst("" + ch, "");
}
return base.trim().length() == 0;
}

Problems With the Current Approach / Other Answers
There are a lot of answers, but none of them is very efficient.
For every letter in a sub-anagram candidate, we search through a list and remove letters. One search takes linear time. Since we have to do a search for each letter, we end up with a quadratic time complexity.
Some people suggested to use a set instead of a list. Searching in a set takes constant time, so we would end up with linear time. However, the set approach fails when the same letter occurs multiple times.
The presented solutions are also slow because of constant speed factors. When we use List<Character> or Set<Character>, the chars of the String have to be boxed inside Character objects. Creating and handling these objects is much slower than using the primitive char type.
Solution
Multisets
We can us a multiset (also know as bag) to represent the letters in a word. For each word, we create a multiset of its letters and check whether that multiset is a subset of the base word's letter multiset.
Example
Base word "Food" has the multi set {f, o, o, d}.
Word "do" has the multi set {d, o}.
Word "dod" has the multi set {d, d, o}.
{d, o} is a subset of {f, o, o, d} ==> do is a sub-anagram of food.
{d, o, d} is not a subset of {f, o, o, d} ==> dod is not a sub-anagram of food.
Storing Multisets
Since we know, that only the characters 'a' to 'z' occur, we use an int array to represent a multiset. The value of array[0] is the number of 'a's; the value of array[1] is the number of 'b's, and so on.
array[1] can also be written as array['b' - 'a']
Example
The word "Food" with the multiset {f, o, o, d} is represented by the array
// Entry for: a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
int[] multiSet = {0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0};
Subset Check
a is subset of b if and only if a[i] <= b[i] for all i.
When we do the subset test while computing the multiset a, we don't have to check all 26 array entries, but only the entries which were set to a value greater than zero.
Re-use Work
We want to check a lot of words for one base word. We can re-use the multiset for the base word and don't have to compute it over and over again.
Instead of writing a method that returns true or false, we write a method that returns the list of all sub-anagrams for a given base word and a given dictionary (list of words to be checked).
Minor optimizations
If a word is longer than the base word, it cannot be a sub-anagram. In such cases, we don't have to compute the multiset for that word.
Implementation
public static List<String> subAnagrams(String base, List<String> dictionary) {
char[] usableChars = new char['z' - 'a'];
base = base.toLowerCase();
for (int i = 0; i < base.length(); ++i) {
++usableChars[base.charAt(i) - 'a'];
}
List<String> subAnagrams = new ArrayList<>();
for (String candidate : dictionary) {
boolean isSubAnagram = candidate.length() <= base.length();
candidate = candidate.toLowerCase();
char[] usedChars = new char['z' - 'a'];
for (int i = 0; isSubAnagram && i < candidate.length(); ++i) {
int charIndex = candidate.charAt(i) - 'a';
isSubAnagram = ++usedChars[charIndex] <= usableChars[charIndex];
}
if (isSubAnagram) {
subAnagrams.add(candidate);
}
}
return subAnagrams;
}
Example usage
public static void main(String[] args) {
List<String> dict = new ArrayList<>();
dict.add("Do");
dict.add("Odd");
dict.add("Good");
dict.add("World");
dict.add("Foo");
System.out.println(subAnagrams("Food", dict));
}
prints [do, foo]

Related

Comparing array items, index out of bound

I have a piece of code and I'm a bit confused how to deal with my issue so, please review method below. I was trying to search for a solution but unfortunately none of them fit my needs so I am looking for an advice here. The method is taking a String and removing duplicated characters so for example - input: ABBCDEF should return ABCDEF, but when entering i+1 in the last iteration I got IndexOutOfBound Exception, so I can iterate until string.length-1 but then I loose the last element, what is the SMARTEST solution in your opinion, thanks.
public String removeDuplicates(String source){
if(source.length() < 2){
return source;
}
StringBuilder noDuplicates = new StringBuilder();
char[] string = source.toCharArray();
for(int i = 0; i < string.length-1; i++){
if(string[i] != string[i+1]){
noDuplicates.append(string[i]);
}
}
return noDuplicates.toString();
}
You could do this like so: append the first character in source, and then only append subsequent characters if they are not equal to the previously-appended character.
if (source.isEmpty()) {
return source; // Or "", it doesn't really matter.
}
StringBuilder sb = new StringBuilder();
sb.append(source.charAt(0));
for (int i = 1; i < source.length(); ++i) {
char c = source.charAt(i);
if (c != sb.charAt(sb.length() - 1)) {
sb.append(c);
}
}
return sb.toString();
But if you wanted to do this more concisely, you could do it with regex:
return source.replaceAll("(.)\\1+", "$1");
You could simply append the last character after the loop:
public String removeDuplicates(String source){
...
noDuplicates.append(string[string.length - 1]);
return noDuplicates.toString();
}
You have a simple logic error:
You make your string to a char array.
That is fine, but the length property of any array will show you the
human way of counting if someting is in it.
If there is 1 element the length will be 1
2 -> 2
3 -> 3
etc.
You get the idea.
So when you go string[i + 1] you go one character to far.
You could just change the abort condition to
i < = string.length - 2
Or you could write a string iterator, to be able to access the next element, but
that seems like overkill for this example
This is just what LinkedHashSet was made for! Under the hood it's a HashSet with an iterator to keep track of insertion order, so you can remove duplicates by adding to the set, then reconstruct the string with guaranteed ordering.
public static String removeDuplicates(String source) {
Set<String> dupeSet = new LinkedHashSet<>();
for (Character v : source.toCharArray()) {
dupeSet.add(v.toString());
}
return String.join("", dupeSet);
}
If you wish to remove all repeating characters regardless of their position in the given String you might want to consider using the chars() method which provides a IntStream of the chars and that has the distinct() method to filter out repeating values. You can then put them back together with a StringBuilder like so:
public class RemoveDuplicatesTest {
public static void main(String[] args) {
String value = "ABBCDEFE";
System.out.println("No Duplicates: " + removeDuplicates(value));
}
public static String removeDuplicates(String value) {
StringBuilder result = new StringBuilder();
value.chars().distinct().forEach(c -> result.append((char) c));
return result.toString();
}
}

how to compare two strings to find common substring

i get termination due to timeout error when i compile. Please help me
Given two strings, determine if they share a common substring. A substring may be as small as one character.
For example, the words "a", "and", "art" share the common substring "a" . The words "be" and "cat" do not share a substring.
Input Format
The first line contains a single integer , the number of test cases.
The following pairs of lines are as follows:
The first line contains string s1 .
The second line contains string s2 .
Output Format
For each pair of strings, return YES or NO.
my code in java
public static void main(String args[])
{
String s1,s2;
int n;
Scanner s= new Scanner(System.in);
n=s.nextInt();
while(n>0)
{
int flag = 0;
s1=s.next();
s2=s.next();
for(int i=0;i<s1.length();i++)
{
for(int j=i;j<s2.length();j++)
{
if(s1.charAt(i)==s2.charAt(j))
{
flag=1;
}
}
}
if(flag==1)
{
System.out.println("YES");
}
else
{
System.out.println("NO");
}
n--;
}
}
}
any tips?
Below is my approach to get through the same HackerRank challenge described above
static String twoStrings(String s1, String s2) {
String result="NO";
Set<Character> set1 = new HashSet<Character>();
for (char s : s1.toCharArray()){
set1.add(s);
}
for(int i=0;i<s2.length();i++){
if(set1.contains(s2.charAt(i))){
result = "YES";
break;
}
}
return result;
}
It passed all the Test cases without a time out issue.
The reason for the timeout is probably: to compare two strings that each are 1.000.000 characters long, your code needs 1.000.000 * 1.000.000 comparisons, always.
There is a faster algorithm that only needs 2 * 1.000.000 comparisons. You should use the faster algorithm instead. Its basic idea is:
for each character in s1: add the character to a set (this is the first million)
for each character in s2: test whether the set from step 1 contains the character, and if so, return "yes" immediately (this is the second million)
Java already provides a BitSet data type that does all you need. It is used like this:
BitSet seenInS1 = new BitSet();
seenInS1.set('x');
seenInS1.get('x');
Since you're worried about execution time, if they give you an expected range of characters (for example 'a' to 'z'), you can solve it very efficiently like this:
import java.util.Arrays;
import java.util.Scanner;
public class Whatever {
final static char HIGHEST_CHAR = 'z'; // Use Character.MAX_VALUE if unsure.
public static void main(final String[] args) {
final Scanner scanner = new Scanner(System.in);
final boolean[] characterSeen = new boolean[HIGHEST_CHAR + 1];
mainloop:
for (int word = Integer.parseInt(scanner.nextLine()); word > 0; word--) {
Arrays.fill(characterSeen, false);
final String word1 = scanner.nextLine();
for (int i = 0; i < word1.length(); i++) {
characterSeen[word1.charAt(i)] = true;
}
final String word2 = scanner.nextLine();
for (int i = 0; i < word2.length(); i++) {
if (characterSeen[word2.charAt(i)]) {
System.out.println("YES");
continue mainloop;
}
}
System.out.println("NO");
}
}
}
The code was tested to work with a few inputs.
This uses a fast array rather than slower sets, and it only creates one non-String object (other than the Scanner) for the entire run of the program. It also runs in O(n) time rather than O(n²) time.
The only thing faster than an array might be the BitSet Roland Illig mentioned.
If you wanted to go completely overboard, you could also potentially speed it up by:
skipping the creation of a Scanner and all those String objects by using System.in.read(buffer) directly with a reusable byte[] buffer
skipping the standard process of having to spend time checking for and properly handling negative numbers and invalid inputs on the first line by making your own very fast int parser that just assumes it's getting the digits of a valid nonnegative int followed by a newline
There are different approaches to solve this problem but solving this problem in linear time is a bit tricky.
Still, this problem can be solved in linear time. Just apply KMP algorithm in a trickier way.
Let's say you have 2 strings. Find the length of both strings first. Say length of string 1 is bigger than string 2. Make string 1 as your text and string 2 as your pattern. If the length of the string is n and length of the pattern is m then time complexity of the above problem would be O(m+n) which is way faster than O(n^2).
In this problem, you need to modify the KMP algorithm to get the desired result.
Just need to modify the KMP
public static void KMPsearch(char[] text,char[] pattern)
{
int[] cache = buildPrefix(pattern);
int i=0,j=0;
while(i<text.length && j<pattern.length)
{
if(text[i]==pattern[j])
{System.out.println("Yes");
return;}
else{
if(j>0)
j = cache[j-1];
else
i++;
}
}
System.out.println("No");
return;
}
Understanding Knuth-Morris-Pratt Algorithm
There are two concepts involved in solving this question.
-Understanding that a single character is a valid substring.
-Deducing that we only need to know that the two strings have a common substring — we don’t need to know what that substring is.
Thus, the key to solving this question is determining whether or not the two strings share a common character.
To do this, we create two sets, a and b, where each set contains the unique characters that appear in the string it’s named after.
Because sets 26 don’t store duplicate values, we know that the size of our sets will never exceed the letters of the English alphabet.
In addition, the small size of these sets makes finding the intersection very quick.
If the intersection of the two sets is empty, we print NO on a new line; if the intersection of the two sets is not empty, then we know that strings and share one or more common characters and we print YES on a new line.
In code, it may look something like this
import java.util.*;
public class Solution {
static Set<Character> a;
static Set<Character> b;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
for(int i = 0; i < n; i++) {
a = new HashSet<Character>();
b = new HashSet<Character>();
for(char c : scan.next().toCharArray()) {
a.add(c);
}
for(char c : scan.next().toCharArray()) {
b.add(c);
}
// store the set intersection in set 'a'
a.retainAll(b);
System.out.println( (a.isEmpty()) ? "NO" : "YES" );
}
scan.close();
}
}
public String twoStrings(String sOne, String sTwo) {
if (sOne.equals(sTwo)) {
return "YES";
}
Set<Character> charSetOne = new HashSet<Character>();
for (Character c : sOne.toCharArray())
charSetOne.add(c);
Set<Character> charSetTwo = new HashSet<Character>();
for (Character c : sTwo.toCharArray())
charSetTwo.add(c);
charSetOne.retainAll(charSetTwo);
if (charSetOne.size() > 0) {
return "YES";
}
return "NO";
}
This must work. Tested with some large inputs.
Python3
def twoStrings(s1, s2):
flag = False
for x in s1:
if x in s2:
flag = True
if flag == True:
return "YES"
else:
return "NO"
if __name__ == '__main__':
q = 2
text = [("hello","world"), ("hi","world")]
for q_itr in range(q):
s1 = text[q_itr][0]
s2 = text[q_itr][1]
result = twoStrings(s1, s2)
print(result)
static String twoStrings(String s1, String s2) {
for (Character ch : s1.toCharArray()) {
if (s2.indexOf(ch) > -1)
return "YES";
}
return "NO";
}

Number of words in a string that are not in an array of strings

I want to create a method that returns the number of words in a string that have no occurrences of words in the array of strings. I want to implement this logic only using anything in the java.lang package.
public int count(String a, String[] b) {
}
E.g.
count(" hey are you there ", new String[]{ "are", "i", "am"})
would return 3 as there is the word "are" in the string.
First off, I think I have to use the string.split function to convert the string to an array of strings. Any ideas?
You could simply do something like:
public int count(String a, String[] b) {
int count = b.length;
for(String s : b) if(a.contains(s)) count--;
return count;
}
EDIT: I might have been confused, I thought you wanted the # of strings in b not in a (in your example it would still be 3). In that case, from your example, split seems inconvenient unless you use regex, so you could create a String[] using Scanner:
public int count(String a, String[] b) {
ArrayList<String> words = new ArrayList<String>();
Scanner scan = new Scanner(a);
while(scan.hasNext()) words.add(scan.next());
int count = words.size();
for(String s : words) if(/*b contains s*/) count--;
return count;
}
Follow the steps to complete the task.
Use StringTokenizer to tokenize the String a.
Convert String Array b to Collection, so that you can check if it contains the given token.
Use loop to get next token from StringTokenizer and check if it contains in List.
-
Try below code, it'll work.
EDIT : Using java.util package.
public int count(String a, String[] b) {
java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(a);
java.util.List bList = java.util.Arrays.asList(b);
int tokens = tokenizer.countTokens();
int counter = tokens;
for(int i=0;i<tokens;i++) {
String token = tokenizer.nextToken().trim();
if(bList.contains(token)) {
counter--;
}
}
return counter;
}
By using this, you can get the counter in just one for loop.
EDIT :: Using java.lang package only.
public int count(String a, String[] b) {
String[] words = a.split(" ");
int tokens = words.length;
int wordCount = 0;
int counter = 0;
for(int i=0;i<tokens;i++) {
String token = words[i].trim();
if(token.length() <= 0) {
continue;
}
wordCount++;
for(String bItem : b) {
if(bItem.equals(token)) {
counter++;
break;
}
}
}
return wordCount - counter;
}
You logic should go somewhat like this:
Split a, right. Now you have a list of words. In a real life, you should probably also try to clarify the requirement—what exactly is a “word”? A reasonable assumption is that it's a sequence of non-whitespace characters, but could be something different (for example, a sequence of letters).
Iterate over a and check whether each word is in b. If it isn't, increment your counter. But every check is a linear search in b, leading to the total complexity of O(nm), so...
Before iterating, convert b into a HashSet. This is a linear operation, but then your main loop will also become a linear operation, therefore the total complexity will be O(m + n).
If you have to do this thing repeatedly for different strings, but the same word list, consider creating a WordCounter class so you only have to create the HashSet once in the constructor.

How to look for a target in an array using two string array's

So in looking around for an answer to my question, i have only been able to find map structures or just comparing the strings and having to code to stop. I need to be able to essentially translate between languages and print out the translation and have the user to able to ask again to translate another word. I have 2 strings of 10 matching words from English to Russian. I need to able to use a target (or key) to find the translation. Also I need to use a sequential search.
import java.util.*;
public class CISCLabTwo
{
public static void main (String [] args)
{
Scanner keyBoard = new Scanner (System.in);
String [] english = {"House", "Fat", "Monkey", "Trip", "Jumbo", "Chicken", "Unicorn", "Radio", "Shack", "Xylophone"};
String [] russian = {"Dom", "Zhir", "Obeziana", "Poezdka", "Ogromniy", "Kuricha", "Edinorog", "Raadiioo", "Hizhina", "Ksilofon"};
System.out.println ("House, Fat, Monkey, Trip, Jumbo, Chicken, Unicorn, Radio, Shack, Xylophone");
System.out.println("Enter a Word From Above to Translate to Russian: ");
int i = 0;
for (i = 0; i < english.length; i++)
if (english[i]=target){
return i;
}
else{
return - 1;
}
}//end class
public static int translate (String [] english, String target)
}//end main
http://en.wikipedia.org/wiki/Sequential_search
Basically you create a for-loop checking for a match in the english array.
When you have a match the function will return the position of the string in the given array. Use this position to get the corresponding Russian translation.
public static int translate(String [] english, String target)
{
for(int i = 0; i < english.length; i++){
if(english[i].equals(target)){
// Found on position i
return i;
}
}
return -1;
}
You might want to rename the function because it doesn't really translate and only returns an integer and not a string.
Firstly, it's confusing to individually handle two arrays in this way. You probably want to create an extra class in the same file:
class Word {
String english;
String russian;
}
Then you can create the following array:
Word[] words = new Word[10];
That way, you can translate using a separate method, as follows:
String translate(String eng) {
for (Word w : words) if (eng.equals(w.english)) return w.russian;
return null;
}
All you need to do is get the index, print the Russian word then break the loop.
If just printing within main then you can do this.
for (i = 0; i < english.length; i++)
{
if (english[i].equals(target))
{
System.out.println(russian[i]; //Print the russian word
break; //stop looping
}
}
Otherwise if you want to have your translate method that returns the index of the word you could do it like so
public static int translate (String [] english, String target)
{
for (i = 0; i < english.length; i++)
{
if (english[i].equals(target))
return i; // No need for the else statement as it would
// fail on first iteration if it wasnt the word
}
return -1; // After loop exits return -1 as was not found
}
Then in main you would call
String russianWord = russian[translate(english, target)];
As for your code, the proper check is in your for-next loop is
if (english[i].equals(target))
return i;
Also, consider whether the case of the words matters. In your example, is "House" the same as "house"? If case doesn't matter, you should use equalsIgnoreCase() instead of equals, i.e.
if (english[i].equalsIgnoreCase(target))
return i;
(moved later cause it seems like this was homework)
You could save yourself a little work by using two ArrayList to hold the words, since ArrayList has an indexOf() method to do the linear search. (I have no idea why the Arrays utility class does not have an indexOf method).
That said, a map based structure seems like a much better fit (and will be more efficient).

Generate all words using Java

I want to know how to generate all words using java from specified characters and length
String first[]={"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
String second[]={"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
String ch ="";
String total[];
for(int i = 0;i<26;i++) {
for(int j = 0;j<26;j++) {
ch+=first[i]+first[j];
System.out.println(ch);
}
}
I get only 576 words only by this program, but the 26! words is 4.03291461 × 10^26
How to write the program in java?
public class Words {
static char[] alphabet = "abcdefghijklmnopqrstuvwxyz".toCharArray();
static void generate(StringBuilder sb, int n) {
if (n == sb.length()) {
System.out.println(sb.toString());
return;
}
for (char letter : alphabet) {
sb.setCharAt(n, letter);
generate(sb, n + 1);
}
}
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
for (int length = 2; length <= 5; length++) {
sb.setLength(length);
generate(sb, 0);
}
}
}
This generates all 2-letters, 3-letters, 4-letters, and 5-letters "words". It uses a standard recursive algorithm.
See also
Given an array of integers [x0 x1 x2], how do you calculate all possible permutations from [0 0 0] to [x0 x1 x2]?
On a more mathematical note, people often confuse what the term "permutation" means. Yes, there are 26! permutations of the 26 letters a-z -- that's A LOT of strings, but this does not include aa, ab, etc. It includes all strings where the 26 letters each appear exactly once.
Consider what you're doing:
you're looping through the first array once, and looping through the second once for each iteration through that loop.
That's going to yield you a total of 26^2 results, or 676 (not 576).
And the way you're constructing the output is very specific, check what you get and you'll notice a highly explicit pattern in there.
The second array of course is never used at all, so completely superfluous.
The solution is to write out on paper how you'd go about it were you to attempt it by hand, then attempt to translate that into code.
For one you're not going to want to have only words of a specific length (which you get) or specific patterns of letters (which you also get).
but the 26! words is 4.03291461 × 1026
how to write the program in java
You don't write that program in Java or any other language. It would be pointless because it would literally take billions of years to finish.
But the number is also completely wrong for your intended result in the comments. 26! is the number of permutations, i.e. the different ways to order 26 elements without repetition. The number of words would be 26^n, where n is the length.
Here's my solution. It's kind of quick, so don't be too hard on the optimization.
public static void printWords(int length) {
if (length < 1)
throw new IllegalArgumentException();
printWordsRec("", length);
}
private static void printWordsRec(String base, int length) {
for (char c = 'a'; c <= 'z'; c++) {
if (length == 1) {
System.out.println(base + c);
}
else {
printWordsRec(base + c, length - 1);
}
}
}

Categories