I am creating a code here but I believe there is a way making the following more efficient. I tried many ways but it does not seem to work.
protected void randomise() {
int[] copy = new int[array().length]; //This makes the new int called randomIndex
// used to indicate if elements have been used
boolean[] used = new boolean[array().length]; //calling "used" as a new boolean for the array
Arrays.fill(used,false);
/**
* if index = 0, it means their is nothing in the index.
* if you apply a random number, it will copy that number to an array called index.
* if randomIndex in use, then the boolean becomes true.
*/
for (int index = 0; index < array().length;) {
do {
randomIndex = randomIndex();
} while (used[randomIndex]); //when random is in use, do the follow instruction.
copy[index] = array[index]; //copy the value value to an array called index.
used[randomIndex] = true; //when randomIndex is in use, then it becomes true.
}
//Of course, if there an extra random stores in the array, the index list is increased by one (index++).
for (int index =0;index < array().length; index++) {
array()[index] = copy[index]; //This tells where to copy the index value. in this case, it is a index array.
}
Do you have to use randomIndex?
If not you can use your bool[] to eliminate that do {} while() by sequentially adding the value to copy (which isn't a great name) and choosing a randInt in the range of the len of elements that haven't been selected, then using that bool[] to count a walk through the array elements ( to make your choice for the next element in copy.
You seem to want to randomly re-order an array. If so, then indeed there is a much more efficient solution. You are currently keeping two extra arrays on the size of the input (O(n)) while you do not have to.
The random shuffling is a common problem, and obviously there have been proposed several algorithms to accomplish this task. One of the most efficient algorithms is Knuth's algorithm for random permutation
The algorithms idea is, loop over the array once, and for each number i, perform a random exchange between i and a (random) array index between 0 and i. This guarantees that the array with be shuffled (meaning that each item will have equal possibility to be placed in each of the array indexes), in O(n) time and without using any extra space.
In short,
for (int i = 0; i < index; i++) {
int r = random.nextInt(i + 1);
exchange(array, i, r);
}
It is simple - use some collection of indexes and remove element when you used it. This way should looks like:
List<Integer> indexes = new ArrayList<>(array.length);
for (int i = 0 ; i < array.length ; i++) {
indexes.add(i);
}
Random r = new Random();
while (indexes.size() > 0) {
int randomIndex = r.nextInt(indexes.size());
int index = indexes.remove(randomIndex);
copy[index] = array[index];
}
Please note that:
you should check what is exact collection will be more efficient in your situation
Another way - create list values for array and use Collections.shuffle method on this list.
Additional another way - use some recursive algorithm to do that work.
Related
I'm trying to put a certain amount of integers into an array in random spots without putting them in the same place.
My combine method concatenates two given integers and returns the Int.
Places is an arrayList to keep the locations of the integers already put into the array.
The random method returns a random integer in between the two given ints.
The combine method works and so does the random method, but I'm not sure why it isn't working.
public void fillOne(int b)
{
for(int x = 0; x < b; x++)
{
int kachow = random(0, 5);
int kachigga = random(0, 5);
int skrrt = combine(kachow, kachigga);
if(notInArray(skrrt))
{
locations[kachow][kachigga] = 1;
places.add(skrrt);
}
}
}
You haven't really explained what isn't working. But an obvious flaw in your algorithm is that it isn't guaranteed to set b elements to 1. If your algorithm generates a duplicate position then it will set fewer than b elements.
Your logic for storing the combined positions is overly complex. One solution would be to reverse the logic: generate a single integer representing both dimensions then divide it into two when you are setting the location. That makes the checks a lot simpler.
For example, if your array is 5x5:
Set<Integer> positions = new HashSet<>();
while (positions.size() < n)
positions.add(random.nextInt(25));
for (int p: positions)
locations[p/5][p%5] = 1;
Because positions is a set it automatically excludes duplicates which means the code will keep adding random positions until their are n distinct positions in the set.
Even simpler, if you are using Java 8:
random.ints(0, 25)
.distinct().limit(n)
.forEach(p -> locations[p/5][p%5] = 1);
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.
lets say i have this array
int [] array= new int[26];
it has 26 places because the position 0 is 'a' , position 1'b' ... position 25 is 'z'
so in each position i have an int number so
if in position array[0]=5 it means i have 5 'a'
if in position array[1]=6 it means i have 6'b'
if in position array[0]=0 it means that i do not have the 'a' letter
what i want is to find in each loop the 2 smallest frequencies and the letters of the two smallest frequencies
for(int i=0;i<array.length;i++)
if(array[i]==0)
continue;
else{
cmin1=(char)('a'+i);
posi=i;
min1=array[posi] ;
break;
}
for(int j=posi+1;j<array.length;j++){
if(array[j]==0)
continue;
else if(array[j]<=min1){
posj=posi;
posi=j;
cmin2=cmin1;
cmin1=(char)(j+'a');
min2=min1;
min1=array[j];
}
i have tried this which is wrong
Java is Object Oriented so...
Let's take a class, which name would be LetterFrequency
LetterFrequency has 2 attributes:
1) Char character
2) Integer occurrences
You need to sort the LetterFrequency objects by their "occurrences" atrribute. To do that, make LetterFrequancy implements Comparable and define method compareTo() accordingly.
Then put all your LetterFrequency objects in a List and use the method
Lists.sort(yourList)
Sort would work but it's not the best performing method.
How about a single loop which would be O(n)?
int min1 = Integer.MAX_INT;
int idx1 = -1;
int min2 = Integer.MAX_INT;
int idx2 = -1;
for(int i=0;i<array.length;i++) {
// skip empty items
if(array[i]==0)
continue;
if (array[i] < min1) {
min2 = min1;
idx2 = idx1;
min1 = array[i];
idx1 = i;
}
else if (array[i] < min2) {
min2 = array[i];
idx2 = i;
}
}
sort the array first...now apply the searching algorithm...and here you go
once you find the smallest element you can get the second smallest as the array is already sorted...i guess there would be no difficulty doing this...for sorting you can use quicksort with complexity(nlogn)...hope it helps you
I would create a class representing each frequency count. Then I would create a Comparator which orders the records by the frequency. Then I would use Arrays.sort() or Collections.sort() to sort the collection using the Comparator.
Alternatively, if you simply want to find the entries in the array but can't change your data type, then you need to define an algorithm for searching (not sorting) the array. To do this, and do it in one pass, I would define local variables for the positions and corresponding frequencies of the two least frequently occurring. Initialize the least to the first item in the array, then proceed by comparing the current one and if it is less then rotate the values of the variables which are keeping track. At the end you'll have the two least frequent.
If you just want to find the smallest element in an array, you can use the following code :
List<int> list = Arrays.asList(ArrayUtils.toObject(array));
// Print the smallest element of your array
System.out.println(Collections.min(list));
First of all, this array declaration will never work:
int [] array= new array[26];
You need:
int [] array= new int[26];
Heap - Sort Algorithm
The problem I am having is this, this algorithms n input is 2, this is designed so that the 1st position (int i) of the array and the 2nd position (int j) have their values compared.
The problem is that this ignores the 0 position of the given array list. I have tried reducing certain values, this will create infinite loops. The algorithm is an adaptation of pseudocode. It isn't designed to run arraylist from 0. I can't think of how to re-adapt this algorithm into a decent minimum heap sort.
public static void input( ArrayList<input> vertexList, int n )
{
int j=n;
int i=n/2;
input object = vertexList.get(n);
while ((i>0) && vertexList.get(i)> object){
vertexList.set(j, vertexList.get(i));
j = i;
i = i/2;
}
vertexList.set(j, object);
}
try to use vertexList.get(i-1) and vertexList.get(j-1) and vertexList.set(j-1, ...)
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.