Find sum of integer array without overflow - java

Given an array of integers (positive and negative), each having at most K bits (plus the sign bit), and it is known that the sum of all the integers in the array also has at most K bits (plus the sign bit). Design an algorithm that computes the sum of integers in the array, with all intermediate sums also having at most K bits (plus the sign bit). [Hint: find in what order you should add positive and negative numbers].
This is a question from interview material not a homework
I am actually thinking of creating two separate arrays one for positive and other for negative, sort both of them and then add both so that most negative gets added to most positive... But this seems to have O(nlogn) time complexity(to sort) and O(n) space complexity> Please help!

First note that even if you let the immediate results overflow, the final result will always be correct if it can be represented. This is because integral types of any size act like cyclic groups under addition in most languages including Java (not in C, where integer overflow is undefined behavior, and C#, which is able to throw you an overflow exception).
If you still want to prevent overflow, here's how to perform it in-place and in linear time:
split the array in-place to its negative entries (in any order) and to its positive entries (in any order). Zero can end up anywhere. In other words, perform one quick-sort step with the pivot being zero.
Let ni point to the start of the array (where negative entries are located).
Let pi point to the end of the array.
Let sum be zero.
While pi >= ni
if sum is negative
add arr[pi] to the sum.
if arr[pi] is negative (we've run out of positive addends) and sum is positive (an overflow has occured), the result overflows.
decrement pi
else
add arr[ni] to the sum.
if arr[ni] is positive and sum is negative, the result overflows.
increment ni.
Finally, check if sum has more than K bits. If it does, declare the result overflows.

The main idea is to iterate the array with two indexes: for positive and negative elements. When the sum is negative we will search for next positive element (using corresponding iterator) to add to the sum, otherwise - for the negative one.
This code should work:
public final class ArrayAdder {
#NotNull
private final int[] array;
private int sum;
public ArrayAdder(#NotNull int[] array) {
this.array = array;
}
public int sum() {
sum = 0;
final IntPredicate positive = v -> v > 0;
final Index positiveIndex = new Index(positive);
final Index negativeIndex = new Index(positive.negate());
while (positiveIndex.index < array.length || negativeIndex.index < array.length) {
sum += sum < 0 ? sum(positiveIndex, negativeIndex) : sum(negativeIndex, positiveIndex);
}
return sum;
}
private int sum(#NotNull Index mainIndex, #NotNull Index secondaryIndex) {
int localSum = 0;
// searching for the next suitable element
while (mainIndex.index < array.length && secondaryIndex.sign.test(array[mainIndex.index])) {
mainIndex.index++;
}
if (mainIndex.index < array.length) {
localSum += array[mainIndex.index++];
} else {
// add the remaining elements
for (; secondaryIndex.index < array.length; secondaryIndex.index++) {
if (secondaryIndex.sign.test(array[secondaryIndex.index])) {
localSum += array[secondaryIndex.index];
}
}
}
return localSum;
}
private static final class Index {
#NotNull
private final IntPredicate sign;
private int index;
public Index(#NotNull IntPredicate sign) {
this.sign = sign;
}
}
}

Option 1:
Sort the array in-place and iterate over half of it. At every step, add the ith element with the size-i-1th element.
Doesn't work if there's a few large numbers but many small negative numbers (or vice versa).
Option 2 (improvement):
Sort in-place.
Keep two indexes - one at the start and one at the end. Exit a loop when they meet. At every step if the result so far is negative add the value at the second index and advance it. If the result is positive add the value at the first index and advance it.

Related

How to determine the best postcondition in this question?

Consider the following program segment:
/** Precondition: a[0]...a[n-1] is an initialized array of integers, and 0 < n <= a.length. **/
int c = 0;
for (int i = 0; i < n; i++)
if (a[i] >= 0)
{
a[c] = a[i];
c++;
}
n = c;
Which is the best postcondition for the segment?
a[0] to a[n-1] has been stripped of all positive integers.
a[0] to a[n-1] has been stripped of all negative integers.
a[0] to a[n-1] has been stripped of all nonnegative integers.
4a[0] to a[n-1] has been stripped of all occurrences of zero.
The updated value of n is less than or equal to the value of n before execution
of the segment.
This is a question on the AP CSA exam. The answer key says that 2. is the answer (it states that 5. is also correct but would not be the "best" postcondition). But I am just thinking: "what if ALL the elements in the initial list are negative numbers?" If that's the case, wouldn't it be impossible to strip away any negative number?
"what if ALL the elements in the initial list are negative numbers?" If that's the case, wouldn't it be impossible to strip away any negative number?
I thought so too at first, but note that the end n is updated:
n = c
With that and only negative numbers n would be zero and a[0] to a[n-1] would be an empty set, for which the statement It does not contain negative numbers is true.
Note, that the algorithm is changing the array's values in place, so it really "strips away" negative numbers. It does it by iterating through all elements of array a and moving it to a lower index if it's a non-negative number.
Then at the end, it sets n to the last index of the element which met the criteria (being non-negative). That's why you have n = c; as the last statement.
So statement 2 is true. The new size of the array is always smaller or equal to the original, so statement 5 is also true.
One thing to notice: In Java, you can still reach all elements if you iterate through the original array. Because in Java every array has a fixed length since being initialized. Let's see the following array:
int a[] = {-1,2,3,-4,5,-6,7,8,-9,-10};
So if I iterate using n at the end, I just get the values that meet the criteria:
for (int i = 0; i < n; i++) {
System.out.print(a[i] + ",");
}
This will print 2,3,5,7,8, but if I iterate through a I get all the values from the end of the array:
for (int e : a) {
System.out.print(e + ",");
}
Now it will print 2,3,5,7,8,-6,7,8,-9,-10. So this algorithm leaves some garbage behind.

How to prove the correctness of recursive "search" algorithm in the code?

I don't know how to prove the recursive algorithm of the problem. I can't use the mathematical induction to solve the this proving.(although I am familiar with the mathematical induction).
The problem:
Given an array of integers nums and a positive integer k, find whether it's possible to divide this array into k non-empty subsets whose sums are all equal.
Example 1:
Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
Output: True
Explanation: It's possible to divide it into 4 subsets (5), (1, 4), (2,3), (2,3) with equal sums.
Note:
1 <= k <= len(nums) <= 16. 0 < nums[i] < 10000.
The algorithm:
(https://leetcode.com/problems/partition-to-k-equal-sum-subsets/solution/)
I first tried when i = 0 at the first recursion, the groups[i] = v, and I have to judge the search(groups, row, nums, target). However, at this time, I don't know how to think what the return value that is true or false will influence.
class Solution {
public boolean search(int[] groups, int row, int[] nums, int target) {
if (row < 0) return true;
int v = nums[row--];
for (int i = 0; i < groups.length; i++) {
if (groups[i] + v <= target) {
groups[i] += v;
if (search(groups, row, nums, target)) return true;
groups[i] -= v;
}
if (groups[i] == 0) break;
}
return false;
}
public boolean canPartitionKSubsets(int[] nums, int k) {
int sum = Arrays.stream(nums).sum();
if (sum % k > 0) return false;
int target = sum / k;
Arrays.sort(nums);
int row = nums.length - 1;
if (nums[row] > target) return false;
while (row >= 0 && nums[row] == target) {
row--;
k--;
}
return search(new int[k], row, nums, target);
}
}
The method canPartitionKSubsets first computes the sum sum of all the numbers.
If the partition existed then the sum of the elements in each partition must be target = sum//k. They check that sum is divisible by k.
They check if the last number is greater than target. If it were, then this number couldn't be in any group. So, they return false in that case.
Now it comes the search call. But lets make clear the interpretation of the variables.
In each call to search the variable groups represent the sums of the numbers currently being considered added to each one of the k groups. The variable row represents the position in the original list of the number currently being considered to be added to one of the groups.
Inside search the loop all the cases of adding the number in position row to each one of the k groups. It adds it and recursively tries to search if the is a complete solution that way. If not, it removes it back from the group that it was added.
The groups are attempted to be filled with numbers from the list in order, stating from group 0 to group number k-1.
They break the loop when they reach a group that currently has sum zero. This is an error in the algorithm. For the statement as you wrote it. This step is here only to cut some loops, but it only makes sense under the assumption that all numbers are positive, which at least in your transcription is not given. If the problem allows non-positive numbers, just remove that line from the code.
The algorithm works simply because it tries all cases. If you arrange all possibilities of placing some of the numbers from the list into some of the k groups in a tree, starting with placing none as the root, and branching each time an additional number is placed, then the tree nodes are the same as stack calls, and the leaves of the tree are the arrangements in which all numbers have been placed. The algorithm is doing Depth First Search on the tree, except for the line
if (groups[i] == 0) break;
which is wrong for the problem as stated.
After reading above thought, I take a tumble.
As we know, row represents the position in the original list of the number currently being considered to be added to one of the groups. If row < 0, we will get the all numbers added in the group.The try to put v in the suitable group. And the group in the bottom of the for loop at least have one element because all groups can be seen as the a set. If this group can't contain the one element, another can't, too. If the current group is not fit for the v, then try next group.
Note: The problem limit nums[i > 0. See the Note in the problem I edit.
1 <= k <= len(nums) <= 16. 0 < nums[i] < 10000.

Unique integer pairs in Java [duplicate]

In this case, the MAX is only 5, so I could check the duplicates one by one, but how could I do this in a simpler way? For example, what if the MAX has a value of 20?
Thanks.
int MAX = 5;
for (i = 1 , i <= MAX; i++)
{
drawNum[1] = (int)(Math.random()*MAX)+1;
while (drawNum[2] == drawNum[1])
{
drawNum[2] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[3] == drawNum[1]) || (drawNum[3] == drawNum[2]) )
{
drawNum[3] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[4] == drawNum[1]) || (drawNum[4] == drawNum[2]) || (drawNum[4] == drawNum[3]) )
{
drawNum[4] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[5] == drawNum[1]) ||
(drawNum[5] == drawNum[2]) ||
(drawNum[5] == drawNum[3]) ||
(drawNum[5] == drawNum[4]) )
{
drawNum[5] = (int)(Math.random()*MAX)+1;
}
}
The simplest way would be to create a list of the possible numbers (1..20 or whatever) and then shuffle them with Collections.shuffle. Then just take however many elements you want. This is great if your range is equal to the number of elements you need in the end (e.g. for shuffling a deck of cards).
That doesn't work so well if you want (say) 10 random elements in the range 1..10,000 - you'd end up doing a lot of work unnecessarily. At that point, it's probably better to keep a set of values you've generated so far, and just keep generating numbers in a loop until the next one isn't already present:
if (max < numbersNeeded)
{
throw new IllegalArgumentException("Can't ask for more numbers than are available");
}
Random rng = new Random(); // Ideally just create one instance globally
// Note: use LinkedHashSet to maintain insertion order
Set<Integer> generated = new LinkedHashSet<Integer>();
while (generated.size() < numbersNeeded)
{
Integer next = rng.nextInt(max) + 1;
// As we're adding to a set, this will automatically do a containment check
generated.add(next);
}
Be careful with the set choice though - I've very deliberately used LinkedHashSet as it maintains insertion order, which we care about here.
Yet another option is to always make progress, by reducing the range each time and compensating for existing values. So for example, suppose you wanted 3 values in the range 0..9. On the first iteration you'd generate any number in the range 0..9 - let's say you generate a 4.
On the second iteration you'd then generate a number in the range 0..8. If the generated number is less than 4, you'd keep it as is... otherwise you add one to it. That gets you a result range of 0..9 without 4. Suppose we get 7 that way.
On the third iteration you'd generate a number in the range 0..7. If the generated number is less than 4, you'd keep it as is. If it's 4 or 5, you'd add one. If it's 6 or 7, you'd add two. That way the result range is 0..9 without 4 or 6.
Here's how I'd do it
import java.util.ArrayList;
import java.util.Random;
public class Test {
public static void main(String[] args) {
int size = 20;
ArrayList<Integer> list = new ArrayList<Integer>(size);
for(int i = 1; i <= size; i++) {
list.add(i);
}
Random rand = new Random();
while(list.size() > 0) {
int index = rand.nextInt(list.size());
System.out.println("Selected: "+list.remove(index));
}
}
}
As the esteemed Mr Skeet has pointed out:
If n is the number of randomly selected numbers you wish to choose and N is the total sample space of numbers available for selection:
If n << N, you should just store the numbers that you have picked and check a list to see if the number selected is in it.
If n ~= N, you should probably use my method, by populating a list containing the entire sample space and then removing numbers from it as you select them.
//random numbers are 0,1,2,3
ArrayList<Integer> numbers = new ArrayList<Integer>();
Random randomGenerator = new Random();
while (numbers.size() < 4) {
int random = randomGenerator .nextInt(4);
if (!numbers.contains(random)) {
numbers.add(random);
}
}
This would be a lot simpler in java-8:
Stream.generate(new Random()::ints)
.flatMap(IntStream::boxed)
.distinct()
.limit(16) // whatever limit you might need
.toArray(Integer[]::new);
There is another way of doing "random" ordered numbers with LFSR, take a look at:
http://en.wikipedia.org/wiki/Linear_feedback_shift_register
with this technique you can achieve the ordered random number by index and making sure the values are not duplicated.
But these are not TRUE random numbers because the random generation is deterministic.
But depending your case you can use this technique reducing the amount of processing on random number generation when using shuffling.
Here a LFSR algorithm in java, (I took it somewhere I don't remeber):
public final class LFSR {
private static final int M = 15;
// hard-coded for 15-bits
private static final int[] TAPS = {14, 15};
private final boolean[] bits = new boolean[M + 1];
public LFSR() {
this((int)System.currentTimeMillis());
}
public LFSR(int seed) {
for(int i = 0; i < M; i++) {
bits[i] = (((1 << i) & seed) >>> i) == 1;
}
}
/* generate a random int uniformly on the interval [-2^31 + 1, 2^31 - 1] */
public short nextShort() {
//printBits();
// calculate the integer value from the registers
short next = 0;
for(int i = 0; i < M; i++) {
next |= (bits[i] ? 1 : 0) << i;
}
// allow for zero without allowing for -2^31
if (next < 0) next++;
// calculate the last register from all the preceding
bits[M] = false;
for(int i = 0; i < TAPS.length; i++) {
bits[M] ^= bits[M - TAPS[i]];
}
// shift all the registers
for(int i = 0; i < M; i++) {
bits[i] = bits[i + 1];
}
return next;
}
/** returns random double uniformly over [0, 1) */
public double nextDouble() {
return ((nextShort() / (Integer.MAX_VALUE + 1.0)) + 1.0) / 2.0;
}
/** returns random boolean */
public boolean nextBoolean() {
return nextShort() >= 0;
}
public void printBits() {
System.out.print(bits[M] ? 1 : 0);
System.out.print(" -> ");
for(int i = M - 1; i >= 0; i--) {
System.out.print(bits[i] ? 1 : 0);
}
System.out.println();
}
public static void main(String[] args) {
LFSR rng = new LFSR();
Vector<Short> vec = new Vector<Short>();
for(int i = 0; i <= 32766; i++) {
short next = rng.nextShort();
// just testing/asserting to make
// sure the number doesn't repeat on a given list
if (vec.contains(next))
throw new RuntimeException("Index repeat: " + i);
vec.add(next);
System.out.println(next);
}
}
}
Another approach which allows you to specify how many numbers you want with size and the min and max values of the returned numbers
public static int getRandomInt(int min, int max) {
Random random = new Random();
return random.nextInt((max - min) + 1) + min;
}
public static ArrayList<Integer> getRandomNonRepeatingIntegers(int size, int min,
int max) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
while (numbers.size() < size) {
int random = getRandomInt(min, max);
if (!numbers.contains(random)) {
numbers.add(random);
}
}
return numbers;
}
To use it returning 7 numbers between 0 and 25.
ArrayList<Integer> list = getRandomNonRepeatingIntegers(7, 0, 25);
for (int i = 0; i < list.size(); i++) {
System.out.println("" + list.get(i));
}
The most efficient, basic way to have non-repeating random numbers is explained by this pseudo-code. There is no need to have nested loops or hashed lookups:
// get 5 unique random numbers, possible values 0 - 19
// (assume desired number of selections < number of choices)
const int POOL_SIZE = 20;
const int VAL_COUNT = 5;
declare Array mapping[POOL_SIZE];
declare Array results[VAL_COUNT];
declare i int;
declare r int;
declare max_rand int;
// create mapping array
for (i=0; i<POOL_SIZE; i++) {
mapping[i] = i;
}
max_rand = POOL_SIZE-1; // start loop searching for maximum value (19)
for (i=0; i<VAL_COUNT; i++) {
r = Random(0, max_rand); // get random number
results[i] = mapping[r]; // grab number from map array
mapping[r] = max_rand; // place item past range at selected location
max_rand = max_rand - 1; // reduce random scope by 1
}
Suppose first iteration generated random number 3 to start (from 0 - 19). This would make results[0] = mapping[3], i.e., the value 3. We'd then assign mapping[3] to 19.
In the next iteration, the random number was 5 (from 0 - 18). This would make results[1] = mapping[5], i.e., the value 5. We'd then assign mapping[5] to 18.
Now suppose the next iteration chose 3 again (from 0 - 17). results[2] would be assigned the value of mapping[3], but now, this value is not 3, but 19.
This same protection persists for all numbers, even if you got the same number 5 times in a row. E.g., if the random number generator gave you 0 five times in a row, the results would be: [ 0, 19, 18, 17, 16 ].
You would never get the same number twice.
Generating all the indices of a sequence is generally a bad idea, as it might take a lot of time, especially if the ratio of the numbers to be chosen to MAX is low (the complexity becomes dominated by O(MAX)). This gets worse if the ratio of the numbers to be chosen to MAX approaches one, as then removing the chosen indices from the sequence of all also becomes expensive (we approach O(MAX^2/2)). But for small numbers, this generally works well and is not particularly error-prone.
Filtering the generated indices by using a collection is also a bad idea, as some time is spent in inserting the indices into the sequence, and progress is not guaranteed as the same random number can be drawn several times (but for large enough MAX it is unlikely). This could be close to complexity O(k n log^2(n)/2), ignoring the duplicates and assuming the collection uses a tree for efficient lookup (but with a significant constant cost k of allocating the tree nodes and possibly having to rebalance).
Another option is to generate the random values uniquely from the beginning, guaranteeing progress is being made. That means in the first round, a random index in [0, MAX] is generated:
items i0 i1 i2 i3 i4 i5 i6 (total 7 items)
idx 0 ^^ (index 2)
In the second round, only [0, MAX - 1] is generated (as one item was already selected):
items i0 i1 i3 i4 i5 i6 (total 6 items)
idx 1 ^^ (index 2 out of these 6, but 3 out of the original 7)
The values of the indices then need to be adjusted: if the second index falls in the second half of the sequence (after the first index), it needs to be incremented to account for the gap. We can implement this as a loop, allowing us to select arbitrary number of unique items.
For short sequences, this is quite fast O(n^2/2) algorithm:
void RandomUniqueSequence(std::vector<int> &rand_num,
const size_t n_select_num, const size_t n_item_num)
{
assert(n_select_num <= n_item_num);
rand_num.clear(); // !!
// b1: 3187.000 msec (the fastest)
// b2: 3734.000 msec
for(size_t i = 0; i < n_select_num; ++ i) {
int n = n_Rand(n_item_num - i - 1);
// get a random number
size_t n_where = i;
for(size_t j = 0; j < i; ++ j) {
if(n + j < rand_num[j]) {
n_where = j;
break;
}
}
// see where it should be inserted
rand_num.insert(rand_num.begin() + n_where, 1, n + n_where);
// insert it in the list, maintain a sorted sequence
}
// tier 1 - use comparison with offset instead of increment
}
Where n_select_num is your 5 and n_number_num is your MAX. The n_Rand(x) returns random integers in [0, x] (inclusive). This can be made a bit faster if selecting a lot of items (e.g. not 5 but 500) by using binary search to find the insertion point. To do that, we need to make sure that we meet the requirements.
We will do binary search with the comparison n + j < rand_num[j] which is the same as n < rand_num[j] - j. We need to show that rand_num[j] - j is still a sorted sequence for a sorted sequence rand_num[j]. This is fortunately easily shown, as the lowest distance between two elements of the original rand_num is one (the generated numbers are unique, so there is always difference of at least 1). At the same time, if we subtract the indices j from all the elements rand_num[j], the differences in index are exactly 1. So in the "worst" case, we get a constant sequence - but never decreasing. The binary search can therefore be used, yielding O(n log(n)) algorithm:
struct TNeedle { // in the comparison operator we need to make clear which argument is the needle and which is already in the list; we do that using the type system.
int n;
TNeedle(int _n)
:n(_n)
{}
};
class CCompareWithOffset { // custom comparison "n < rand_num[j] - j"
protected:
std::vector<int>::iterator m_p_begin_it;
public:
CCompareWithOffset(std::vector<int>::iterator p_begin_it)
:m_p_begin_it(p_begin_it)
{}
bool operator ()(const int &r_value, TNeedle n) const
{
size_t n_index = &r_value - &*m_p_begin_it;
// calculate index in the array
return r_value < n.n + n_index; // or r_value - n_index < n.n
}
bool operator ()(TNeedle n, const int &r_value) const
{
size_t n_index = &r_value - &*m_p_begin_it;
// calculate index in the array
return n.n + n_index < r_value; // or n.n < r_value - n_index
}
};
And finally:
void RandomUniqueSequence(std::vector<int> &rand_num,
const size_t n_select_num, const size_t n_item_num)
{
assert(n_select_num <= n_item_num);
rand_num.clear(); // !!
// b1: 3578.000 msec
// b2: 1703.000 msec (the fastest)
for(size_t i = 0; i < n_select_num; ++ i) {
int n = n_Rand(n_item_num - i - 1);
// get a random number
std::vector<int>::iterator p_where_it = std::upper_bound(rand_num.begin(), rand_num.end(),
TNeedle(n), CCompareWithOffset(rand_num.begin()));
// see where it should be inserted
rand_num.insert(p_where_it, 1, n + p_where_it - rand_num.begin());
// insert it in the list, maintain a sorted sequence
}
// tier 4 - use binary search
}
I have tested this on three benchmarks. First, 3 numbers were chosen out of 7 items, and a histogram of the items chosen was accumulated over 10,000 runs:
4265 4229 4351 4267 4267 4364 4257
This shows that each of the 7 items was chosen approximately the same number of times, and there is no apparent bias caused by the algorithm. All the sequences were also checked for correctness (uniqueness of contents).
The second benchmark involved choosing 7 numbers out of 5000 items. The time of several versions of the algorithm was accumulated over 10,000,000 runs. The results are denoted in comments in the code as b1. The simple version of the algorithm is slightly faster.
The third benchmark involved choosing 700 numbers out of 5000 items. The time of several versions of the algorithm was again accumulated, this time over 10,000 runs. The results are denoted in comments in the code as b2. The binary search version of the algorithm is now more than two times faster than the simple one.
The second method starts being faster for choosing more than cca 75 items on my machine (note that the complexity of either algorithm does not depend on the number of items, MAX).
It is worth mentioning that the above algorithms generate the random numbers in ascending order. But it would be simple to add another array to which the numbers would be saved in the order in which they were generated, and returning that instead (at negligible additional cost O(n)). It is not necessary to shuffle the output: that would be much slower.
Note that the sources are in C++, I don't have Java on my machine, but the concept should be clear.
EDIT:
For amusement, I have also implemented the approach that generates a list with all the indices 0 .. MAX, chooses them randomly and removes them from the list to guarantee uniqueness. Since I've chosen quite high MAX (5000), the performance is catastrophic:
// b1: 519515.000 msec
// b2: 20312.000 msec
std::vector<int> all_numbers(n_item_num);
std::iota(all_numbers.begin(), all_numbers.end(), 0);
// generate all the numbers
for(size_t i = 0; i < n_number_num; ++ i) {
assert(all_numbers.size() == n_item_num - i);
int n = n_Rand(n_item_num - i - 1);
// get a random number
rand_num.push_back(all_numbers[n]); // put it in the output list
all_numbers.erase(all_numbers.begin() + n); // erase it from the input
}
// generate random numbers
I have also implemented the approach with a set (a C++ collection), which actually comes second on benchmark b2, being only about 50% slower than the approach with the binary search. That is understandable, as the set uses a binary tree, where the insertion cost is similar to binary search. The only difference is the chance of getting duplicate items, which slows down the progress.
// b1: 20250.000 msec
// b2: 2296.000 msec
std::set<int> numbers;
while(numbers.size() < n_number_num)
numbers.insert(n_Rand(n_item_num - 1)); // might have duplicates here
// generate unique random numbers
rand_num.resize(numbers.size());
std::copy(numbers.begin(), numbers.end(), rand_num.begin());
// copy the numbers from a set to a vector
Full source code is here.
Your problem seems to reduce to choose k elements at random from a collection of n elements. The Collections.shuffle answer is thus correct, but as pointed out inefficient: its O(n).
Wikipedia: Fisher–Yates shuffle has a O(k) version when the array already exists. In your case, there is no array of elements and creating the array of elements could be very expensive, say if max were 10000000 instead of 20.
The shuffle algorithm involves initializing an array of size n where every element is equal to its index, picking k random numbers each number in a range with the max one less than the previous range, then swapping elements towards the end of the array.
You can do the same operation in O(k) time with a hashmap although I admit its kind of a pain. Note that this is only worthwhile if k is much less than n. (ie k ~ lg(n) or so), otherwise you should use the shuffle directly.
You will use your hashmap as an efficient representation of the backing array in the shuffle algorithm. Any element of the array that is equal to its index need not appear in the map. This allows you to represent an array of size n in constant time, there is no time spent initializing it.
Pick k random numbers: the first is in the range 0 to n-1, the second 0 to n-2, the third 0 to n-3 and so on, thru n-k.
Treat your random numbers as a set of swaps. The first random index swaps to the final position. The second random index swaps to the second to last position. However, instead of working against a backing array, work against your hashmap. Your hashmap will store every item that is out of position.
int getValue(i)
{
if (map.contains(i))
return map[i];
return i;
}
void setValue(i, val)
{
if (i == val)
map.remove(i);
else
map[i] = val;
}
int[] chooseK(int n, int k)
{
for (int i = 0; i < k; i++)
{
int randomIndex = nextRandom(0, n - i); //(n - i is exclusive)
int desiredIndex = n-i-1;
int valAtRandom = getValue(randomIndex);
int valAtDesired = getValue(desiredIndex);
setValue(desiredIndex, valAtRandom);
setValue(randomIndex, valAtDesired);
}
int[] output = new int[k];
for (int i = 0; i < k; i++)
{
output[i] = (getValue(n-i-1));
}
return output;
}
You could use one of the classes implementing the Set interface (API), and then each number you generate, use Set.add() to insert it.
If the return value is false, you know the number has already been generated before.
Instead of doing all this create a LinkedHashSet object and random numbers to it by Math.random() function .... if any duplicated entry occurs the LinkedHashSet object won't add that number to its List ... Since in this Collection Class no duplicate values are allowed .. in the end u get a list of random numbers having no duplicated values .... :D
With Java 8 upwards you can use the ints method from the IntStream interface:
Returns an effectively unlimited stream of pseudorandom int values.
Random r = new Random();
int randomNumberOrigin = 0;
int randomNumberBound = 10;
int size = 5;
int[] unique = r.ints(randomNumberOrigin, randomNumberBound)
.distinct()
.limit(size)
.toArray();
Following code create a sequence random number between [1,m] that was not generated before.
public class NewClass {
public List<Integer> keys = new ArrayList<Integer>();
public int rand(int m) {
int n = (int) (Math.random() * m + 1);
if (!keys.contains(n)) {
keys.add(n);
return n;
} else {
return rand(m);
}
}
public static void main(String[] args) {
int m = 4;
NewClass ne = new NewClass();
for (int i = 0; i < 4; i++) {
System.out.println(ne.rand(m));
}
System.out.println("list: " + ne.keys);
}
}
The most easy way is use nano DateTime as long format.
System.nanoTime();
There is algorithm of card batch: you create ordered array of numbers (the "card batch") and in every iteration you select a number at random position from it (removing the selected number from the "card batch" of course).
Here is an efficient solution for fast creation of a randomized array. After randomization you can simply pick the n-th element e of the array, increment n and return e. This solution has O(1) for getting a random number and O(n) for initialization, but as a tradeoff requires a good amount of memory if n gets large enough.
There is a more efficient and less cumbersome solution for integers than a Collections.shuffle.
The problem is the same as successively picking items from only the un-picked items in a set and setting them in order somewhere else. This is exactly like randomly dealing cards or drawing winning raffle tickets from a hat or bin.
This algorithm works for loading any array and achieving a random order at the end of the load. It also works for adding into a List collection (or any other indexed collection) and achieving a random sequence in the collection at the end of the adds.
It can be done with a single array, created once, or a numerically ordered collectio, such as a List, in place. For an array, the initial array size needs to be the exact size to contain all the intended values. If you don't know how many values might occur in advance, using a numerically orderred collection, such as an ArrayList or List, where the size is not immutable, will also work. It will work universally for an array of any size up to Integer.MAX_VALUE which is just over 2,000,000,000. List objects will have the same index limits. Your machine may run out of memory before you get to an array of that size. It may be more efficient to load an array typed to the object types and convert it to some collection, after loading the array. This is especially true if the target collection is not numerically indexed.
This algorithm, exactly as written, will create a very even distribution where there are no duplicates. One aspect that is VERY IMPORTANT is that it has to be possible for the insertion of the next item to occur up to the current size + 1. Thus, for the second item, it could be possible to store it in location 0 or location 1. For the 20th item, it could be possible to store it in any location, 0 through 19. It is just as possible the first item to stay in location 0 as it is for it to end up in any other location. It is just as possible for the next new item to go anywhere, including the next new location.
The randomness of the sequence will be as random as the randomness of the random number generator.
This algorithm can also be used to load reference types into random locations in an array. Since this works with an array, it can also work with collections. That means you don't have to create the collection and then shuffle it or have it ordered on whatever orders the objects being inserted. The collection need only have the ability to insert an item anywhere in the collection or append it.
// RandomSequence.java
import java.util.Random;
public class RandomSequence {
public static void main(String[] args) {
// create an array of the size and type for which
// you want a random sequence
int[] randomSequence = new int[20];
Random randomNumbers = new Random();
for (int i = 0; i < randomSequence.length; i++ ) {
if (i == 0) { // seed first entry in array with item 0
randomSequence[i] = 0;
} else { // for all other items...
// choose a random pointer to the segment of the
// array already containing items
int pointer = randomNumbers.nextInt(i + 1);
randomSequence[i] = randomSequence[pointer];
randomSequence[pointer] = i;
// note that if pointer & i are equal
// the new value will just go into location i and possibly stay there
// this is VERY IMPORTANT to ensure the sequence is really random
// and not biased
} // end if...else
} // end for
for (int number: randomSequence) {
System.out.printf("%2d ", number);
} // end for
} // end main
} // end class RandomSequence
It really all depends on exactly WHAT you need the random generation for, but here's my take.
First, create a standalone method for generating the random number.
Be sure to allow for limits.
public static int newRandom(int limit){
return generatedRandom.nextInt(limit); }
Next, you will want to create a very simple decision structure that compares values. This can be done in one of two ways. If you have a very limited amount of numbers to verify, a simple IF statement will suffice:
public static int testDuplicates(int int1, int int2, int int3, int int4, int int5){
boolean loopFlag = true;
while(loopFlag == true){
if(int1 == int2 || int1 == int3 || int1 == int4 || int1 == int5 || int1 == 0){
int1 = newRandom(75);
loopFlag = true; }
else{
loopFlag = false; }}
return int1; }
The above compares int1 to int2 through int5, as well as making sure that there are no zeroes in the randoms.
With these two methods in place, we can do the following:
num1 = newRandom(limit1);
num2 = newRandom(limit1);
num3 = newRandom(limit1);
num4 = newRandom(limit1);
num5 = newRandom(limit1);
Followed By:
num1 = testDuplicates(num1, num2, num3, num4, num5);
num2 = testDuplicates(num2, num1, num3, num4, num5);
num3 = testDuplicates(num3, num1, num2, num4, num5);
num4 = testDuplicates(num4, num1, num2, num3, num5);
num5 = testDuplicates(num5, num1, num2, num3, num5);
If you have a longer list to verify, then a more complex method will yield better results both in clarity of code and in processing resources.
Hope this helps. This site has helped me so much, I felt obliged to at least TRY to help as well.
I created a snippet that generates no duplicate random integer. the advantage of this snippet is that you can assign the list of an array to it and generate the random item, too.
No duplication random generator class
With Java 8 using the below code, you can create 10 distinct random Integer Numbers within a range of 1000.
Random random = new Random();
Integer[] input9 = IntStream.range(1, 10).map(i -> random.nextInt(1000)).boxed().distinct()
.toArray(Integer[]::new);
System.out.println(Arrays.toString(input9));
Modify the range to generate more numbers example : range(1,X). It will generate X distinct random numbers.
Modify the nextInt value to select the random number range : random.nextInt(Y)::random number will be generated within the range Y

How to exclude one number from Random generator every time? [duplicate]

In this case, the MAX is only 5, so I could check the duplicates one by one, but how could I do this in a simpler way? For example, what if the MAX has a value of 20?
Thanks.
int MAX = 5;
for (i = 1 , i <= MAX; i++)
{
drawNum[1] = (int)(Math.random()*MAX)+1;
while (drawNum[2] == drawNum[1])
{
drawNum[2] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[3] == drawNum[1]) || (drawNum[3] == drawNum[2]) )
{
drawNum[3] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[4] == drawNum[1]) || (drawNum[4] == drawNum[2]) || (drawNum[4] == drawNum[3]) )
{
drawNum[4] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[5] == drawNum[1]) ||
(drawNum[5] == drawNum[2]) ||
(drawNum[5] == drawNum[3]) ||
(drawNum[5] == drawNum[4]) )
{
drawNum[5] = (int)(Math.random()*MAX)+1;
}
}
The simplest way would be to create a list of the possible numbers (1..20 or whatever) and then shuffle them with Collections.shuffle. Then just take however many elements you want. This is great if your range is equal to the number of elements you need in the end (e.g. for shuffling a deck of cards).
That doesn't work so well if you want (say) 10 random elements in the range 1..10,000 - you'd end up doing a lot of work unnecessarily. At that point, it's probably better to keep a set of values you've generated so far, and just keep generating numbers in a loop until the next one isn't already present:
if (max < numbersNeeded)
{
throw new IllegalArgumentException("Can't ask for more numbers than are available");
}
Random rng = new Random(); // Ideally just create one instance globally
// Note: use LinkedHashSet to maintain insertion order
Set<Integer> generated = new LinkedHashSet<Integer>();
while (generated.size() < numbersNeeded)
{
Integer next = rng.nextInt(max) + 1;
// As we're adding to a set, this will automatically do a containment check
generated.add(next);
}
Be careful with the set choice though - I've very deliberately used LinkedHashSet as it maintains insertion order, which we care about here.
Yet another option is to always make progress, by reducing the range each time and compensating for existing values. So for example, suppose you wanted 3 values in the range 0..9. On the first iteration you'd generate any number in the range 0..9 - let's say you generate a 4.
On the second iteration you'd then generate a number in the range 0..8. If the generated number is less than 4, you'd keep it as is... otherwise you add one to it. That gets you a result range of 0..9 without 4. Suppose we get 7 that way.
On the third iteration you'd generate a number in the range 0..7. If the generated number is less than 4, you'd keep it as is. If it's 4 or 5, you'd add one. If it's 6 or 7, you'd add two. That way the result range is 0..9 without 4 or 6.
Here's how I'd do it
import java.util.ArrayList;
import java.util.Random;
public class Test {
public static void main(String[] args) {
int size = 20;
ArrayList<Integer> list = new ArrayList<Integer>(size);
for(int i = 1; i <= size; i++) {
list.add(i);
}
Random rand = new Random();
while(list.size() > 0) {
int index = rand.nextInt(list.size());
System.out.println("Selected: "+list.remove(index));
}
}
}
As the esteemed Mr Skeet has pointed out:
If n is the number of randomly selected numbers you wish to choose and N is the total sample space of numbers available for selection:
If n << N, you should just store the numbers that you have picked and check a list to see if the number selected is in it.
If n ~= N, you should probably use my method, by populating a list containing the entire sample space and then removing numbers from it as you select them.
//random numbers are 0,1,2,3
ArrayList<Integer> numbers = new ArrayList<Integer>();
Random randomGenerator = new Random();
while (numbers.size() < 4) {
int random = randomGenerator .nextInt(4);
if (!numbers.contains(random)) {
numbers.add(random);
}
}
This would be a lot simpler in java-8:
Stream.generate(new Random()::ints)
.flatMap(IntStream::boxed)
.distinct()
.limit(16) // whatever limit you might need
.toArray(Integer[]::new);
There is another way of doing "random" ordered numbers with LFSR, take a look at:
http://en.wikipedia.org/wiki/Linear_feedback_shift_register
with this technique you can achieve the ordered random number by index and making sure the values are not duplicated.
But these are not TRUE random numbers because the random generation is deterministic.
But depending your case you can use this technique reducing the amount of processing on random number generation when using shuffling.
Here a LFSR algorithm in java, (I took it somewhere I don't remeber):
public final class LFSR {
private static final int M = 15;
// hard-coded for 15-bits
private static final int[] TAPS = {14, 15};
private final boolean[] bits = new boolean[M + 1];
public LFSR() {
this((int)System.currentTimeMillis());
}
public LFSR(int seed) {
for(int i = 0; i < M; i++) {
bits[i] = (((1 << i) & seed) >>> i) == 1;
}
}
/* generate a random int uniformly on the interval [-2^31 + 1, 2^31 - 1] */
public short nextShort() {
//printBits();
// calculate the integer value from the registers
short next = 0;
for(int i = 0; i < M; i++) {
next |= (bits[i] ? 1 : 0) << i;
}
// allow for zero without allowing for -2^31
if (next < 0) next++;
// calculate the last register from all the preceding
bits[M] = false;
for(int i = 0; i < TAPS.length; i++) {
bits[M] ^= bits[M - TAPS[i]];
}
// shift all the registers
for(int i = 0; i < M; i++) {
bits[i] = bits[i + 1];
}
return next;
}
/** returns random double uniformly over [0, 1) */
public double nextDouble() {
return ((nextShort() / (Integer.MAX_VALUE + 1.0)) + 1.0) / 2.0;
}
/** returns random boolean */
public boolean nextBoolean() {
return nextShort() >= 0;
}
public void printBits() {
System.out.print(bits[M] ? 1 : 0);
System.out.print(" -> ");
for(int i = M - 1; i >= 0; i--) {
System.out.print(bits[i] ? 1 : 0);
}
System.out.println();
}
public static void main(String[] args) {
LFSR rng = new LFSR();
Vector<Short> vec = new Vector<Short>();
for(int i = 0; i <= 32766; i++) {
short next = rng.nextShort();
// just testing/asserting to make
// sure the number doesn't repeat on a given list
if (vec.contains(next))
throw new RuntimeException("Index repeat: " + i);
vec.add(next);
System.out.println(next);
}
}
}
Another approach which allows you to specify how many numbers you want with size and the min and max values of the returned numbers
public static int getRandomInt(int min, int max) {
Random random = new Random();
return random.nextInt((max - min) + 1) + min;
}
public static ArrayList<Integer> getRandomNonRepeatingIntegers(int size, int min,
int max) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
while (numbers.size() < size) {
int random = getRandomInt(min, max);
if (!numbers.contains(random)) {
numbers.add(random);
}
}
return numbers;
}
To use it returning 7 numbers between 0 and 25.
ArrayList<Integer> list = getRandomNonRepeatingIntegers(7, 0, 25);
for (int i = 0; i < list.size(); i++) {
System.out.println("" + list.get(i));
}
The most efficient, basic way to have non-repeating random numbers is explained by this pseudo-code. There is no need to have nested loops or hashed lookups:
// get 5 unique random numbers, possible values 0 - 19
// (assume desired number of selections < number of choices)
const int POOL_SIZE = 20;
const int VAL_COUNT = 5;
declare Array mapping[POOL_SIZE];
declare Array results[VAL_COUNT];
declare i int;
declare r int;
declare max_rand int;
// create mapping array
for (i=0; i<POOL_SIZE; i++) {
mapping[i] = i;
}
max_rand = POOL_SIZE-1; // start loop searching for maximum value (19)
for (i=0; i<VAL_COUNT; i++) {
r = Random(0, max_rand); // get random number
results[i] = mapping[r]; // grab number from map array
mapping[r] = max_rand; // place item past range at selected location
max_rand = max_rand - 1; // reduce random scope by 1
}
Suppose first iteration generated random number 3 to start (from 0 - 19). This would make results[0] = mapping[3], i.e., the value 3. We'd then assign mapping[3] to 19.
In the next iteration, the random number was 5 (from 0 - 18). This would make results[1] = mapping[5], i.e., the value 5. We'd then assign mapping[5] to 18.
Now suppose the next iteration chose 3 again (from 0 - 17). results[2] would be assigned the value of mapping[3], but now, this value is not 3, but 19.
This same protection persists for all numbers, even if you got the same number 5 times in a row. E.g., if the random number generator gave you 0 five times in a row, the results would be: [ 0, 19, 18, 17, 16 ].
You would never get the same number twice.
Generating all the indices of a sequence is generally a bad idea, as it might take a lot of time, especially if the ratio of the numbers to be chosen to MAX is low (the complexity becomes dominated by O(MAX)). This gets worse if the ratio of the numbers to be chosen to MAX approaches one, as then removing the chosen indices from the sequence of all also becomes expensive (we approach O(MAX^2/2)). But for small numbers, this generally works well and is not particularly error-prone.
Filtering the generated indices by using a collection is also a bad idea, as some time is spent in inserting the indices into the sequence, and progress is not guaranteed as the same random number can be drawn several times (but for large enough MAX it is unlikely). This could be close to complexity O(k n log^2(n)/2), ignoring the duplicates and assuming the collection uses a tree for efficient lookup (but with a significant constant cost k of allocating the tree nodes and possibly having to rebalance).
Another option is to generate the random values uniquely from the beginning, guaranteeing progress is being made. That means in the first round, a random index in [0, MAX] is generated:
items i0 i1 i2 i3 i4 i5 i6 (total 7 items)
idx 0 ^^ (index 2)
In the second round, only [0, MAX - 1] is generated (as one item was already selected):
items i0 i1 i3 i4 i5 i6 (total 6 items)
idx 1 ^^ (index 2 out of these 6, but 3 out of the original 7)
The values of the indices then need to be adjusted: if the second index falls in the second half of the sequence (after the first index), it needs to be incremented to account for the gap. We can implement this as a loop, allowing us to select arbitrary number of unique items.
For short sequences, this is quite fast O(n^2/2) algorithm:
void RandomUniqueSequence(std::vector<int> &rand_num,
const size_t n_select_num, const size_t n_item_num)
{
assert(n_select_num <= n_item_num);
rand_num.clear(); // !!
// b1: 3187.000 msec (the fastest)
// b2: 3734.000 msec
for(size_t i = 0; i < n_select_num; ++ i) {
int n = n_Rand(n_item_num - i - 1);
// get a random number
size_t n_where = i;
for(size_t j = 0; j < i; ++ j) {
if(n + j < rand_num[j]) {
n_where = j;
break;
}
}
// see where it should be inserted
rand_num.insert(rand_num.begin() + n_where, 1, n + n_where);
// insert it in the list, maintain a sorted sequence
}
// tier 1 - use comparison with offset instead of increment
}
Where n_select_num is your 5 and n_number_num is your MAX. The n_Rand(x) returns random integers in [0, x] (inclusive). This can be made a bit faster if selecting a lot of items (e.g. not 5 but 500) by using binary search to find the insertion point. To do that, we need to make sure that we meet the requirements.
We will do binary search with the comparison n + j < rand_num[j] which is the same as n < rand_num[j] - j. We need to show that rand_num[j] - j is still a sorted sequence for a sorted sequence rand_num[j]. This is fortunately easily shown, as the lowest distance between two elements of the original rand_num is one (the generated numbers are unique, so there is always difference of at least 1). At the same time, if we subtract the indices j from all the elements rand_num[j], the differences in index are exactly 1. So in the "worst" case, we get a constant sequence - but never decreasing. The binary search can therefore be used, yielding O(n log(n)) algorithm:
struct TNeedle { // in the comparison operator we need to make clear which argument is the needle and which is already in the list; we do that using the type system.
int n;
TNeedle(int _n)
:n(_n)
{}
};
class CCompareWithOffset { // custom comparison "n < rand_num[j] - j"
protected:
std::vector<int>::iterator m_p_begin_it;
public:
CCompareWithOffset(std::vector<int>::iterator p_begin_it)
:m_p_begin_it(p_begin_it)
{}
bool operator ()(const int &r_value, TNeedle n) const
{
size_t n_index = &r_value - &*m_p_begin_it;
// calculate index in the array
return r_value < n.n + n_index; // or r_value - n_index < n.n
}
bool operator ()(TNeedle n, const int &r_value) const
{
size_t n_index = &r_value - &*m_p_begin_it;
// calculate index in the array
return n.n + n_index < r_value; // or n.n < r_value - n_index
}
};
And finally:
void RandomUniqueSequence(std::vector<int> &rand_num,
const size_t n_select_num, const size_t n_item_num)
{
assert(n_select_num <= n_item_num);
rand_num.clear(); // !!
// b1: 3578.000 msec
// b2: 1703.000 msec (the fastest)
for(size_t i = 0; i < n_select_num; ++ i) {
int n = n_Rand(n_item_num - i - 1);
// get a random number
std::vector<int>::iterator p_where_it = std::upper_bound(rand_num.begin(), rand_num.end(),
TNeedle(n), CCompareWithOffset(rand_num.begin()));
// see where it should be inserted
rand_num.insert(p_where_it, 1, n + p_where_it - rand_num.begin());
// insert it in the list, maintain a sorted sequence
}
// tier 4 - use binary search
}
I have tested this on three benchmarks. First, 3 numbers were chosen out of 7 items, and a histogram of the items chosen was accumulated over 10,000 runs:
4265 4229 4351 4267 4267 4364 4257
This shows that each of the 7 items was chosen approximately the same number of times, and there is no apparent bias caused by the algorithm. All the sequences were also checked for correctness (uniqueness of contents).
The second benchmark involved choosing 7 numbers out of 5000 items. The time of several versions of the algorithm was accumulated over 10,000,000 runs. The results are denoted in comments in the code as b1. The simple version of the algorithm is slightly faster.
The third benchmark involved choosing 700 numbers out of 5000 items. The time of several versions of the algorithm was again accumulated, this time over 10,000 runs. The results are denoted in comments in the code as b2. The binary search version of the algorithm is now more than two times faster than the simple one.
The second method starts being faster for choosing more than cca 75 items on my machine (note that the complexity of either algorithm does not depend on the number of items, MAX).
It is worth mentioning that the above algorithms generate the random numbers in ascending order. But it would be simple to add another array to which the numbers would be saved in the order in which they were generated, and returning that instead (at negligible additional cost O(n)). It is not necessary to shuffle the output: that would be much slower.
Note that the sources are in C++, I don't have Java on my machine, but the concept should be clear.
EDIT:
For amusement, I have also implemented the approach that generates a list with all the indices 0 .. MAX, chooses them randomly and removes them from the list to guarantee uniqueness. Since I've chosen quite high MAX (5000), the performance is catastrophic:
// b1: 519515.000 msec
// b2: 20312.000 msec
std::vector<int> all_numbers(n_item_num);
std::iota(all_numbers.begin(), all_numbers.end(), 0);
// generate all the numbers
for(size_t i = 0; i < n_number_num; ++ i) {
assert(all_numbers.size() == n_item_num - i);
int n = n_Rand(n_item_num - i - 1);
// get a random number
rand_num.push_back(all_numbers[n]); // put it in the output list
all_numbers.erase(all_numbers.begin() + n); // erase it from the input
}
// generate random numbers
I have also implemented the approach with a set (a C++ collection), which actually comes second on benchmark b2, being only about 50% slower than the approach with the binary search. That is understandable, as the set uses a binary tree, where the insertion cost is similar to binary search. The only difference is the chance of getting duplicate items, which slows down the progress.
// b1: 20250.000 msec
// b2: 2296.000 msec
std::set<int> numbers;
while(numbers.size() < n_number_num)
numbers.insert(n_Rand(n_item_num - 1)); // might have duplicates here
// generate unique random numbers
rand_num.resize(numbers.size());
std::copy(numbers.begin(), numbers.end(), rand_num.begin());
// copy the numbers from a set to a vector
Full source code is here.
Your problem seems to reduce to choose k elements at random from a collection of n elements. The Collections.shuffle answer is thus correct, but as pointed out inefficient: its O(n).
Wikipedia: Fisher–Yates shuffle has a O(k) version when the array already exists. In your case, there is no array of elements and creating the array of elements could be very expensive, say if max were 10000000 instead of 20.
The shuffle algorithm involves initializing an array of size n where every element is equal to its index, picking k random numbers each number in a range with the max one less than the previous range, then swapping elements towards the end of the array.
You can do the same operation in O(k) time with a hashmap although I admit its kind of a pain. Note that this is only worthwhile if k is much less than n. (ie k ~ lg(n) or so), otherwise you should use the shuffle directly.
You will use your hashmap as an efficient representation of the backing array in the shuffle algorithm. Any element of the array that is equal to its index need not appear in the map. This allows you to represent an array of size n in constant time, there is no time spent initializing it.
Pick k random numbers: the first is in the range 0 to n-1, the second 0 to n-2, the third 0 to n-3 and so on, thru n-k.
Treat your random numbers as a set of swaps. The first random index swaps to the final position. The second random index swaps to the second to last position. However, instead of working against a backing array, work against your hashmap. Your hashmap will store every item that is out of position.
int getValue(i)
{
if (map.contains(i))
return map[i];
return i;
}
void setValue(i, val)
{
if (i == val)
map.remove(i);
else
map[i] = val;
}
int[] chooseK(int n, int k)
{
for (int i = 0; i < k; i++)
{
int randomIndex = nextRandom(0, n - i); //(n - i is exclusive)
int desiredIndex = n-i-1;
int valAtRandom = getValue(randomIndex);
int valAtDesired = getValue(desiredIndex);
setValue(desiredIndex, valAtRandom);
setValue(randomIndex, valAtDesired);
}
int[] output = new int[k];
for (int i = 0; i < k; i++)
{
output[i] = (getValue(n-i-1));
}
return output;
}
You could use one of the classes implementing the Set interface (API), and then each number you generate, use Set.add() to insert it.
If the return value is false, you know the number has already been generated before.
Instead of doing all this create a LinkedHashSet object and random numbers to it by Math.random() function .... if any duplicated entry occurs the LinkedHashSet object won't add that number to its List ... Since in this Collection Class no duplicate values are allowed .. in the end u get a list of random numbers having no duplicated values .... :D
With Java 8 upwards you can use the ints method from the IntStream interface:
Returns an effectively unlimited stream of pseudorandom int values.
Random r = new Random();
int randomNumberOrigin = 0;
int randomNumberBound = 10;
int size = 5;
int[] unique = r.ints(randomNumberOrigin, randomNumberBound)
.distinct()
.limit(size)
.toArray();
Following code create a sequence random number between [1,m] that was not generated before.
public class NewClass {
public List<Integer> keys = new ArrayList<Integer>();
public int rand(int m) {
int n = (int) (Math.random() * m + 1);
if (!keys.contains(n)) {
keys.add(n);
return n;
} else {
return rand(m);
}
}
public static void main(String[] args) {
int m = 4;
NewClass ne = new NewClass();
for (int i = 0; i < 4; i++) {
System.out.println(ne.rand(m));
}
System.out.println("list: " + ne.keys);
}
}
The most easy way is use nano DateTime as long format.
System.nanoTime();
There is algorithm of card batch: you create ordered array of numbers (the "card batch") and in every iteration you select a number at random position from it (removing the selected number from the "card batch" of course).
Here is an efficient solution for fast creation of a randomized array. After randomization you can simply pick the n-th element e of the array, increment n and return e. This solution has O(1) for getting a random number and O(n) for initialization, but as a tradeoff requires a good amount of memory if n gets large enough.
There is a more efficient and less cumbersome solution for integers than a Collections.shuffle.
The problem is the same as successively picking items from only the un-picked items in a set and setting them in order somewhere else. This is exactly like randomly dealing cards or drawing winning raffle tickets from a hat or bin.
This algorithm works for loading any array and achieving a random order at the end of the load. It also works for adding into a List collection (or any other indexed collection) and achieving a random sequence in the collection at the end of the adds.
It can be done with a single array, created once, or a numerically ordered collectio, such as a List, in place. For an array, the initial array size needs to be the exact size to contain all the intended values. If you don't know how many values might occur in advance, using a numerically orderred collection, such as an ArrayList or List, where the size is not immutable, will also work. It will work universally for an array of any size up to Integer.MAX_VALUE which is just over 2,000,000,000. List objects will have the same index limits. Your machine may run out of memory before you get to an array of that size. It may be more efficient to load an array typed to the object types and convert it to some collection, after loading the array. This is especially true if the target collection is not numerically indexed.
This algorithm, exactly as written, will create a very even distribution where there are no duplicates. One aspect that is VERY IMPORTANT is that it has to be possible for the insertion of the next item to occur up to the current size + 1. Thus, for the second item, it could be possible to store it in location 0 or location 1. For the 20th item, it could be possible to store it in any location, 0 through 19. It is just as possible the first item to stay in location 0 as it is for it to end up in any other location. It is just as possible for the next new item to go anywhere, including the next new location.
The randomness of the sequence will be as random as the randomness of the random number generator.
This algorithm can also be used to load reference types into random locations in an array. Since this works with an array, it can also work with collections. That means you don't have to create the collection and then shuffle it or have it ordered on whatever orders the objects being inserted. The collection need only have the ability to insert an item anywhere in the collection or append it.
// RandomSequence.java
import java.util.Random;
public class RandomSequence {
public static void main(String[] args) {
// create an array of the size and type for which
// you want a random sequence
int[] randomSequence = new int[20];
Random randomNumbers = new Random();
for (int i = 0; i < randomSequence.length; i++ ) {
if (i == 0) { // seed first entry in array with item 0
randomSequence[i] = 0;
} else { // for all other items...
// choose a random pointer to the segment of the
// array already containing items
int pointer = randomNumbers.nextInt(i + 1);
randomSequence[i] = randomSequence[pointer];
randomSequence[pointer] = i;
// note that if pointer & i are equal
// the new value will just go into location i and possibly stay there
// this is VERY IMPORTANT to ensure the sequence is really random
// and not biased
} // end if...else
} // end for
for (int number: randomSequence) {
System.out.printf("%2d ", number);
} // end for
} // end main
} // end class RandomSequence
It really all depends on exactly WHAT you need the random generation for, but here's my take.
First, create a standalone method for generating the random number.
Be sure to allow for limits.
public static int newRandom(int limit){
return generatedRandom.nextInt(limit); }
Next, you will want to create a very simple decision structure that compares values. This can be done in one of two ways. If you have a very limited amount of numbers to verify, a simple IF statement will suffice:
public static int testDuplicates(int int1, int int2, int int3, int int4, int int5){
boolean loopFlag = true;
while(loopFlag == true){
if(int1 == int2 || int1 == int3 || int1 == int4 || int1 == int5 || int1 == 0){
int1 = newRandom(75);
loopFlag = true; }
else{
loopFlag = false; }}
return int1; }
The above compares int1 to int2 through int5, as well as making sure that there are no zeroes in the randoms.
With these two methods in place, we can do the following:
num1 = newRandom(limit1);
num2 = newRandom(limit1);
num3 = newRandom(limit1);
num4 = newRandom(limit1);
num5 = newRandom(limit1);
Followed By:
num1 = testDuplicates(num1, num2, num3, num4, num5);
num2 = testDuplicates(num2, num1, num3, num4, num5);
num3 = testDuplicates(num3, num1, num2, num4, num5);
num4 = testDuplicates(num4, num1, num2, num3, num5);
num5 = testDuplicates(num5, num1, num2, num3, num5);
If you have a longer list to verify, then a more complex method will yield better results both in clarity of code and in processing resources.
Hope this helps. This site has helped me so much, I felt obliged to at least TRY to help as well.
I created a snippet that generates no duplicate random integer. the advantage of this snippet is that you can assign the list of an array to it and generate the random item, too.
No duplication random generator class
With Java 8 using the below code, you can create 10 distinct random Integer Numbers within a range of 1000.
Random random = new Random();
Integer[] input9 = IntStream.range(1, 10).map(i -> random.nextInt(1000)).boxed().distinct()
.toArray(Integer[]::new);
System.out.println(Arrays.toString(input9));
Modify the range to generate more numbers example : range(1,X). It will generate X distinct random numbers.
Modify the nextInt value to select the random number range : random.nextInt(Y)::random number will be generated within the range Y

Sum of two numbers equal to the given number

I have an array with positive integers in random order. A number x
from the list is given ,we need to find any two numbers in the list
having sum equal to x.Running time must be less than n^2.
{edit}
What I did is that , I put all the numbers less than half of x in one array and greater than half of x in another array and all greater than x are discarded and then the idea is that the required two numbers must from the two arrays (not from a single array) and by iterating I can get the two numbers.
Now for the worst case I am little confuse is that approach is good? or if anyone guide me something more better than this also can we achieve log n or n *log n ?
Your solution is both wrong, and in O(n^2).
It is wrong since consider x=5 and arr=[1,2,3,5] - the two numbers needed are from one array, not from both.
What if arr=[3,3,6], x=6, you will place both 3s in one list (not greater than x/2 for example), and will fail to find 3+3=6.
Your algorithm runs in O(n^2), because assume exactly half of the elements are greater than x1, and half are smaller than x. Then, the number of combinations you have to check are (n/2*n/2) /2 = n^2/8
To solve it in O(nlogn), think what happens if you sort the data, given a number arr[i], can you find efficiently if there is a number x-arr[i] in the now sorted array?
You can even enhance the above to O(n) average case by placing the elements in a hash-set, and now, given an number y, can you find efficiently if x-y is also in the set?
EDIT:
Stroked out parts are not relevant anymore since OP editted the question, added a new cause of concern instead.
(1) than x/2 in the editted question.
Here is O(n) solution for finding the first pair of indices of array which sums to the expected target. The solution will stop when it finds the first 2 indices that sum to target, if you need all the pairs that add up to target then instead of using int[] result, you can use ArrayList or even a Map, process the complete array and return it with all the pairs of indices. There is an obvious assumption that the Map's hashcode function is really good and there are not much collisions so that map operations perform in O(1) time.
import java.util.*;
public class Solution {
public static void main(String[] args) {
int[] array = new int[] {1,2,4,7,12,67,12,5,9,1,10};
System.out.println(Arrays.toString(sum(array, 68)));
}
public static int[] sum(int[] array, int target) {
int[] result = new int[2];
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
// n iterations
for (int index = 0; index < array.length; index++) {
// constant
if (map.containsKey(target - array[index])) {
result[1] = index;
// constant
result[0] = map.get(target - array[index]);
return result;
}
// constant
map.put(array[index], index);
}
return result;
}
}
Here you go,
Sort the array using merge sort (Time complexity: n logn). Take two pointers/counters, say i & j, one starts from index 0 and another from n-1 (assuming n size of array is n).
if array[i]+array[j]=sum
return;
else if (array[i]+array[j]<sum) i++;
else j--;
Do it until i>j.
Overall time complexity: n logn
/* Time Complexity = O(n)-since HashMap operations take O(1) time*/
public static ArrayList<Integer> twoSum(int[] arr , int target){
if (arr == null){
throw new IllegalArgumentException();
}
ArrayList<Integer> targetHolder = new ArrayList<>();
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0 ; i < arr.length ; i++){
if (map.containsKey(arr[i])){
int index = map.get(arr[i]);
targetHolder.add(index+1);
targetHolder.add(i+1);
}
else{
map.put(target-arr[i], i);
}
}
return targetHolder;
}
public static void main(String[] args) {
int[] A = {1,2,3,4,5,6};
System.out.println(twoSum(A, 6));
}
}
public void function(int[] array, int sum){
for(int i = 0; i < array.length/2; i ++){
for(int j = array.length-1;; j--){
if(array[i]+array[j] < sum) break;
if(array[i]+array[j] == sum) System.out.println(array[i]+" + "+array[j]+" = "+sum);
}
}
}

Categories