I am trying to solve the following problem:
Given a collection of numbers that might contain duplicates, return
all possible unique permutations.
Here is my code:
public class Solution {
public ArrayList<ArrayList<Integer>> permute(ArrayList<Integer> a) {
HashMap<ArrayList<Integer>, Boolean> unique = new HashMap<>();
ArrayList<ArrayList<Integer>> results = new ArrayList<>();
permu(results, a, 0, unique);
return results;
}
private void permu(ArrayList<ArrayList<Integer>> results, final ArrayList<Integer> a, int item, HashMap<ArrayList<Integer>, Boolean> unique) {
for(int i = 0; i < a.size(); i++) {
ArrayList<Integer> aClone = new ArrayList<>(a);
// swap
int backup = aClone.get(i);
aClone.set(i, aClone.get(item));
aClone.set(item, backup);
if(!unique.containsKey(aClone)) {
results.add(aClone);
unique.put(aClone, true);
permu(results, aClone, i, unique); //<--- Stack overflow error
}
}
}
}
I have a stack overflow error on this the call to the recurrence, line (19)
Well, I don't like to ruin good job interview questions, but this question was fun to think about, so...
Here's a super-L337 answer for generating all unique permutations very quickly and without using much memory or stack. If you use this in a job interview, the interviewer will ask you to explain how it works. If you can do that, then you deserve it :)
Note that I permuted the chars in a string instead of the instead of integers in a list, just because it's easier to pretty-print the result.
import java.util.Arrays;
import java.util.function.Consumer;
public class UniquePermutations
{
static void generateUniquePermutations(String s, Consumer<String> consumer)
{
char[] array = s.toCharArray();
Arrays.sort(array);
for (;;)
{
consumer.accept(String.valueOf(array));
int changePos=array.length-2;
while (changePos>=0 && array[changePos]>=array[changePos+1])
--changePos;
if (changePos<0)
break; //all done
int swapPos=changePos+1;
while(swapPos+1 < array.length && array[swapPos+1]>array[changePos])
++swapPos;
char t = array[changePos];
array[changePos] = array[swapPos];
array[swapPos] = t;
for (int i=changePos+1, j = array.length-1; i < j; ++i,--j)
{
t = array[i];
array[i] = array[j];
array[j] = t;
}
}
}
public static void main (String[] args) throws java.lang.Exception
{
StringBuilder line = new StringBuilder();
generateUniquePermutations("banana", s->{
if (line.length() > 0)
{
if (line.length() + s.length() >= 75)
{
System.out.println(line.toString());
line.setLength(0);
}
else
line.append(" ");
}
line.append(s);
});
System.out.println(line);
}
}
Here is the output:
aaabnn aaanbn aaannb aabann aabnan aabnna aanabn aananb aanban aanbna
aannab aannba abaann abanan abanna abnaan abnana abnnaa anaabn anaanb
anaban anabna ananab ananba anbaan anbana anbnaa annaab annaba annbaa
baaann baanan baanna banaan banana bannaa bnaaan bnaana bnanaa bnnaaa
naaabn naaanb naaban naabna naanab naanba nabaan nabana nabnaa nanaab
nanaba nanbaa nbaaan nbaana nbanaa nbnaaa nnaaab nnaaba nnabaa nnbaaa
Related
So I was trying to solve a question on sorting elements based on their frequencies using a comparator and got this error message.
The question is :
Given an array A[] of integers, sort the array according to frequency of elements. That is elements that have higher frequency come first. If frequencies of two elements are same, then smaller number comes first.
I have attached the code and the corresponding error message down below.
Error message:
Runtime Error:
Runtime ErrorException in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:899)
at java.util.TimSort.mergeAt(TimSort.java:516)
at java.util.TimSort.mergeForceCollapse(TimSort.java:457)
at java.util.TimSort.sort(TimSort.java:254)
at java.util.Arrays.sort(Arrays.java:1512)
at java.util.ArrayList.sort(ArrayList.java:1460)
at java.util.Collections.sort(Collections.java:175)
at Main.sortEleByFreq(File.java:50)
at Main.main(File.java:30)
Code:
import java.util.*;
class Main
{
static class pair
{
int val;
int freq;
pair(int val,int freq)
{
this.val = val;
this.freq=freq;
}
}
public static void main (String[] args)
{
Scanner sc = new Scanner(System.in);
int t =sc.nextInt();
while(t-->0)
{
int n =sc.nextInt();
int a[] = new int[n];
for(int i =0 ;i <n ; i++)
{
a[i]= sc.nextInt();
}
sortEleByFreq(a,n);
}
}
static void sortEleByFreq(int a[],int n)
{
Arrays.sort(a);
HashMap<Integer,Integer> map = new HashMap<>();
for(int i=0;i<n;i++)
{
if(map.containsKey(a[i]))
map.put(a[i],map.get(a[i])+1);
else
map.put(a[i],1);
}
ArrayList<pair> res = new ArrayList<>();
for(int i=0;i<n;i++)
res.add(new pair(a[i],map.get(a[i])));
Collections.sort(res,new CustomSort());
StringBuilder sb = new StringBuilder();
for(int i=0;i<n;i++)
sb.append(res.get(i).val+" ");
System.out.println(sb);
}
static class CustomSort implements Comparator<pair>
{
public int compare(pair p1,pair p2)
{
if(p1.freq<p2.freq||p1.freq==p2.freq && p1.val>p2.val)
return 1;
return -1;
}
}
}
So I have stored the frequency and value of the element as a pair, and then used a comparator to sort it.
You need to return 0 as well in case of p1.val == p2.val,
static class CustomSort implements Comparator<pair>
{
public int compare(pair p1,pair p2)
{
if(p1.freq<p2.freq||p1.freq==p2.freq && p1.val>p2.val)
return 1;
if (p1.val == p2.val)
return 0;
return -1;
}
}
You Comparator should handles all the cases, and you're not at the moment, here is how :
handle p1.freq < p2.freq and p1.freq > p2.freq
if not they are equal, sort on val field
static class CustomSort implements Comparator<pair>{
public int compare(pair p1,pair p2){
if(p1.freq < p2.freq)
return 1;
if(p1.freq > p2.freq)
return -1;
return Integer.compare(p1.val, p2.val);
}
}
I know similar questions have been asked before but I have found the answers confusing. I am trying to make a program that will find every combination of an array-list with no repetitions and only of the maximum size. If the list has 4 items it should print out only the combinations with all 4 items present. This is what I have so far:
public main(){
UI.initialise();
UI.addButton("Test", this::testCreate);
UI.addButton("Quit", UI::quit);
}
public void createCombinations(ArrayList<String> list, String s, int depth) {
if (depth == 0) {
return;
}
depth --;
for (int i = 0; i < list.size(); i++) {
if (this.constrain(s + "_" + list.get(i), list.size())) {
UI.println(s + "_" + list.get(i));
}
createCombinations(list, s + "_" + list.get(i), depth);
}
}
public void testCreate() {
ArrayList<String> n = new ArrayList<String>();
n.add("A"); n.add("B"); n.add("C"); n.add("D");
this.createCombinations(n , "", n.size());
}
public boolean constrain(String s, int size) {
// Constrain to only the maximum length
if ((s.length() != size*2)) {
return false;
}
// Constrain to only combinations without repeats
Scanner scan = new Scanner(s).useDelimiter("_");
ArrayList<String> usedTokens = new ArrayList<String>();
String token;
while (scan.hasNext()) {
token = scan.next();
if (usedTokens.contains(token)) {
return false;
} else {
usedTokens.add(token);
}
}
// If we fully iterate over the loop then there are no repitions
return true;
}
public static void main(String[] args){
main obj = new main();
}
This prints out the following which is correct:
_A_B_C_D
_A_B_D_C
_A_C_B_D
_A_C_D_B
_A_D_B_C
_A_D_C_B
_B_A_C_D
_B_A_D_C
_B_C_A_D
_B_C_D_A
_B_D_A_C
_B_D_C_A
_C_A_B_D
_C_A_D_B
_C_B_A_D
_C_B_D_A
_C_D_A_B
_C_D_B_A
_D_A_B_C
_D_A_C_B
_D_B_A_C
_D_B_C_A
_D_C_A_B
_D_C_B_A
This works for small lists but is very inefficient for larger ones. I am aware that what I have done is completely wrong but I want to learn the correct way. Any help is really appreciated. Thanks in advance.
P.S. This is not homework, just for interest although I am a new CS student (if it wasn't obvious).
Implementing Heap's algorithm in Java:
import java.util.Arrays;
public class Main {
public static void swap(final Object[] array, final int index1, final int index2) {
final Object tmp = array[index1];
array[index1] = array[index2];
array[index2] = tmp;
}
public static void printPermutations_HeapsAlgorithm(final int n, final Object[] array) {
final int[] c = new int[n];
for (int i = 0; i < c.length; ++i)
c[i] = 0;
System.out.println(Arrays.toString(array)); //Consume first permutation.
int i=0;
while (i < n) {
if (c[i] < i) {
if ((i & 1) == 0)
swap(array, 0, i);
else
swap(array, c[i], i);
System.out.println(Arrays.toString(array)); //Consume permutation.
++c[i];
i=0;
}
else
c[i++] = 0;
}
}
public static void main(final String[] args) {
printPermutations_HeapsAlgorithm(4, new Character[]{'A', 'B', 'C', 'D'});
}
}
Possible duplicate of this.
For example if the input is "name" and the minGram is 1 and maxGramSize is 2 output will consist of n,a,m,e,na,am,me. If the minGram=2, maxGram=4 inputWord=name, output = na,am,me,nam,ame,name.
Function signature can be something like this:
public List<String> generateNGrams(String input, int minGramSize, int maxGramSize)
Initially I tried doing it with for loops, but I was finding it hard to follow the indices. Then I tried solving it using recursion with pen and paper but I'm still struggling with it. Can someone help me with this?
One solution:
private static void addNgrams(final int size, final String input,
final List<String> list)
{
final int maxStartIndex = input.length() - size;
for (int i = 0; i < maxStartIndex; i++)
list.add(input.stubString(i, i + size));
}
public List<String> generateNGrams(final String input, final int minSize,
final int maxSize)
{
final List<String> ret = new ArrayList<>();
for (int size = minSize; size <= maxSize; size++)
addNgrams(size, input, ret);
return ret;
}
Note: lacks basic error checkings (for instance, maxSize greater than the size of input; minSize greater than maxSize; others); left as an exercise.
Here is a program that recursively generates nGrams: This code also handles the tail grams.
import java.util.ArrayList;
public class NGrams {
ArrayList<String> nGrams = new ArrayList<String>();
public void generateNGrams(String str, int n) {
if (str.length() == n ) {
int counter = 0;
while (counter < n) {
nGrams.add(str.substring(counter));
counter++;
}
return;
}
int counter = 0;
String gram = "";
while (counter < n) {
gram += str.charAt(counter);
counter++;
}
nGrams.add(gram);
generateNGrams(str.substring(1), n);
}
public void printNGrams() {
for (String str : nGrams) {
System.out.println(str);
}
}
public static void main(String[] args) {
NGrams ng = new NGrams();
ng.generateNGrams("hello world", 3);
ng.printNGrams();
}
}
Output:
hel
ell
llo
lo
o w
wo
wor
orl
rld
ld
d
i have one arrayList
List value = new ArrayList();
this arraylist are value is = {a,b,c,d}
i have required combination to string using this arraylist
Required Output: abcd,bcd,acd,abd,abc,cd,bd,bc,ad,ac,ab,a,b,c,d,null
If it's possible? then please send me code....
It's my code but not perfectly work
import java.util.ArrayList;
import java.util.List;
public class PossibleCombination {
public static void main(String[] args) {
List segList = new ArrayList();
for(int i=65;i<70;i++){
segList.add((char)i);
}
int segSize = segList.size();
int[][] a = new int[segSize][2];
int i;
for(i=0; i<= segSize-1; i++)
{
a[i][0] = 0;
a[i][1] = 1;
}
boolean b1 = true;
int t =0;
while(b1)
{
StringBuffer stb = new StringBuffer();
for(i=0;i<segSize; i++)
{
if(a[i][0]==0)
stb.append(segList.get(i));
}
System.out.println(stb);
if(t>=a.length){
t=0;
}
int Pos=t;
while(a[Pos][0]>=a[Pos][1])
{
if(Pos<segSize-1)
Pos++;
else
break;
}
a[Pos][0]++;
Pos--;
while(Pos>=0)
{
if(a[Pos][0]>0)
{
a[Pos][0]--;
break;
}
Pos--;
}
t++;
if(a[segSize-1][0]> a[segSize-1][1]){
b1 = false;
}
}
}
}
Yes, It is definitely possible. However, it will of course require exponential time.
I will leave the actual implementation to you, but here are some hints.
The easiest way to do this is recursively, but that will take a lot of stack space very quickly.
Another way to do this is via some kind of breath-first expanding of the resulting list. This can be done iteratively with a FIFO queue.
List<String[]> value = new ArrayList<String[]>();
String[] item = {"a","b","c"};
value.add(item);
i have a task where i need to find the mode of an array. which means i am looking for the int which is most frequent. i have kinda finished that, but the task also says if there are two modes which is the same, i should return the smallest int e.g {1,1,1,2,2,2} should give 1 (like in my file which i use that array and it gives 2)
public class theMode
{
public theMode()
{
int[] testingArray = new int[] {1,1,1,2,2,2,4};
int mode=findMode(testingArray);
System.out.println(mode);
}
public int findMode(int[] testingArray)
{
int modeWeAreLookingFor = 0;
int frequencyOfMode = 0;
for (int i = 0; i < testingArray.length; i++)
{
int currentIndexOfArray = testingArray[i];
int frequencyOfEachInArray = howMany(testingArray,currentIndexOfArray);
if (frequencyOfEachInArray > frequencyOfMode)
{
modeWeAreLookingFor = currentIndexOfArray;
frequencyOfMode = modeWeAreLookingFor;
}
}
return modeWeAreLookingFor;
}
public int howMany(int[] testingArray, int c)
{
int howManyOfThisInt=0;
for(int i=0; i < testingArray.length;i++)
{
if(testingArray[i]==c){
howManyOfThisInt++;
}
}
return howManyOfThisInt;
}
public static void main(String[] args)
{
new theMode();
}
}
as you see my algorithm returns the last found mode or how i should explain it.
I'd approach it differently. Using a map you could use each unique number as the key and then the count as the value. step through the array and for each number found, check the map to see if there is a key with that value. If one is found increment its value by 1, otherwise create a new entry with the value of 1.
Then you can check the value of each map entry to see which has the highest count. If the current key has a higher count than the previous key, then it is the "current" answer. But you have the possibility of keys with similar counts so you need to store each 'winnning' answer.
One way to approach this is to check each map each entry and remove each entry that is less than the current highest count. What you will be left with is a map of all "highest counts". If you map has only one entry, then it's key is the answer, otherwise you will need to compare the set of keys to determine the lowest.
Hint: You're updating ModeWeAreLookingFor when you find a integer with a strictly higher frequency. What if you find an integer that has the same frequency as ModeWeAreLookingFor ?
Extra exercice: In the first iteration of the main loop execution, you compute the frequency of '1'. On the second iteration (and the third, and the fourth), you re-compute this value. You may save some time if you store the result of the first computation. Could be done with a Map.
Java code convention states that method names and variable name should start with a lower case character. You would have a better syntax coloring and code easier to read if you follow this convention.
this might work with a little modification.
http://www.toves.org/books/java/ch19-array/index.html#fig2
if ((count > maxCount) || (count == maxCount && nums[i] < maxValue)) {
maxValue = nums[i];
maxCount = count;
}
since it seems there are no other way, i did a hashmap after all. i am stuck once again in the logics when it comes to comparing frequencys and and the same time picking lowest integer if equal frequencys.
public void theMode()
{
for (Integer number: intAndFrequencyMap.keySet())
{
int key = number;
int value = intAndFrequencyMap.get(number);
System.out.println("the integer: " +key + " exists " + value + " time(s).");
int lowestIntegerOfArray = 0;
int highestFrequencyOfArray = 0;
int theInteger = 0;
int theModeWanted = 0;
if (value > highestFrequencyOfArray)
{
highestFrequencyOfArray = value;
theInteger = number;
}
else if (value == highestFrequencyOfArray)
{
if (number < theInteger)
{
number = theInteger;
}
else if (number > theInteger)
{
}
else if (number == theInteger)
{
number = theInteger;
}
}
}
}
Completed:
import java.util.Arrays;
public class TheMode
{
//Probably not the most effective solution, but works without hashmap
//or any sorting algorithms
public TheMode()
{
int[] testingArray = new int[] {2,3,5,4,2,3,3,3};
int mode = findMode(testingArray);
System.out.println(Arrays.toString(testingArray));
System.out.println("The lowest mode is: " + mode);
int[] test2 = new int[] {3,3,2,2,1};
int mode2=findMode(test2);
System.out.println(Arrays.toString(test2));
System.out.println("The lowest mode is: " +mode2);
int[] test3 = new int[] {4,4,5,5,1};
int mode3 = findMode(test3);
System.out.println(Arrays.toString(test3));
System.out.println(The lowest mode is: " +mode3);
}
public int findMode(int[] testingArray)
{
int modeWeAreLookingFor = 0;
int frequencyOfMode = 0;
for (int i = 0; i < testingArray.length; i++)
{
int currentIndexOfArray = testingArray[i];
int countIntegerInArray = howMany(testingArray, currentIndexOfArray);
if (countIntegerInArray == frequencyOfMode)
{
if (modeWeAreLookingFor > currentIndexOfArray)
{
modeWeAreLookingFor = currentIndexOfArray;
}
}
else if (countIntegerInArray > frequencyOfMode)
{
modeWeAreLookingFor = currentIndexOfArray;
frequencyOfMode = countIntegerInArray;
}
}
return modeWeAreLookingFor;
}
public int howMany(int[] testingArray, int c)
{
int howManyOfThisInt=0;
for(int i=0; i < testingArray.length;i++)
{
if(testingArray[i]==c){
howManyOfThisInt++;
}
}
return howManyOfThisInt;
}
public static void main(String[] args)
{
new TheMode();
}
}
Glad you managed to solve it. As you will now see, there is more than one way to approach a problem. Here's what I meant by using a map
package util;
import java.util.HashMap;
import java.util.Map;
public class MathUtil {
public static void main(String[] args) {
MathUtil app = new MathUtil();
int[] numbers = {1, 1, 1, 2, 2, 2, 3, 4};
System.out.println(app.getMode(numbers));
}
public int getMode(int[] numbers) {
int mode = 0;
Map<Integer, Integer> numberMap = getFrequencyMap(numbers);
int highestCount = 0;
for (int number : numberMap.keySet()) {
int currentCount = numberMap.get(number);
if (currentCount > highestCount) {
highestCount = currentCount;
mode = number;
} else if (currentCount == highestCount && number < mode) {
mode = number;
}
}
return mode;
}
private Map<Integer,Integer> getFrequencyMap(int[] numbers){
Map<Integer, Integer> numberMap = new HashMap<Integer, Integer>();
for (int number : numbers) {
if (numberMap.containsKey(number)) {
int count = numberMap.get(number);
count++;
numberMap.put(number, count);
} else {
numberMap.put(number, 1);
}
}
return numberMap;
}
}