This question already has answers here:
Unique random number generation in an integer array [duplicate]
(9 answers)
Closed 4 years ago.
So i'm trying to create an array of 4 items that is randomly filled with 4 unique numbers. Currently I have a hugely long while loop which checks each value in the array and keeps repeating if they are the same. It's really badly coded and I was wondering if you guys could help me figure out a better way?
Here's what I currently have.
int array[4];
while(array[0] == array[1] || array[1] == array[2] || array[2] == array[3] || array[0] == array[2] || array[0] == array[3] || array[1] == array[3])
{
array[0] = rand() % 20;
array[1] = rand() % 20;
array[2] = rand() % 20;
array[3] = rand() % 20;
}
Here's an algorithm to generate your array of 4 distinct numbers from 0 to 20 which is O(n + m) with n the 4 numbers and m the 20 possible values:
Create an array randArr of 20 integers: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}. This is the array used to pick random numbers
array is an array of 4 integers that will contain the result
for i going from 0 to 3 (included):
Pick a random number r between i and 19 (inclusive). Swap randArr[r] and randArr[i]
Copy to array: array[i] = randArr[i]
Here's the implementation (with a slight improvement to merge the last 2 steps):
int randArr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
int array[4];
for (int i = 0; i < 4; i++) {
int r = i + rand() % (20 - i);
array[i] = randArr[r];
randArr[r] = randArr[i];
}
https://tech.io/snippet/dGgblEO
You want generate random numbers from 0 to 19 and fill them in the array without any duplicates.
Since you have not initialized the elements of array, it is possible that the uninitialized values are already distinct from each other. In this case, the while loop will not be executed at all.
Secondly, you are generating random values for every element of the array every time when any two of them match. This is not required. You have to regenerate the random number only for the element that matches any of the existing ones. This is what a set structure (mentioned in the comments) does.
To shuffle an array of n elements, Fisher–Yates shuffle Algorithm is used which works in O(n) time complexity.
In your case, take an initial array of values from 0 to 19. Once you have shuffled this array, you can take the any k elements of this array (in your case k = 4) and use them (They will be distinct). Implementations of this algorithm can be found online.
Let's say I have an array A with n unique elements on the range [0, n). In other words, I have a permutation of the integers [0, n).
Is possible to transform A into B using O(1) extra space (AKA in-place) such that B[A[i]] = i?
For example:
A B
[3, 1, 0, 2, 4] -> [2, 1, 3, 0, 4]
Yes, it is possible, with O(n^2) time algorithm:
Take element at index 0, then write 0 to the cell indexed by that element. Then use just overwritten element to get next index and write previous index there. Continue until you go back to index 0. This is cycle leader algorithm.
Then do the same starting from index 1, 2, ... But before doing any changes perform cycle leader algorithm without any modifications starting from this index. If this cycle contains any index below the starting index, just skip it.
Or this O(n^3) time algorithm:
Take element at index 0, then write 0 to the cell indexed by that element. Then use just overwritten element to get next index and write previous index there. Continue until you go back to index 0.
Then do the same starting from index 1, 2, ... But before doing any changes perform cycle leader algorithm without any modifications starting from all preceding indexes. If current index is present in any preceding cycle, just skip it.
I have written (slightly optimized) implementation of O(n^2) algorithm in C++11 to determine how many additional accesses are needed for each element on average if random permutation is inverted. Here are the results:
size accesses
2^10 2.76172
2^12 4.77271
2^14 6.36212
2^16 7.10641
2^18 9.05811
2^20 10.3053
2^22 11.6851
2^24 12.6975
2^26 14.6125
2^28 16.0617
While size grows exponentially, number of element accesses grows almost linearly, so expected time complexity for random permutations is something like O(n log n).
Inverting an array A requires us to find a permutation B which fulfills the requirement A[B[i]] == i for all i.
To build the inverse in-place, we have to swap elements and indices by setting A[A[i]] = i for each element A[i]. Obviously, if we would simply iterate through A and perform aforementioned replacement, we might override upcoming elements in A and our computation would fail.
Therefore, we have to swap elements and indices along cycles of A by following c = A[c] until we reach our cycle's starting index c = i.
Every element of A belongs to one such cycle. Since we have no space to store whether or not an element A[i] has already been processed and needs to be skipped, we have to follow its cycle: If we reach an index c < i we would know that this element is part of a previously processed cycle.
This algorithm has a worst-case run-time complexity of O(n²), an average run-time complexity of O(n log n) and a best-case run-time complexity of O(n).
function invert(array) {
main:
for (var i = 0, length = array.length; i < length; ++i) {
// check if this cycle has already been traversed before:
for (var c = array[i]; c != i; c = array[c]) {
if (c <= i) continue main;
}
// Replacing each cycle element with its predecessors index:
var c_index = i,
c = array[i];
do {
var tmp = array[c];
array[c] = c_index; // replace
c_index = c; // move forward
c = tmp;
} while (i != c_index)
}
return array;
}
console.log(invert([3, 1, 0, 2, 4])); // [2, 1, 3, 0, 4]
Example for A = [1, 2, 3, 0] :
The first element 1 at index 0 belongs to the cycle of elements 1 - 2 - 3 - 0. Once we shift indices 0, 1, 2 and 3 along this cycle, we have completed the first step.
The next element 0 at index 1 belongs to the same cycle and our check tells us so in only one step (since it is a backwards step).
The same holds for the remaining elements 1 and 2.
In total, we perform 4 + 1 + 1 + 1 'operations'. This is the best-case scenario.
Implementation of this explanation in Python:
def inverse_permutation_zero_based(A):
"""
Swap elements and indices along cycles of A by following `c = A[c]` until we reach
our cycle's starting index `c = i`.
Every element of A belongs to one such cycle. Since we have no space to store
whether or not an element A[i] has already been processed and needs to be skipped,
we have to follow its cycle: If we reach an index c < i we would know that this
element is part of a previously processed cycle.
Time Complexity: O(n*n), Space Complexity: O(1)
"""
def cycle(i, A):
"""
Replacing each cycle element with its predecessors index
"""
c_index = i
c = A[i]
while True:
temp = A[c]
A[c] = c_index # replace
c_index = c # move forward
c = temp
if i == c_index:
break
for i in range(len(A)):
# check if this cycle has already been traversed before
j = A[i]
while j != i:
if j <= i:
break
j = A[j]
else:
cycle(i, A)
return A
>>> inverse_permutation_zero_based([3, 1, 0, 2, 4])
[2, 1, 3, 0, 4]
This can be done in O(n) time complexity and O(1) space if we try to store 2 numbers at a single position.
First, let's see how we can get 2 values from a single variable. Suppose we have a variable x and we want to get two values from it, 2 and 1. So,
x = n*1 + 2 , suppose n = 5 here.
x = 5*1 + 2 = 7
Now for 2, we can take remainder of x, ie, x%5. And for 1, we can take quotient of x, ie , x/5
and if we take n = 3
x = 3*1 + 2 = 5
x%3 = 5%3 = 2
x/3 = 5/3 = 1
We know here that the array contains values in range [0, n-1], so we can take the divisor as n, size of array. So, we will use the above concept to store 2 numbers at every index, one will represent old value and other will represent the new value.
A B
0 1 2 3 4 0 1 2 3 4
[3, 1, 0, 2, 4] -> [2, 1, 3, 0, 4]
.
a[0] = 3, that means, a[3] = 0 in our answer.
a[a[0]] = 2 //old
a[a[0]] = 0 //new
a[a[0]] = n* new + old = 5*0 + 2 = 2
a[a[i]] = n*i + a[a[i]]
And during array traversal, a[i] value can be greater than n because we are modifying it. So we will use a[i]%n to get the old value.
So the logic should be
a[a[i]%n] = n*i + a[a[i]%n]
Array -> 13 6 15 2 24
Now, to get the older values, take the remainder on dividing each value by n, and to get the new values, just divide each value by n, in this case, n=5.
Array -> 2 1 3 0 4
Following approach Optimizes the cycle walk if it is already handled. Also each element is 1 based. Need to convert accordingly while trying to access the elements in the given array.
enter code here
#include <stdio.h>
#include <iostream>
#include <vector>
#include <bits/stdc++.h>
using namespace std;
// helper function to traverse cycles
void cycle(int i, vector<int>& A) {
int cur_index = i+1, next_index = A[i];
while (next_index > 0) {
int temp = A[next_index-1];
A[next_index-1] = -(cur_index);
cur_index = next_index;
next_index = temp;
if (i+1 == abs(cur_index)) {
break;
}
}
}
void inverse_permutation(vector<int>& A) {
for (int i = 0; i < A.size(); i++) {
cycle(i, A);
}
for (int i = 0; i < A.size(); i++) {
A[i] = abs(A[i]);
}
for (int i = 0; i < A.size(); i++) {
cout<<A[i]<<" ";
}
}
int main(){
// vector<int> perm = {4,0,3,1,2,5,6,7,8};
vector<int> perm = {5,1,4,2,3,6,7,9,8};
//vector<int> perm = { 17,2,15,19,3,7,12,4,18,20,5,14,13,6,11,10,1,9,8,16};
// vector<int> perm = {4, 1, 2, 3};
// { 6,17,9,23,2,10,20,7,11,5,14,13,4,1,25,22,8,24,21,18,19,12,15,16,3 } =
// { 14,5,25,13,10,1,8,17,3,6,9,22,12,11,23,24,2,20,21,7,19,16,4,18,15 }
// vector<int> perm = {6, 17, 9, 23, 2, 10, 20, 7, 11, 5, 14, 13, 4, 1, 25, 22, 8, 24, 21, 18, 19, 12, 15, 16, 3};
inverse_permutation(perm);
return 0;
}
This is another question (I posted one other one, go look!) from my computer science final study guide. I am not sure how to get the value of x[2] or x[5] without a computer (No computers used during the exam). Can someone please explain how to figure out these values just by reading the code? Thanks!
int x[SIZE] = {5, 3, 4, 5, 2, 4, 3, 5, 1, 2};
int i;
int j;
for(i = 0; i < SIZE / 2; i++)
{
for(j = x[i]; j < SIZE; j++)
{
x[j]++;
}
}
printf("x[2] = %d\n", x[2]);
printf("x[5] = %d\n", x[5]);
Firstly, the array is
int x[SIZE] = {5, 3, 4, 5, 2, 4, 3, 5, 1, 2};
and SIZE is 10 ( or I'll assume it is 10 ).
The outer for loop is
for(i = 0; i < SIZE / 2; i++)
so it iterates from i=0 to i=4.
Now, let's look at the inner for loop
for(j = x[i]; j < SIZE; j++)
{
x[j]++;
}
The value assigned for j is x[i].
Firstly, at i=0, the value of j would be x[0] which is 5. So, the inner for loop executes from j=5 to j=9. In the loop, it does x[j]++, that is, x[5]++, which is 4++, which gives 5. Now on the next iteration of the inner loop, j=6, and x[6]++, so 3++, hence gives 4. So, all the values of the array from x[5] to x[9] are incremented once.
So, the array now becomes
5 3 4 5 2 5 4 6 2 3
If you look at this pattern, you will notice that to for the value of x[2] to change, j must become 2 and for that x[i] must be 2, but looking at the the way the loop will progress, you can see that the values of x[0], x[1] and x[2] will not change. So, x[2] will remain as 4.
Now, moving on to the next iteration of the outer loop, i=1, so j=x[1], so from j=3 to j=9, increment the values of x[j], so the array becomes
5 3 4 6 3 6 5 7 3 4
For the next iteration at i=2, the inner loop iterates from j=4 to j=9, so the array becomes
5 3 4 6 4 7 6 8 4 5
For the next iteration at i=3, the inner loop iterates from j=6 to j=9, and hence the array becomes
5 3 4 6 4 7 7 9 5 6
And now, for the last iteration of the outer loop, at i=4 , the inner loop iterates from j=4 to j=9, and the array becomes
5 3 4 6 5 8 8 10 6 7
So, the output of the program would be
x[2] = 4
x[5] = 8
This is how to interpret programs like these without a compiler.
x is an array. An array has a group of elements in it. The elements are indexed by a number. In C the index starts from 0. So the first element has an index 0, second one's index is 1 and so on.
So if you are looking for x[2] that means the element at index 2 or position 3 which is 4 in the given code. But wait, there is a nested loop between the array definition and the printing of that value. This means that the original values in the array changes. So, you need to figure out what changes the loop makes to the array by manually iterating through it on a piece of paper. I'll leave that part to you.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Zero sum SubArray
An array contains both positive and negative elements, find the
subarray whose sum equals 0.
This is an interview question.
Unfortunately, I cannot read the accepted answer to this question, so I am asking it again: how to find the minimal integer subarray with zero sum?
Note, this is not a "zero subset problem". The obvious brute-force solution is O(N^2) (loop over all subarrays). Can we solve it in O(N)?
This algorithm will find them all, you can easily modify it to find the minimal subarray.
Given an int[] input array, you can create an int[] tmp array where tmp[i] = tmp[i - 1] + input[i]; so that at each element of tmp will store the sum of the input up to that element.
Now if you check tmp, you'll notice that there might be values that are equal to each other. Let's say that this values are at indexes j an k with j < k, then the subarray with sum 0 will be from index j + 1 to k. NOTE: if j + 1 == k, then k is 0 and that's it! ;)
NOTE: The algorithm should consider a virtual tmp[-1] = 0;
The implementation can be done in different ways including using a HashMap as suggested by BrokenGlass but be careful with the special case in the NOTE above.
Example:
int[] input = {4, 6, 3, -9, -5, 1, 3, 0, 2}
int[] tmp = {4, 10, 13, 4, -1, 0, 3, 3, 5}
Note the value 4 in tmp at index 0 and 3 ==> sum tmp 1 to 3 = 0, length (3 - 1) + 1 = 4
Note the value 0 in tmp at index 5 ==> sum tmp 0 to 5 = 0, length (5 - 0) + 1 = 6
Note the value 3 in tmp at index 6 and 7 ==> sum tmp 7 to 7 = 0, length (7 - 7) + 1 = 1
An array contains both positive and negative elements, find the
subarray whose sum equals 0.
Yes that can be done in O(n). If the sum of the elements within a subarray equals zero that means the sum of elements up to the first element before the sub array is the same as the sum of elements up to the last element in the subarray.
Go through the array and for each element K put the sum up to K and the index K in a hashtable, if the sum up to the current element exists already check the index of that element and the current element, if the delta is lower than the minimum subarray length, update the minimum. Update the hashtable with (sum, current index K).