I wrote the following algorithm for finding all possible permutations of n unique alphabets.
Set<String> results = new HashSet<String>();
int size = 1;
//find the total permutations possible
for(int i=0;i<array.length;i++){
size*=(i+1);
}
// i is the number of items remaining to be shuffled.
while(results.size()<size){
for (int i = array.length; i > 1; i--) {
// Pick a random element to swap with the i-th element.
int j = rng.nextInt(i); // 0 <= j <= i-1 (0-based array)
// Swap array elements.
char tmp = array[j];
array[j] = array[i-1];
array[i-1] = tmp;
}
StringBuffer str = new StringBuffer();
for(int i=0;i<array.length;i++)
str.append(array[i]);
results.add(str.toString());
}
System.out.println(results);
1) Is there anything to be done to improve this algorithm?
2) What would be the time complexity of this algorithm?
PS: I apologize to the people who who reacted to my previous post. I'll try on my own before asking for help.
By utilizing a random shuffling, you're going to have a massive number of iterations that end up not actually putting a new item into the set - you should look for an approach that ensures that on each iteration a new item is placed into the set (by 'new' I simply mean a permutation that hasn't been seen previously).
I wouldn't like to guess at the time complexity of the algorithm supplied above - it's going to be big.
1) Is there anything to be done to improve this algorithm?
Yes. Just to give you some hints how you could generate the permutations deterministically:
imagine the lexicographic order of all permutations on N elements. Imagine, how could you generate the next permutation in that order given the previous
think about what would the set of permutations with a common prefix (eg. 435 126, 435 162 etc.) be and how could you use it in an algorithm.
The best way to generate permutations is to do so iteratively: finding a scheme to go from one permutation to the next until you've seen them all. Knuth has exposed such a scheme in one of the combinatorial fascicles of TAOCP, and without going into his assembly-like pseudo code, you might want to check these nifty C implementation of those algorithms. The algorithm you are looking for is the one that generates permutations.
The advantage of such an algorithm by opposition to (what I understand of) yours, is that it is deterministic and will generate a different permutation every single time.
Thank you for your inputs. I think I have got a better algorithm. Please provide comments
private static List<String> allPerms(char[] array) {
List<String> perms = new ArrayList<String>();
if(array.length<=1 )
perms.add(String.valueOf(array[0]));
else{
char[] newarray = Arrays.copyOf(array, array.length-1);
char lastChar = array[array.length-1];
List<String> soFar = allPerms(newarray);
for(int i=0; i<soFar.size(); i++) {
String curr = soFar.get(i);
for(int j=0;j<array.length;j++){
StringBuffer buff = new StringBuffer(curr);
perms.add(buff.insert(j, lastChar).toString());
}
}
}
return perms; }
Related
I was learning the fundamentals of dynamic programming and came over to the question of finding the Longest Increasing Subsequence in an array. Before looking up the DP solution, I decided to code it myself and came up with the following algorithm, the complete code to which can be found here.
The idea is to create a List Array to store all the increasing subsequences, and store the corresponding max value of each subsequence for faster comparisons.
private void findLIS(int[] inputArr) {
List[] listOfSubs = new ArrayList[inputArr.length]; //Max different subsequences in an array would be N
//To store the max value of each of the subsequences found yet
List<Integer> maxValList = new ArrayList<Integer>();
listOfSubs[0] = new ArrayList<Integer>();
listOfSubs[0].add(inputArr[0]); //Add the first element of the array to the list
maxValList.add(inputArr[0]);
for (int i=1;i<inputArr.length;i++) {
boolean flag = false;
int iter=0;
//Compare inputArr[i] with the maxVal of each subsequence
for (int j=0; j<maxValList.size(); j++) {
if (inputArr[i]>maxValList.get(j)) {
maxValList.set(j, inputArr[i]); //Update the maxVal in the corresponding position in the list
listOfSubs[j].add(inputArr[i]);
flag = true;
}
iter = j;
}
//If inputArr[i] is not greater than any previous values add it to a new list
if (!flag) {
maxValList.add(inputArr[i]);
listOfSubs[iter+1] = new ArrayList<Integer>();
listOfSubs[iter+1].add(inputArr[i]);
}
}
//Finding the maximum length subsequence among all the subsequences
int max=0, iter=0, index=0;
for (List<Integer> lst : listOfSubs) {
if (lst!=null && lst.size() > max) {
max = lst.size();
index=iter;
}
iter++;
}
//Print the longest increasing subsequence found
System.out.println("The Longest Increasing Subsequence is of length " + listOfSubs[index].size() +
" and is as follows:");
for (int i=0;i<listOfSubs[index].size();i++) {
System.out.print(listOfSubs[index].get(i) + " ");
}
}
The code runs in O(n^2) time and works perfectly for small/medium sized inputs. However, when I try running the code against some of the online practice portals (like HackerRank), I get both TLE (Time Limit Exceeded Errors) and Wrong Answer. I understand the TLE errors, as the efficient solution is a DP O(nlogn) solution, but I'm confused about the wrong answers generated by this algorithm. Since, the inputs for such cases are too big (~10000), I'm unable to manually verify the where the solution goes wrong.
The complete code plus the output to one of the data sets can be found here. The correct answer should be 195 as reported by HackerRank.
I found the problem with my solution. The problem is because of not reading the problem statement carefully.
Say we consider the input as {3, 2, 6, 4, 5, 1}. I only consider the sequences {3,6} and {2,6} in my code, but not sequences {2,4,5} or {3,4,5}. Thus, at every iteration if I find a number greater than the max of the previous subsequences, I add it to all such subsequences thereby diminishing the possibility of reaching the latter subsequences.
This question already has an answer here:
Finding all the number combos in array that add up to input number
(1 answer)
Closed 6 years ago.
I'm currently working on the following question from a interviewing book:
You are given a random array of 50 unique integers ranging from 1 to 100 inclusive. Write a method using Java that takes in a positive integer as a parameter and returns an array of all the number combinations that add up to that value.
For example, given an array of integers [3,6,1,9,2,5,12] and being passed the integer value 9, you would return [[3,6],[6,1,2],[9],[3,1,5]]. Order of returning the results in the array does not matter, though you should return unique sets (ie. [6,3] and [3,6] are the same and only one should be returned). Also, the individual results should be in the order they are found (ie [6,1,2] should be returned, not [1,2,6]).
I've made decent progress on it, but I fear I may solving this the wrong way.
import java.util.*;
public class findCombinations {
public static void main(String[] args) {
int number;
int[] list = new int[10];
Scanner reader = new Scanner(System.in);
//fill the array
for (int i = 0; i < list.length; i++) {
number = (int)(Math.random() * 10) + 1;
list[i] = number;
for (int j = 0; j < i; j++) { //remove duplicates
if (list[i] == list[j]) {
i--;
break;
}
}
}
Arrays.sort(list);
//test output
for (int i = 0; i < list.length; i++) {
System.out.println(list[i]);
}
System.out.println("Enter a number: ");
int input = reader.nextInt();
ArrayList<Integer> trimmedList = new ArrayList<Integer>();
//cut out the numbers that are impossible to use
for (int i = 0; i < list.length; i++) {
if (list[i] <= input) {
trimmedList.add(list[i]);
}
}
//test output
printList(trimmedList);
ArrayList<Integer> comboList = new ArrayList<Integer>();
System.out.println("Finding combinations...");
for (int i = 0; i < trimmedList.size(); i++) {
int current = trimmedList.get(i);
if (current == input) { System.out.println(current); }
else if (current < input) {
comboList.add(current);
if (isCombo(comboList, input)) {
printList(comboList);
}
else { continue; }
}
else { continue; }
}
}
public static boolean isCombo(ArrayList<Integer> list, int input) {
ArrayList<Integer> combo = new ArrayList<Integer>();
int sum = 0;
for (int i : list)
sum += i;
if (sum == input) { return true; }
else { return false; }
}
public static void printList(ArrayList<Integer> list) {
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i));
}
}
}
I know this is incomplete but I wanted to ask if anyone had any suggestions or improvements I could make on this? I sorted my list and trimmed out all the integers that won't possibly be used, but now the hard part is finding all the combos.
There are many different approaches to solve this problem, each with their own merits, so I wouldn't worry too much about whether your answer is the 'right' one or not...so long as it actually solves the problem! Also, an interviewer will likely be more interested in your thought-process, and the strategies you use, rather than a 100% perfect solution written in the span of a few minutes on a whiteboard.
Here's a couple of things to consider:
As you noticed, you can immediately eliminate any integers larger than your target value.
You're essentially generating arbitrarily-sized subsets of your starting array—so Set is likely the most useful data type to work with. {2, 3} and {3, 2} should be seen as identical when you're generating your response set.
Integer partitioning is an NP-Complete problem. It's hard. I think you've taken the correct approach of starting with the array, rather than with the target value.
There are many algorithms for generating combinations of integers from a larger set. Check out this SO answer for a few of them. You can generate k sized combinations from your (already-filtered) starting set, for k from 1-50.
Actually...there are more direct ways to get the power set of your starting set. Consider the inherent structure of a power set (shown below). By enumerating a few examples, you'll notice a natural recurrence in your strategy for identifying the subsets.
As you're generating these combinations, discard any whose elements don't sum to your target value.
Image Source: https://en.wikipedia.org/wiki/Power_set
Since this is a learning exercise, you will benefit most if you can solve this for yourself. So ...
Hints:
Sorting the numbers first is on the right track
I would use recursion to iterate the solutions. Given a partial sum, only numbers less than a certain number are possible candidates to be added to the sum ...
Work out the algorithm in your head >before< you start coding it.
And I agree with what #nbrooks says on the topic of what the interviewers are looking for. You need to be able to think ... and explain your thinking to the interviewer ... at the algorithmic level. That is what will distinguish the excellent candidates from the ordinary ones.
I realize generating your array of random numbers is not part of the problem statement, but I think your difficulties begin here.
First of all, use a Set<Integer> type collection to collect your generated numbers; break when the set reaches the desired size. If generated order is important, use a LinkedHashSet.
Set<Integer> origSet = new HashSet<Integer>(); // fill with random numbers
At some point, you have a list of numbers for which the order matters. Maintain this list as a List<Integer>. The list preserves the order of your original list so that you can produce the number combinations in the right order (i.e., 6 precedes 1, 1 precedes 2).
List<Integer> origList = new ArrayList<Integer>(origSet); // use indexOf method to find index of a number
You create a second list that is sorted; this list is the one used by your recursion algorithm.
List<Integer> sortedList = new ArrayList<Integer>(origList); // sort this
You don't need to trim the list because a recursive algorithm will trim any branch with no feasible solution.
A recursive algorithm can generate the combos in fewer lines of code. Reordering takes a few more lines.
I have an array of N elements and contain 1 to (N-1) integers-a sequence of integers starting from 1 to the max number N-1-, meaning that there is only one number is repeated, and I want to write an algorithm that return this repeated element, I have found a solution but it only could work if the array is sorted, which is may not be the case.
?
int i=0;
while(i<A[i])
{
i++
}
int rep = A[i];
I do not know why RC removed his comment but his idea was good.
With the knowledge of N you easy can calculate that the sum of [1:N-1]. then sum up all elementes in your array and subtract the above sum and you have your number.
This comes at the cost of O(n) and is not beatable.
However this only works with the preconditions you mentioned.
A more generic approach would be to sort the array and then simply walk through it. This would be O(n log(n)) and still better than your O(n²).
I you know the maximum number you may create a lookup table and init it with all zeros, walk through the array and check for one and mark the entries with one. The complexity is also just O(n) but at the expense of memory.
if the value range is unknown a simiar approach can be used but instead of using a lookup table a hashset canbe used.
Linear search will help you with complexity O(n):
final int n = ...;
final int a[] = createInput(n); // Expect each a[i] < n && a[i] >= 0
final int b[] = new int[n];
for (int i = 0; i < n; i++)
b[i]++;
for (int i = 0; i < n; i++)
if (b[i] >= 2)
return a[i];
throw new IllegalArgumentException("No duplicates found");
A possible solution is to sum all elements in the array and then to compute the sym of the integers up to N-1. After that subtract the two values and voila - you found your number. This is the solution proposed by vlad_tepesch and it is good, but has a drawback - you may overflow the integer type. To avoid this you can use 64 bit integer.
However I want to propose a slight modification - compute the xor sum of the integers up to N-1(that is compute 1^2^3^...(N-1)) and compute the xor sum of your array(i.e. a0^a1^...aN-1). After that xor the two values and the result will be the repeated element.
This question already has answers here:
Sort an array in Java
(19 answers)
Closed 9 years ago.
Im trying to organize random numbers in an array from least to greatest.
I came up with a loop which I thought should work but has a lot of logic errors.
for(int z=0; z<=999;z++){
for(w=1; w<=999;w++){
if(z<w){
if(numberArray[z]<numberArray[w])
temp=numberArray[w];
}
}
numberArray[z]=temp;
}
Can anyone tell me how to fix this or an algorithm of their own for doing this?
There are several ways you can sort an array in Java. Here I post but 3 of them : the core library, and 2 algorithms you can make on your own.
1 ) Core one: This is literally only one line of code. I would suggest using this - simple, and very efficient, compared to the below two solutions.
Arrays.sort(myArray);
2 ) Selection Sort : Find the lowest value in an array, move it to the first position, find the next lowest, move to 2nd position, etc.
public void selectionSort(Comparable[] a)
{
for(int index = 0; index < a.length; index++)
{
// find the smallest one in the array from index : end
int smallest = indexOfMin(a, index);
// swap the value at index and the value at the smallest one found
Comparable temp = a[smallest];
a[smallest] = a[index];
display.update();
a[index] = temp;
}
}
3 ) Insertion Sort : Inserts each element in the array into a growing sequence of sorted values and finishes at the end of the array.
public void insertionSort(Comparable[] a)
{
for(int i = 1; i < a.length; i++)
{
insert(a, i);
}
}
public void insert(Comparable[] a, int nextIndex)
{
int index = 0;
Comparable finalObject = a[nextIndex];
// Let us first find the first occurence of a comparable greater than our comparable
while(finalObject.compareTo(a[index]) > 0)
index++;
for(int i = (nextIndex-1); i >= index; i--)
a[i+1] = a[i];
a[index] = finalObject;
}
One liner:
Arrays.sort(numberArray);
Or greatest to least order:
Arrays.sort(numberArray, Collections.reverseOrder());
Or even better, use a Binary Search Tree that keeps its contents in sorted order, this is great for collections that are pretty dynamic, as the add operation is cheaper memory wise and time wise than a full in-place sort:
TreeSet<int> set = new TreeSet<int>();
set.add(10);
set.add(4);
set.add(11);
set.toString();
// prints 4, 10, 11
Arrays.sort() is a quick and easy way.
Also consider PriorityQueues if you need something a little more robust!
This link is another question on SO with a great answer.
Recently, I tried to solve Problem 23 of Project Euler. For that I first create a list of all abundant numbers, called abundants.
Next I iterate over this list and build another list of all sums of abundant numbers that are below a certain limit. Now I noticed something strange. I use a nested loop to iterate twice over the list. But if I use an array to store the sum it takes some seconds, if I add the sums to an ArrayList it takes hours. What's the reason for that? I thought the costly operation are the two nested loops, but it seems the costly operation is ArrayList#add. Any hints why this is the case?
Here the code for the array:
for (int i = 0; i < abundants.size(); i++) {
for (int j = 0; j < abundants.size(); j++) {
int tot = abundants.get(i) + abundants.get(j);
if (tot <= limit)
isSum[tot] = true;
}
}
}
Here the code for the ArrayList:
ArrayList<Integer> sums = new ArrayList<Integer>();
for (int i = 0; i < abundants.size(); i++) {
for (int j = 0; j < abundants.size(); j++) {
int s = abundants.get(i) + abundants.get(j);
if (!sums.contains(s) && s < limit) {
sums.add(s);
}
}
}
Your ArrayList implementation is O(n^3) whereas the other is O(n^2): sums.contains(...) has to traverse the entire sums list for every iteration of your inner loop.
I think rather that your problem is in ArrayList#contains, which has to traverse the whole list, thus raising your complexity to O(n^3), as opposed to O(n^2) of the program #1.
Your code isn't equivalent, the .contains() is more expensive than what you are doing with the raw array. The .contains() walks the entire array every time is called, you don't do this in the raw array based version.
Because int can be much faster than Integer.
Try using Integer[] in the first case or TIntArrayList in the second case for comparison.
If you know the (maximum) number of the elements, try to initialize the Array list with a given size:
ArrayList<Integer> sums = new ArrayList<Integer>(abundants.size() * abundants.size());
With that the ArrayList won't have to be resized, this will increase the speed.