1

Intro: This is an interview question I had which I couldn't solve. A code solution will be good (in any language), but an algorithm/pseudocode is also great.


The problem: This problem is about designing an algorithm that solves the following problem:
You are given a function int getRand(int x) that gets an int x and returns an int in the range from 0 to x randomly (exclusively -> [0, k) ). Each call to getRand() is performed in O(1) time. You are also given an array int[] arr of size k containing integers.

Write a function getRandUnique() that when called will return a random member from arr such that after k requests exactly you will have a full permutation of the members of arr (this actually means that getRandUnique() will return a different member of arr for each call). Each call to getRandUnique() has to be performed in O(1) time.
You are allowed to use/store global variables etc...

E.g.: Assume arr = [2, 3, 5 , 1]. A call to getRandUnique() will return either 2, 3, 5, 1 in 1/4 probability. A consequent call to getRandUnique() will return on of the remaining 3 members in 1/3 probability and so on...


Attempt: I actually solved this myself (after much trial and error) and posted the solution "Q&A Style". I would love to get some other possible ideas/solutions. I will accept any solution that works as the correct answer (I don't want to accept my own)!


Question: How can this be achieved with all the above restrictions?

Edit: Now I am aware that this problem corresponds to the Fisher–Yates shuffle, even though the specifications are a little different/more strict here.

Community
  • 1
  • 1
Idos
  • 15,053
  • 14
  • 60
  • 75
  • are pre-computations allowed? eg a-priori shuffle, then get sequentially with O(1)? – Kostas Kryptos Feb 06 '16 at 15:32
  • Everything is allowed as long as "everything" isn't more than O(1) (because that would defeat the purpose I guess) – Idos Feb 06 '16 at 15:33
  • People reporting this question as off-topic "why isn't this code working?", what exactly is the problem? This is a classic Q&A question and is completely on-topic on SO. – Idos Feb 06 '16 at 15:57
  • @Tunaki It would seem to be, once you associate "permutation" with "shuffle". But there are already 3 close votes as "off-topic" because, I assume, the pseudocode was included in an answer rather than in the question, and I don't wish to further their cause. Perhaps someone with a gold badge could mark it as a dup. :) – beaker Feb 06 '16 at 15:58
  • @beaker The pseudocode is in the answer *by design* as this is a Q&A question, hence not off-topic. Dup? maybe, not so clear because it is phrased extremely differently. I would let a mod decide – Idos Feb 06 '16 at 16:01
  • @Idos Oh, sorry I thought it was you who answered to me in the previous comments... Do you disagree with the dupe target? It seems like the answer is the same. – Tunaki Feb 06 '16 at 16:02
  • @Idos I agree with you. :) My suggestion was to keep this post around as a dup of the shuffle post rather than let it get closed as off-topic. – beaker Feb 06 '16 at 16:03
  • @Tunaki I don't believe it to be an exact duplicate because of the specific instructions. But I prefer not to cause a hassle/scene. So if you believe it's a dup then go ahead it's cool by me – Idos Feb 06 '16 at 16:03

1 Answers1

2

My solution is as follows:

  • Define index = 0.

  • Call and assign index = getRand(k) (remember that k is the size of arr).

  • Swap arr[index] with arr[k].

  • Now call and assign index = getRand(k-1). Now you can be certain that you won't get the index k again so you won't have to remove it.
  • Swap arr[index] with arr[k-1]
  • Continue doing this until you call the last getRand(1).

Now you have an array arr that is a random permutation of itself as requested (don't even need an additional array).

Idos
  • 15,053
  • 14
  • 60
  • 75
  • 3
    You appear to have rediscovered the [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher–Yates_shuffle). – beaker Feb 06 '16 at 15:31
  • 1
    That's the right solution, but just a point on nomenclature: "Remove" generally implies a O(N) solution (basically moving everything after one forward) which is not what you want here (and which I'm sure you didn't have in mind). "Swap" is more appropriate – Voo Feb 06 '16 at 15:31
  • Hahaha nice catch! Apparently I reinvented the wheel.. Voo you're right, I will correct myself – Idos Feb 06 '16 at 15:32
  • Note that this assumes you are allowed to modify "arr". If not, it becomes more interesting.. In that case if allocation of O(n) memory is considered O(1) then it is still solvable, otherwise it is not. – CaptainCodeman Feb 07 '16 at 16:27