Debugging the code for palindrome pairs in java - java

I was solving the problem of palindrome pairs on leetCode. So here I found a complete solution with explanation for it. Here is the code:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
class TrieNode {
TrieNode[] next;
int index;
List<Integer> list;
TrieNode() {
next = new TrieNode[26];
index = -1;
list = new ArrayList<>();
}
}
public class Trie {
public List<List<Integer>> palindromePairs(String[] words) {
List<List<Integer>> res = new ArrayList<>();
TrieNode root = new TrieNode();
for (int i = 0; i < words.length; i++) {
addWord(root, words[i], i);
}
for (int i = 0; i < words.length; i++) {
search(words, i, root, res);
}
return res;
}
private void addWord(TrieNode root, String word, int index) {
for (int i = word.length() - 1; i >= 0; i--) {
int j = word.charAt(i) - 'a';
if (root.next[j] == null) {
root.next[j] = new TrieNode();
}
if (isPalindrome(word, 0, i)) {
root.list.add(index);
}
root = root.next[j];
}
root.list.add(index);
root.index = index;
}
private void search(String[] words, int i, TrieNode root, List<List<Integer>> res) {
for (int j = 0; j < words[i].length(); j++) {
if (root.index >= 0 && root.index != i && isPalindrome(words[i], j, words[i].length() - 1)) {
res.add(Arrays.asList(i, root.index));
}
root = root.next[words[i].charAt(j) - 'a'];
if (root == null) return;
}
for (int j : root.list) {
if (i == j) continue;
res.add(Arrays.asList(i, j));
}
}
private boolean isPalindrome(String word, int i, int j) {
while (i < j) {
if (word.charAt(i++) != word.charAt(j--)) return false;
}
return true;
}
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
long n = Integer.parseInt(sc.nextLine());
String[] s = new String[(int) n];
for (long i = 0; i < n; i++)
s[(int) i] = sc.nextLine();
Trie t = new Trie();
System.out.println(t.palindromePairs(s));
}
}
But now I'm facing some problems with code. By the explanation of algorithm given, I thought it could give us all palindromes in a set of strings. But for example if we have these strings as input:
3
abcdfd
cba
cba
Obviously we can make two palindromes by concatenating strings. But the code just finds one palindrome pairs. I just can't understand where the problem is.

This happens because in the above implementation of the Trie, every distinc word can only be stored once. Here the second occurrence of "cba" overrides the previous one with index 2. So when searching for the word "abcdfd", there is only one "cba" in the trie and hence only one palindrome is detected.
As a simple solution, you can keep a list of indices, instead of a single index filed, for each TrieNode and change your addWord and search methods accordingly to handle the case of duplicate words.

Related

How to find the number of ways the given abbreviations can be formed from the given sentence - java

I'm developing a word building game. I got stuck with the following scenario.
I have a word which is an abbreviation; Also, I have one sentence, from which I have to determine the number of ways it can be formed.
for example:
1 abbreviation: ACM
Sentence: academy concern manager.
output: 4.
2: abbreviation: RADAR
Sentence: Radio addition ranger.
output: 6
Ground Rules: atleast one char from each word should be used from each word to form the abbreviation
Explanation: in second example, from the word radio, rad-ra-r can be used to form the abbreviation in such a way with the following words the entire abbreviation can be achieved. and the order should be maintained.
so far i tried to do something like this
public static void checkOccurence(String[] in) {
String word = "";
int k = 0, n;
int total = 0, c = 0;
int extra = 1;
for (int i = 1; i < in.length; i++) {
int v = 0;
n = k;
word = in[i].toUpperCase();
if (k < ab.length()) {
for (int j = 0; j < word.length(); j++) {
if (k < ab.length()) {
if (word.charAt(j) == ab.charAt(k)) {
k++;
}
}
}
}
for (int j = 0; j < word.length(); j++) {
for (int l = 0; l < ab.length(); l++) {
if (word.charAt(j) == ab.charAt(l)) {
if (j != l && l < k - 1) {
v += calculateExtra(word, j, l, k);
} else if (j == l && l < k - 1 && calculateExtra(word, j, l, k) != 1) {
c++;
}
}
}
}
v += c;
System.out.println(v);
if (k == n && v > 0) {
v = 0;
}
total += v;
}
if (k == ab.length() && total != 0)
count += total;
if (k == ab.length() && total == 0)
count++;
}
I do not think it's perfect, and I sure there is a lot to improve, but here is a solution that works on both your example(There may be additional edge cases)
I wrote this as an example of how to approach this problem.
first, we calculate all options and then we check which nodes fulfill all the conditions.
do notice the LowerCase game, it is important!
public class Main {
public static void main(String[] args) {
// write your code here
Node exampleNode = new Node();
exampleNode.mySentence="academy concern manager".toLowerCase();
exampleNode.chars="ACM".toLowerCase().toCharArray();
exampleNode.nextNode();
System.out.println(getOutput(exampleNode));
exampleNode = new Node();
exampleNode.mySentence="Radio addition ranger".toLowerCase();
exampleNode.chars="RADAR".toLowerCase().toCharArray();
exampleNode.nextNode();
System.out.println(getOutput(exampleNode));
}
public static int getOutput(Node node){
int output=0;
if(node.chars.length==0&& node.mySentence.indexOf(" ")==-1){
Node nextNode=node;
String s="";
while (nextNode!=null){
String sub =nextNode.myChar+nextNode.mySentence;
s=replaceLast(s.toLowerCase(),"",sub)+s;
nextNode = nextNode.father;
}
boolean wordWithoutChar = false;
for (String word:s.split(" ")) {
boolean noCharInThisWord=true;
for (char c:word.toCharArray()) {
if(c<='Z'&&c>='A'){
noCharInThisWord = false;
}
}
if(noCharInThisWord){
wordWithoutChar=noCharInThisWord;
}
}
if(!wordWithoutChar){
System.out.println(s);
output++;
}
}
for (Node n:node.nodes) {
output +=getOutput(n);
}
return output;
}
public static String replaceLast(String find, String replace, String string) {
int lastIndex = string.lastIndexOf(find);
if (lastIndex == -1) {
return string;
}
String beginString = string.substring(0, lastIndex);
String endString = string.substring(lastIndex + find.length());
return beginString + replace + endString;
}
public static class Node{
List<Node> nodes = new ArrayList<>();
Node father =null;
char myChar=0;
char[] chars=null;
String mySentence="";
public void nextNode() {
int index=0;
if(chars.length>0){
while (index<mySentence.length()){
if(mySentence.toCharArray()[index]==chars[0]){
Node son = new Node();
son.chars = Arrays.copyOfRange(chars, 1, chars.length);
son.mySentence=mySentence.substring(index+1);
son.father=this;
son.myChar= (char) (chars[0]-32);
son.nextNode();
nodes.add(son);
}
index++;
}
}
return;
}
}
}
output:
Academy Concern Manager
Academy conCern Manager
acAdemy Concern Manager
acAdemy conCern Manager
4
RADio Addition Ranger
RADio Addition rangeR
RAdio aDdition rAngeR
RAdio adDition rAngeR
Radio ADdition rAngeR
Radio AdDition rAngeR
6

Algo: Find anagram of given string at a given index in lexicographically sorted order

Need to write an Algo to find Anagram of given string at a given index in lexicographically sorted order. For example:
Consider a String: ABC then all anagrams are in sorted order: ABC ACB
BAC BCA CAB CBA. So, for index 5 value is: CAB. Also, consider the case of duplicates like for AADFS anagram would be DFASA at index 32
To do this I have written Algo but I think there should be something less complex than this.
import java.util.*;
public class Anagram {
static class Word {
Character c;
int count;
Word(Character c, int count) {
this.c = c;
this.count = count;
}
}
public static void main(String[] args) {
System.out.println(findAnagram("aadfs", 32));
}
private static String findAnagram(String word, int index) {
// starting with 0 that's y.
index--;
char[] array = word.toCharArray();
List<Character> chars = new ArrayList<>();
for (int i = 0; i < array.length; i++) {
chars.add(array[i]);
}
// Sort List
Collections.sort(chars);
// To maintain duplicates
List<Word> words = new ArrayList<>();
Character temp = chars.get(0);
int count = 1;
int total = chars.size();
for (int i = 1; i < chars.size(); i++) {
if (temp == chars.get(i)) {
count++;
} else {
words.add(new Word(temp, count));
count = 1;
temp = chars.get(i);
}
}
words.add(new Word(temp, count));
String anagram = "";
while (index > 0) {
Word selectedWord = null;
// find best index
int value = 0;
for (int i = 0; i < words.size(); i++) {
int com = combination(words, i, total);
if (index < value + com) {
index -= value;
if (words.get(i).count == 1) {
selectedWord = words.remove(i);
} else {
words.get(i).count--;
selectedWord = words.get(i);
}
break;
}
value += com;
}
anagram += selectedWord.c;
total--;
}
// put remaining in series
for (int i = 0; i < words.size(); i++) {
for (int j = 0; j < words.get(i).count; j++) {
anagram += words.get(i).c;
}
}
return anagram;
}
private static int combination(List<Word> words, int index, int total) {
int value = permutation(total - 1);
for (int i = 0; i < words.size(); i++) {
if (i == index) {
int v = words.get(i).count - 1;
if (v > 0) {
value /= permutation(v);
}
} else {
value /= permutation(words.get(i).count);
}
}
return value;
}
private static int permutation(int i) {
if (i == 1) {
return 1;
}
return i * permutation(i - 1);
}
}
Can someone help me with less complex logic.
I write the following code to solve your problem.
I assume that the given String is sorted.
The permutations(String prefix, char[] word, ArrayList permutations_list) function generates all possible permutations of the given string without duplicates and store them in a list named permutations_list. Thus, the word: permutations_list.get(index -1) is the desired output.
For example, assume that someone gives us the word "aab".
We have to solve this problem recursively:
Problem 1: permutations("","aab").
That means that we have to solve the problem:
Problem 2: permutations("a","ab").
String "ab" has only two letters, therefore the possible permutations are "ab" and "ba". Hence, we store in permutations_list the words "aab" and "aba".
Problem 2 has been solved. Now we go back to problem 1.
We swap the first "a" and the second "a" and we realize that these letters are the same. So we skip this case(we avoid duplicates).
Next, we swap the first "a" and "b". Now, the problem 1 has changed and we want to solve the new one:
Problem 3: permutations("","baa").
The next step is to solve the following problem:
Problem 4: permutations("b","aa").
String "aa" has only two same letters, therefore there is one possible permutation "aa". Hence, we store in permutations_list the word "baa"
Problem 4 has been solved. Finally, we go back to problem 3 and problem 3 has been solved. The final permutations_list contains "aab", "aba" and "baa".
Hence, findAnagram("aab", 2) returns the word "aba".
import java.util.ArrayList;
import java.util.Arrays;
public class AnagramProblem {
public static void main(String args[]) {
System.out.println(findAnagram("aadfs",32));
}
public static String findAnagram(String word, int index) {
ArrayList<String> permutations_list = new ArrayList<String>();
permutations("",word.toCharArray(), permutations_list);
return permutations_list.get(index - 1);
}
public static void permutations(String prefix, char[] word, ArrayList<String> permutations_list) {
boolean duplicate = false;
if (word.length==2 && word[0]!=word[1]) {
String permutation1 = prefix + String.valueOf(word[0]) + String.valueOf(word[1]);
permutations_list.add(permutation1);
String permutation2 = prefix + String.valueOf(word[1]) + String.valueOf(word[0]);
permutations_list.add(permutation2);
return;
}
else if (word.length==2 && word[0]==word[1]) {
String permutation = prefix + String.valueOf(word[0]) + String.valueOf(word[1]);
permutations_list.add(permutation);
return;
}
for (int i=0; i < word.length; i++) {
if (!duplicate) {
permutations(prefix + word[0], new String(word).substring(1,word.length).toCharArray(), permutations_list);
}
if (i < word.length - 1) {
char temp = word[0];
word[0] = word[i+1];
word[i+1] = temp;
}
if (i < word.length - 1 && word[0]==word[i+1]) duplicate = true;
else duplicate = false;
}
}
}
I think your problem will become a lot simpler if you considerate generating the anagrams in alphabetical order, so you don't have to sort them afterwards.
The following code (from Generating all permutations of a given string) generates all permutations of a String. The order of these permutations are given by the initial order of the input String. If you sort the String beforehand, the anagrams will thus be added in sorted order.
to prevent duplicates, you can simply maintain a Set of Strings you have already added. If this Set does not contain the anagram you're about to add, then you can safely add it to the list of anagrams.
Here is the code for the solution i described. I hope you find it to be simpler than your solution.
public class Anagrams {
private List<String> sortedAnagrams;
private Set<String> handledStrings;
public static void main(String args[]) {
Anagrams anagrams = new Anagrams();
List<String> list = anagrams.permutations(sort("AASDF"));
System.out.println(list.get(31));
}
public List<String> permutations(String str) {
handledStrings = new HashSet<String>();
sortedAnagrams = new ArrayList<String>();
permutation("", str);
return sortedAnagrams;
}
private void permutation(String prefix, String str) {
int n = str.length();
if (n == 0){
if(! handledStrings.contains(prefix)){
//System.out.println(prefix);
sortedAnagrams.add(prefix);
handledStrings.add(prefix);
}
}
else {
for (int i = 0; i < n; i++)
permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i + 1, n));
}
}
public static String sort(String str) {
char[] arr = str.toCharArray();
Arrays.sort(arr);
return new String(arr);
}
}
If you create a "next permutation" method which alters an array to its next lexicographical permutation, then your base logic could be to just invoke that method n-1 times in a loop.
There's a nice description with code that can be found here. Here's both the basic pseudocode and an example in Java adapted from that page.
/*
1. Find largest index i such that array[i − 1] < array[i].
(If no such i exists, then this is already the last permutation.)
2. Find largest index j such that j ≥ i and array[j] > array[i − 1].
3. Swap array[j] and array[i − 1].
4. Reverse the suffix starting at array[i].
*/
boolean nextPermutation(char[] array) {
int i = array.length - 1;
while (i > 0 && array[i - 1] >= array[i]) i--;
if (i <= 0) return false;
int j = array.length - 1;
while (array[j] <= array[i - 1]) j--;
char temp = array[i - 1];
array[i - 1] = array[j];
array[j] = temp;
j = array.length - 1;
while (i < j) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
return true;
}

Find length of longest palindrome. Is it possible to do this without an extra data structure?

The problem is to find the LENGTH of the longest palindrome, not the palindrome itself. I used a Map for this, but I was wondering if there was a way to do it without using other data structures.
Also, how long does this algorithm take to run?
public class Solution {
public int longestPalindrome(String s) {
boolean oddExists = false; // checks if there are odd characters
int length = s.length(); // assumes that highest possible length can be the original length
Map<Character, Integer> map = new HashMap<Character, Integer>(); // counts characters
for (int i = 0; i < length; i++){
if (!map.containsKey(s.charAt(i))){map.put(s.charAt(i), 0);}
map.put(s.charAt(i), map.get(s.charAt(i)) + 1);
}
for (char x : map.keySet()){ // go through all the characters
if (map.get(x) % 2 != 0){ // if there are odd characters, length of palindrome decreases
oddExists = true; // odd character found
length--; // length decreased
}
}
if (oddExists){length++;} // one odd character can be allowed to be at the center of the palindrome
return length;
}
}
Try this.
public int longestPalindrome(String s) {
s = s.toLowerCase();
int length = s.length();
char[] map = new char[26];
for (int i = 0; i < length; i++)
++map[s.charAt(i) - 'a'];
for (int i = 0; i < 26; ++i)
if ((map[i] & 1) != 0)
--length;
if (length < s.length())
++length;
return length;
}
This is my solution. It does not use any maps.
public class Algo {
public static void main(String[] args){
/*
System.out.println(isPalindrome("a"));
System.out.println(isPalindrome(""));
System.out.println(isPalindrome("aba"));
System.out.println(isPalindrome("akka"));
System.out.println(isPalindrome("lolz"));
*/
System.out.println(longestPalindrome("lolz"));
System.out.println(longestPalindrome("akka"));
System.out.println(longestPalindrome("elephant"));
System.out.println(longestPalindrome("attari"));
}
public static int longestPalindrome(String x){
if (isPalindrome(x)) {
return x.length();
} else {
//return 0;
return Math.max(longestPalindrome(x.substring(1)),
longestPalindrome(x.substring(0, x.length() - 1)));
}
}
public static boolean isPalindrome(String x){
int startIndex = 0;
int endIndex = x.length() - 1;
while(startIndex < endIndex){
if (x.charAt(startIndex) != x.charAt(endIndex)) {
return false;
}
startIndex++;
endIndex--;
}
return true;
}
}

Searching LinkedList, comparing two "Strings"?

I have a LinkedList where each node contains a word. I also have a variable that contains 6 randomly generated letters. I have a code the determines all possible letter combinations of those letters. I need to traverse through the linked list and determine the best "match" among the nodes.
Example:
-Letters generated: jghoot
-Linked list contains: cat, dog, cow, loot, hooter, ghlooter (I know ghlooter isn't a word)
The method would return hooter because it shares the most characters and is most similar to it. Any ideas?
I guess you could say I am looking for the word that the generated letters are a substring of.
use a nested for loop, compare each letter of your original string with the one you are comparing it to, and for each match, increase a local int variable. at the end of the loop, compare local int variable to global int variable that holds the "best" match till that one, and if bigger, store local int into global one, and put your found node into global node. at the end you should have a node which matches closest.
something like this
int currBest = 0;
int currBestNode = firstNodeOfLinkedList;
while(blabla)
{
int localBest = 0;
for(i= 0; i < currentNodeWord.length; i++)
{
for(j=0; j < originalWord.length;j++)
{
if(currentNodeWord[i] == originalWord[j])
{
localBest++
}
}
}
if(localBest > currBest)
{
currBest = localBest;
currBestNode = currentNodeStringBeingSearched;
}
}
// here u are out of ur loop, ur currBestNode should be set to the best match found.
hope that helps
If you're considering only character counts, first you need a method to count chars in a word
public int [] getCharCounts(String word) {
int [] result = new int['z' - 'a' + 1];
for(int i = 0; i<word.length(); i++) result[word.charAt(i) - 'a']++;
return result;
}
and then you need to compare character counts of two words
public static int compareCounts(int [] count1, int [] count2) [
int result = 0;
for(int i = 0; i<count1.length; i++) {
result += Math.min(count1[i], count2[i]);
}
return result;
}
public static void main(String[] args) {
String randomWord = "jghoot";
int [] randomWordCharCount = getCharCounts(randomWord);
ArrayList<String> wordList = new ArrayList();
String bestElement = null;
int bestMatch = -1;
for(String word : wordList) {
int [] wordCount = getCharCounts(word);
int cmp = compareCounts(randomWordCharCount, wordCount);
if(cmp > bestMatch) {
bestMatch = cmp;
bestElement = word;
}
}
System.out.println(word);
}
I think this works.
import java.util.*;
import java.io.*;
class LCSLength
{
public static void main(String args[])
{
ArrayList<String> strlist=new ArrayList<String>();
strlist.add(new String("cat"));
strlist.add(new String("cow"));
strlist.add(new String("hooter"));
strlist.add(new String("dog"));
strlist.add(new String("loot"));
String random=new String("jghoot"); //Your String
int maxLength=-1;
String maxString=new String();
for(String s:strlist)
{
int localMax=longestSubstr(s,random);
if(localMax>maxLength)
{
maxLength=localMax;
maxString=s;
}
}
System.out.println(maxString);
}
public static int longestSubstr(String first, String second) {
if (first == null || second == null || first.length() == 0 || second.length() == 0) {
return 0;
}
int maxLen = 0;
int fl = first.length();
int sl = second.length();
int[][] table = new int[fl+1][sl+1];
for(int s=0; s <= sl; s++)
table[0][s] = 0;
for(int f=0; f <= fl; f++)
table[f][0] = 0;
for (int i = 1; i <= fl; i++) {
for (int j = 1; j <= sl; j++) {
if (first.charAt(i-1) == second.charAt(j-1)) {
if (i == 1 || j == 1) {
table[i][j] = 1;
}
else {
table[i][j] = table[i - 1][j - 1] + 1;
}
if (table[i][j] > maxLen) {
maxLen = table[i][j];
}
}
}
}
return maxLen;
}
}
Credits: Wikipedia for longest common substring algorithm.
http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_substring

Make And Show All Permutations of An Integer Array [duplicate]

This question already has answers here:
Algorithm to find next greater permutation of a given string
(14 answers)
Closed 8 years ago.
I am currently making a Permutation class for java. One of my methods for this class, is advance(), where the computer will take the array, and then display all permutations of the array.
So, for example, if I give the array {0,1,2,3,4,5}, or the number 6, it should give me from 012345.....543210.
Here is the code I have so far:
import java.util.*;
public class Permutation extends java.lang.Object {
public static int[] permutation;
public static int[] firstPerm;
public static int[] lastPerm;
public static int length;
public static int count;
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public Permutation(int n) {
length = n;
permutation = new int[length];
for (int i = 0; i < length; i++) {
permutation[i] = i;
}
}
public Permutation(int[] perm) {
length = perm.length;
permutation = new int[length];
boolean[] t = new boolean[length];
for (int i = 0; i < length; i++) {
if (perm[i] < 0 || perm[i] >= length) {
throw new IllegalArgumentException("INVALID ELEMENT");
}
if (t[perm[i]]) {
throw new IllegalArgumentException("DUPLICATE VALUES");
}
t[perm[i]] = true;
permutation[i] = perm[i];
}
}
public void advance() {
}
public int getElement(int i) {
return permutation[i];
}
public boolean isFirstPerm() {
firstPerm = new int[permutation.length];
for (int i = 0; i < permutation.length; i++) {
firstPerm[i] = permutation[i];
}
Arrays.sort(firstPerm);
if (Arrays.equals(firstPerm, permutation)) {
return true;
} else {
return false;
}
}
public boolean isLastPerm() {
lastPerm = new int[firstPerm.length];
for (int i = 0; i < firstPerm.length; i++) {
lastPerm[i] = firstPerm[firstPerm.length - 1 - i];
}
if (Arrays.equals(permutation, lastPerm)) {
return true;
} else {
return false;
}
}
public static Permutation randomPermutation(int n) {
if (n <= 0) {
throw new IllegalArgumentException("INVALID NUMBER");
} else {
length = n;
permutation = new int[length];
for (int i = 0; i < length; i++) {
permutation[i] = i;
}
Collections.shuffle(Arrays.asList(permutation));
return new Permutation(permutation);
}
}
public void reset() {
Arrays.sort(permutation);
}
public boolean isValid(int[] perm) {
boolean[] t = new boolean[length];
for (int i = 0; i < length; i++) {
if (perm[i] < 0 || perm[i] >= length) {
return false;
}
if (t[perm[i]]) {
return false;
}
}
return true;
}
public int[] toArray() {
return permutation;
}
public String toString() {
StringBuffer result = new StringBuffer();
for (int i = 0; i < permutation.length; i++) {
result.append(permutation[i]);
}
String perms = result.toString();
return perms;
}
public static long totalPermutations(int n) {
count = 1;
for (int i = 1; i <= n; i++) {
count = count * i;
}
return count;
}
}
As you can see, the advance() method is the last thing I need to do, but I can't figure it out. Any help will be grand.
One of methods you can employ is:
Fix the first element and recursively find all permutations of rest of the array.
Then change the first elements by trying each of the remaining elements.
Base case for recursion is when you travel the entire length to get 0 element array. Then, either print it or add it to a List which you can return at the end.
public void advance() {
int[] temp = Arrays.copyOf(arr, arr.length);
printAll(0,temp);
}
private void printAll(int index,int[] temp) {
if(index==n) { //base case..the end of array
//print array temp here
}
else {
for(int i=index;i<n;i++) {//change the first element stepwise
swap(temp,index,i);//swap to change
printAll(index+1, temp);//call recursively
swap(temp,index,i);//swap again to backtrack
}
}
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
The way your code looks right now, it sounds like you want to be able to control the permutation class externally, rather than only supporting the one operation of printing all the permutations in order.
Here's an example of how to calculate a permutation.
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test {
public static int factorial(int x) {
int f = 1;
while (x > 1) {
f = f * x;
x--;
}
return f;
}
public static List<Integer> permute(List<Integer> list, int iteration) {
if (list.size() <= 1) return list;
int fact = factorial(list.size() - 1);
int first = iteration / fact;
List<Integer> copy = new ArrayList<Integer>(list);
Integer head = copy.remove(first);
int remainder = iteration % fact;
List<Integer> tail = permute(copy, remainder);
tail.add(0, head);
return tail;
}
public static void main(String[] args) throws IOException {
List<Integer> list = Arrays.asList(4, 5, 6, 7);
for (int i = 0; i < 24; i++) {
System.out.println(permute(list, i));
}
}
}
Just to elaborate, the idea behind the code is to map an integer (iteration) to a particular permutation (ordering of the list). We're treating it as a base-n representation of the permutation where each digit represents which element of the set goes in that position of the resulting permutation.
For example, if we're permuting (1, 2, 3, 4) then we know there are 4! permutations, and that "1" will be the first element in 3! of them, and it will be followed by all permutations of (2, 3, 4). Of those 3! permutations of the new set (2, 3, 4), "2" will be the first element in 2! of them, etc.
That's why we're using / and % to calculate which element goes into each position of the resulting permutation.
This should work, and it's pretty compact, only drawback is that it is recursive:
private static permutation(int x) {
if (x < 1) {
throw new IllegalArgumentException(x);
}
LinkedList<Integer> numbers = new LinkedList<>();
for (int i = 0; i < x; i++) {
numbers.add(i);
}
printPermutations(numbers, new LinkedList<>());
}
private static void printPermutations(
LinkedList<Integer> numbers, LinkedList<Integer> heads) {
int size = numbers.size();
for (int i = 0; i < size; i++) {
int n = numbers.getFirst();
numbers.removeFirst();
heads.add(n);
printPermutations(numbers, heads);
numbers.add(n);
heads.removeLast();
}
if (numbers.isEmpty()) {
String sep = "";
for (int n : heads) {
System.out.print(sep + n);
sep = " ";
}
System.out.println("");
}
}

Categories

Resources