All numbers in a given range but random order - math

Let's say I want to generate all integers from 1-1000 in a random order. But...
No numbers are generated more then once
Without storing an Array, List... of all possible numbers
Without storing the already generated numbers.
Without missing any numbers in the end.
I think that should be impossible but maybe I'm just not thinking about the right solution.
I would like to use it in C# but I'm more interested in the approche then the actual implementation.

Encryption. An encryption is a one-to-one mapping between two sets. If the two sets are the same, then it is a permutation specified by the encryption key. Write/find an encryption that maps {0, 1000} onto itself. Read up on Format Preserving Encryption (FPE) to help you here.
To generate the random order just encrypt the numbers 0, 1, 2, ... in order. You don't need to store them, just keep track of how far you have got through the list.
From a practical point of view, numbers in {0, 1023} would be easier to deal with as that would be a block cipher with a 10 bit block size, and you could write a simple Feistel cipher to generate your numbers. You might want to do that anyway, and just re-encrypt numbers above 1000 -- the cycle walking method of FPE.

If randomness isn't a major concern, you could use a linear congruential generator. Since an LCG won't produce a maximal length sequences when the modulus is a prime number, you would need to choose a larger modulus (the next highest power of 2 would be an obvious choice) and skip any values outside the required range.
I'm afraid C# isn't really my thing, but hopefully the following Python is self-explanatory. It will need a bit of tweaking if you want to generate sequences over very small ranges:
# randint(a, b) returns a random integer in the range (a..b) (inclusive)
from random import randint
def lcg_params(u, v):
# Generate parameters for an LCG that produces a maximal length sequence
# of numbers in the range (u..v)
diff = v - u
if diff < 4:
raise ValueError("Sorry, range must be at least 4.")
m = 2 ** diff.bit_length() # Modulus
a = (randint(1, (m >> 2) - 1) * 4) + 1 # Random odd integer, (a-1) divisible by 4
c = randint(3, m) | 1 # Any odd integer will do
return (m, a, c, u, diff + 1)
def generate_pseudorandom_sequence(rmin, rmax):
(m, a, c, offset, seqlength) = lcg_params(rmin, rmax)
x = 1 # Start with a seed value of 1
result = [] # Create empty list for output values
for i in range(seqlength):
# To generate numbers on the fly without storing them in an array,
# just run the following while loop to fetch a new number
while True:
x = (x * a + c) % m # Iterate LCG until we get a value in the
if x < seqlength: break # required range
result.append(x + offset) # Add this value to the list
return result
Example:
>>> generate_pseudorandom_sequence(1, 20)
[4, 6, 8, 1, 10, 3, 12, 5, 14, 7, 16, 9, 18, 11, 20, 13, 15, 17, 19, 2]

Related

Counting Unique Paths in an Array with Special Rules

Description of the Problem:
I have an array of two-digit numbers going from 00 to 99. I must choose a number at random anywhere in the array; let's call this result r. I may now take up to n steps within the array to "travel" to another number in the array, according to the following rules:
Adding or subtracting 1 from r takes one (1) step; I cannot add 1 if there is a 9 in the ones place (ex: 09, 19, 29, ...) and I cannot subtract 1 if there is a 0 in the ones place (ex: 00, 10, 20, ...)
Adding or subtracting 10 from r takes one (1) step; I cannot bring the result to lower than 00 or higher than 99.
By taking two (2) steps, I can swap the digits in the ones and tens place (ex: 13 -> 31, 72 -> 27); however, I can't perform the swap if the digits are the same (ex: can't swap 00, 11, 22, ...)
For a given number x (00 <= x <= 99) I want to count the set of unique values of r from which I can travel to x, given that I can take between 0 and n steps. I call this count how "accessible" x is. I'd like to express this as a formula, A(x, n), rather than just brute-forcing the results for each combination of x and n.
What I Have Tried:
A(x, 0) is easy enough to calculate: A(x, 0) = 1 for all values in the array, because the only way to reach x from r is for r = x; I take zero (0) steps to reach it.
A(x, 1) is trickier, but still simple: you just take into account the new paths available if I spend my one step on either Rule #1 or Rule #2, and add them to A(x, 0). A(x, 2) is where I have to start including Rule #3, but also includes the problem of backtracking. For instance, if I want to reach x and x = r, and I have two (2) steps available, I could perform the following operation: Step 1, r -> r' = r+1 (Rule #1); Step 2, r' -> r'' = r'-1 (Rule #1); r'' = x AND r'' = r. This does not add to my count of unique values from which I can travel to x from.
Where I am Stuck:
I cannot figure out how to count the number of backtracking paths in order to remove them from the otherwise simple calculations of A(x, n), so my values of accessibility are coming out too high.

What is the most efficient way to find all pairs of numbers from a list of integers which add up to a separate given integer?

I had an interview yesterday and was asked to give a method to find all of the pairs of numbers from a list which add up to an integer which is given separate to the list. The list can be infinitely long, but for example:
numbers = [11,1,5,27,7,18,2,4,8]
sum = 9
pairs = [(1,8),(5,4),(7,2)]
I got as far as sorting the list and eliminating all numbers greater than the sum number and then doing two nested for loops to take each index and iterate through the other numbers to check whether they sum up to the given number, but was told that there was a more efficient way of doing it...
I've been trying to figure it out but have nothing, other than doing the nested iteration backwards but that only seems marginally more efficient.
Any ideas?
This can be done in O(n) time and O(n) auxiliary space; testing for membership of a set takes O(1) time. Since the output also takes up to O(n) space, the auxiliary space should not be a significant issue.
def pairs_sum(numbers, k):
numbers_set = set(numbers)
return [(x, y) for x in numbers if (y := k - x) in numbers_set and x < y]
Example:
>>> pairs_sum([11, 1, 5, 27, 7, 18, 2, 4, 8], 9)
[(1, 8), (2, 7), (4, 5)]
It is kind of a classic and not sure stackoverflow is the right place to ask that kind of question.
Sort the list is acsending order
Two iterators one starting from the end of the list descending i1, one starting from the beginning of the list ascending i2
Loop
while i1 > i2
if (list[i1] + list[i2] == target)
store {list[i1], list[i2]) in results pairs
i1--
i2++
else if (list[i1] + list[i2] > target)
i1--
else if (list[i1] + list[i2] < target)
i2++
This should be in O(n) with n the length of the list if you avoid the sorting algorithm which can be done with a quick sort on average in O(n log n)
Note: this algorithm doesn't take into account the case where the input list have several times the same number

Statistical probability of N contiguous true-bits in a sequence of bits?

Let's assume I have an N-bit stream of generated bits. (In my case 64kilobits.)
Whats the probability of finding a sequence of X "all true" bits, contained within a stream of N bits. Where X = (2 to 16), and N = (16 to 1000000), and X < N.
For example:
If N=16 and X=5, whats the likelyhood of finding 11111 within a 16-bit number.
Like this pseudo-code:
int N = 1<<16; // (64KB)
int X = 5;
int Count = 0;
for (int i = 0; i < N; i++) {
int ThisCount = ContiguousBitsDiscovered(i, X);
Count += ThisCount;
}
return Count;
That is, if we ran an integer in a loop from 0 to 64K-1... how many times would 11111 appear within those numbers.
Extra rule: 1111110000000000 doesn't count, because it has 6 true values in a row, not 5. So:
1111110000000000 = 0x // because its 6 contiguous true bits, not 5.
1111100000000000 = 1x
0111110000000000 = 1x
0011111000000000 = 1x
1111101111100000 = 2x
I'm trying to do some work involving physically-based random-number generation, and detecting "how random" the numbers are. Thats what this is for.
...
This would be easy to solve if N were less than 32 or so, I could just "run a loop" from 0 to 4GB, then count how many contiguous bits were detected once the loop was completed. Then I could store the number and use it later.
Considering that X ranges from 2 to 16, I'd literally only need to store 15 numbers, each less than 32 bits! (if N=32)!
BUT in my case N = 65,536. So I'd need to run a loop, for 2^65,536 iterations. Basically impossible :)
No way to "experimentally calculate the values for a given X, if N = 65,536". So I need maths, basically.
Fix X and N, obiously with X < N. You have 2^N possible values of combinations of 0 and 1 in your bit number, and you have N-X +1 possible sequences of 1*X (in this part I'm only looking for 1's together) contained in you bit number. Consider for example N = 5 and X = 2, this is a possible valid bit number 01011, so fixed the last two characteres (the last two 1's) you have 2^2 possible combinations for that 1*Xsequence. Then you have two cases:
Border case: Your 1*X is in the border, then you have (2^(N -X -1))*2 possible combinations
Inner case: You have (2^(N -X -2))*(N-X-1) possible combinations.
So, the probability is (border + inner )/2^N
Examples:
1)N = 3, X =2, then the proability is 2/2^3
2) N = 4, X = 2, then the probaility is 5/16
A bit brute force, but I'd do something like this to avoid getting mired in statistics theory:
Multiply the probabilities (1 bit = 0.5, 2 bits = 0.5*0.5, etc) while looping
Keep track of each X and when you have the product of X bits, flip it and continue
Start with small example (N = 5, X=1 - 5) to make sure you get edge cases right, compare to brute force approach.
This can probably be expressed as something like Sum (Sum 0.5^x (x = 1 -> 16) (for n = 1 - 65536) , but edge cases need to be taken into account (i.e. 7 bits doesn't fit, discard probability), which gives me a bit of a headache. :-)
#Andrex answer is plain wrong as it counts some combinations several times.
For example consider the case N=3, X=1. Then the combination 101 happens only 1/2^3 times but the border calculation counts it two times: one as the sequence starting with 10 and another time as the sequence ending with 01.
His calculations gives a (1+4)/8 probability whereas there are only 4 unique sequences that have at least a single contiguous 1 (as opposed to cases such as 011):
001
010
100
101
and so the probability is 4/8.
To count the number of unique sequences you need to account for sequences that can appear multiple times. As long as X is smaller than N/2 this will happens. Not sure how you can count them tho.

Return the ith number of the format x^y, where x and y are integers

x and y are integers greater than 1.
A Special number can be expressed as x^y.
Note that the special number sequence is in ascending order (4, 8, 9, 16, 25, 27, 32, ...).
Given an integer i, the program should return the ith special number.
i=0 -> num=4
i=4 -> num=25
Would like some insights. Faced this in a coding round for a company. Brute force ended up with TLEs.
Edit 1: Found a link: https://codegolf.stackexchange.com/questions/78985/find-the-n-th-perfect-power.
Edit-2: I shared the codegolf link to help check some of the solutions that are already available and are expected to exceed the time limit. I tried both with the Mathematica solution and the sage solution approach, faced TLE on both of them.
This problem is equivalent to finding an integer j where log_j k is an integer, and j is in a sequence with an upper bound k such that sum [floor(log_j k) - 1 | j <- [2..floor(sqrt k)] == i
We can make a rough estimate of where the ith element would be by binary search with a limited iteration. If we guess the number at m^2, the highest base that may be counted is:
m
Then we can examine lower bases and add up their log counts. For example, i = 10:
Guess: 10^2
Highest base: 10
Then at minimum we have (10 - 1) + (floor(log2 (10^2)) - 1)
= 15 elements. Too many.
Guess: 5^2
Highest base: 5
Minimum element count: (5 - 1) + (floor(log2 (5^2)) - 1) = 8
Iterate over logs:
-- Because of the exponential nature of the problem,
-- if the guess is too large, the bulk of the elements will appear
-- early in the iteration; and if it's too small, the limit on
-- exponents will drop early allowing for early exit in either case.
[floor(logBase x 25) - 1 | x <- [2..4]] = [3,1,1]
sum ([1] ++ [3,1,1]) = 6. Too few.
Guess: 7^2
Highest base: 7
Minimum element count: (7 - 1) + (floor(log2 (7^2)) - 1) = 10
Iterate over logs:
[floor(logBase x 49) - 1 | x <- [2..6]] = [4,2,1,1,1]
sum ([1] ++ [4,2,1,1,1]) = 10
Answer: 7^2

Generating two sets of numbers where the sum of each set and the sum of their dot product is N

In this question Getting N random numbers that the sum is M, the object was to generate a set of random numbers that sums to a specific number N. After reading this question, I started playing around with the idea of generating sets of numbers that satisfy this condition
sum(A) == sum(B) && sum(B) == sum(A * B)
An example of this would be
A <- c(5, 5, -10, 6, 6, -12)
B <- c(5, -5, 0, 6, -6, 0)
In this case, the three sums equal zero. Obviously, those sets aren't random, but they satisfy the condition. Is there a way to generate 'random' sets of data that satisfy the above condition? (As opposed to using a little algorithm as in the above example.)
(Note: I tagged this as an R question, but the language really doesn't matter to me.)
You'd need to define the first vector in n-dimensional space, and the 2nd one will have N-2 degrees of freedom (i.e. random numbers) since the sum and one angle are already determined.
The 2nd vector would need to be transformed into N-dimensional space; There are infinitely many transforms that could work, so if you don't care about the probability distribution of the resulting vectors, just choose the one that's most intuitive to you.
There's a nice geometrical interpretation to the first constraint: it constrains the 2nd vector to a (hyper-)plane in N-dimensional space; the 2nd constraint doesn't have a simple geometric interpretation.
check out hyperspherical cooridnates.
You can generate one set completely randomly. And generate randomly all numbers in set B except for two numbers. Since you have two equations you should be able to solve for those two numbers.

Resources