Riffling Cards in Mathematica - algorithm

My friend posed this question to me; felt like sharing it here.
Given a deck of cards, we split it into 2 groups, and "interleave them"; let us call this operation a 'split-join'. And repeat the same operation on the resulting deck.
E.g., { 1, 2, 3, 4 } becomes { 1, 2 } & { 3, 4 } (split) and we get { 1, 3, 2, 4 } (join)
Also, if we have an odd number of cards i.e., { 1, 2, 3 } we can split it like { 1, 2 } & { 3 } (bigger-half first) leading to { 1, 3, 2 }
(i.e., n is split up as Ceil[n/2] & n-Ceil[n/2])
The question my friend asked me was:
HOW many such split-joins are needed to get the original deck back?
And that got me wondering:
If the deck has n cards, what is the number of split-joins needed if:
n is even ?
n is odd ?
n is a power of '2' ? [I found that we then need log (n) (base 2) number of split-joins...]
(Feel free to explore different scenarios like that.)
Is there a simple pattern/formula/concept correlating n and the number of split-joins required?
I believe, this is a good thing to explore in Mathematica, especially, since it provides the Riffle[] method.

To quote MathWorld:
The numbers of out-shuffles needed to return a deck of n=2, 4, ... to its original order are 1, 2, 4, 3, 6, 10, 12, 4, 8, 18, 6, 11, ... (Sloane's A002326), which is simply the multiplicative order of 2 (mod n-1). For example, a deck of 52 cards therefore is returned to its original state after eight out-shuffles, since 2**8=1 (mod 51) (Golomb 1961). The smallest numbers of cards 2n that require 1, 2, 3, ... out-shuffles to return to the deck's original state are 1, 2, 4, 3, 16, 5, 64, 9, 37, 6, ... (Sloane's A114894).
The case when n is odd isn't addressed.
Note that the article also includes a Mathematica notebook with functions to explore out-shuffles.

If we have an odd number of cards n==2m-1, and if we split the cards such that during each shuffle the first group contains m cards, the second group m-1 cards, and the groups are joined such that no two cards of the same group end up next to each other, then the number of shuffles needed is equal to MultiplicativeOrder[2, n].
To show this, we note that after one shuffle the card which was at position k has moved to position 2k for 0<=k<m and to 2k-2m+1 for m<=k<2m-1, where k is such that 0<=k<2m-1. Written modulo n==2m-1 this means that the new position is Mod[2k, n] for all 0<=k<n. Therefore, for each card to return to its original position we need N shuffles where N is such that Mod[2^N k, n]==Mod[k, n] for all 0<=k<n from which is follows that N is any multiple of MultiplicativeOrder[2, n].
Note that due to symmetry the result would have been exactly the same if we had split the deck the other way around, i.e. the first group always contains m-1 cards and the second group m cards. I don't know what would happen if you alternate, i.e. for odd shuffles the first group contains m cards, and for even shuffles m-1 cards.

There's old work by magician/mathematician Persi Diaconnis about restoring the order with perfect riffle shuffles. Ian Stewart wrote about that work in one of his 1998 Scientific American Mathematical Recreation columns -- see, e.g.: http://www.whydomath.org/Reading_Room_Material/ian_stewart/shuffle/shuffle.html

old question I know, but strange no one put up an actual mathematica solution..
countrifflecards[deck_] := Module[{n = Length#deck, ct, rifdeck},
ct = 0;
rifdeck =
Riffle ##
Partition[ # , Ceiling[ n/2], Ceiling[ n/2], {1, 1}, {} ] &;
NestWhile[(++ct; rifdeck[#]) &, deck, #2 != deck &,2 ]; ct]
This handles even and odd cases:
countrifflecards[RandomSample[ Range[#], #]] & /# Range[2, 52, 2]
{1, 2, 4, 3, 6, 10, 12, 4, 8, 18, 6, 11, 20, 18, 28, 5, 10, 12, 36,
12, 20, 14, 12, 23, 21, 8}
countrifflecards[RandomSample[ Range[#], #]] & /# Range[3, 53, 2]
{2, 4, 3, 6, 10, 12, 4, 8, 18, 6, 11, 20, 18, 28, 5, 10, 12, 36, 12,
20, 14, 12, 23, 21, 8, 52}
You can readily show if you add a card to the odd-case the extra card will stay on the bottom and not change the sequence, hence the odd case result is just the n+1 even result..
ListPlot[{#, countrifflecards[RandomSample[ Range[#], #]]} & /#
Range[2, 1000]]

Related

Find the maximum number of points per game

The input is an array of cards. In one move, you can remove any group of consecutive identical cards. For removing k cards, you get k * k points. Find the maximum number of points you can get per game.
Time limit: O(n4)
Example:
Input: [1, 8, 7, 7, 7, 8, 4, 8, 1]
Output: 23
Does anyone have an idea how to solve this?
To clarify, in the given example, one path to the best solution is
Remove Points Total new hand
3 7s 9 9 [1, 8, 8, 4, 8, 1]
1 4 1 10 [1, 8, 8, 8, 1]
3 8s 9 19 [1, 1]
2 1s 4 23 []
Approach
Recursion would fit well here.
First, identify the contiguous sequences in the array -- one lemma of this problem is that if you decide to remove at least one 7, you want to remove the entire sequence of three. From here on, you'll work with both cards and quantities. For instance,
card = [1, 8, 7, 8, 4, 8, 1]
quant = [1, 1, 3, 1, 1, 1, 1]
Now you're ready for the actual solving. Iterate through the array. For each element, remove that element, and add the score for that move.
Check to see whether the elements on either side match; if so, merge those entries. Recur on the remaining array.
For instance, here's the first turn of what will prove to be the optimal solution for the given input:
Choose and remove the three 7's
card = [1, 8, 8, 4, 8, 1]
quant = [1, 1, 1, 1, 1, 1]
score = score + 3*3
Merge the adjacent 8 entries:
card = [1, 8, 4, 8, 1]
quant = [1, 2, 1, 1, 1]
Recur on this game.
Improvement
Use dynamic programming: memoize the solution for every sub game.
Any card that appears only once in the card array can be removed first, without loss of generality. In the given example, you can remove the 7's and the single 4 to improve the remaining search tree.

Computing number of sequences

I saw the following problem that I was unable to solve. What kind of algorithm will solve it?
We have been given a positive integer n. Let A be the set of all possible strings of length n where characters are from the set {1,2,3,4,5,6}, i.e. the results of dice thrown n times. How many elements of A contains at least one of the following strings as a substring:
1, 2, 3, 4, 5, 6
1, 1, 2, 2, 3, 3
4, 4, 5, 5, 6, 6
1, 1, 1, 2, 2, 2
3, 3, 3, 4, 4, 4
5, 5, 5, 6, 6, 6
1, 1, 1, 1, 1, 1
2, 2, 2, 2, 2, 2
3, 3, 3, 3, 3, 3
4, 4, 4, 4, 4, 4
5, 5, 5, 5, 5, 5
6, 6, 6, 6, 6, 6
I was wondering some kind of recursive approach but I got only mess when I tried to solve the problem.
I suggest reading up on the Aho-Corasick algorithm. This constructs a finite state machine based on a set of strings. (If your list of strings is fixed, you could even do this by hand.)
Once you have a finite state machine (with around 70 states), you should add an extra absorbing state to mark when any of the strings has been detected.
Now you problem is reduced to finding how many of the 6**n strings end up in the absorbing state after being pushed through the state machine.
You can do this by expressing the state machine as a matrix . Entry M[i,j] tells the number of ways of getting to state i from state j when one letter is added.
Finally you compute the matrix raised to the power n applied to an input vector that is all zeros except for a 1 in the position corresponding to the initial state. The number in the absorbing state position will tell you the total number of strings.
(You can use the standard matrix exponentiation algorithm to generate this answer in O(logn) time.)
What's wrong with your recursive approach, can you elaborate on that, anyway this can be solved using a recursive approach in O(6^n), but can be optimized using dp, using the fact that you only need to track the last 6 elements, so it can be done in O ( 6 * 2^6 * n) with dp.
rec (String cur, int step) {
if(step == n) return 0;
int ans = 0;
for(char c in { '1', '2', '3', '4', '5', '6' } {
if(cur.length < 6) cur += c
else {
shift(cur,1) // shift the string to the left by 1 step
cur[5] = c // add the new element to the end of the string
}
if(cur in list) ans += 1 + rec(cur, step+1) // list described in the question
else ans += rec(cur, step+1)
}
return ans;
}

How to Generate N random numbers from a SHA-256 Hash

I'm working on a "provably fair" site where let's say X participants enter into a drawing and we need to pick first 1 overall winner, but then ideally we also want to pick N sub-winners out of the X total.
(for the curious, the SHA-256 Hash will be the merkle tree root of a Bitcoin block at a pre-specified time)
So, given a SHA-256 hash, how do we generate N random numbers?
I think I know how to generate 1 random number (within ruby's Fixnum range). According to this article: http://patshaughnessy.net/2014/1/9/how-big-is-a-bignum
The maximum Fixnum integer is: 4611686018427387903
Let's pluck the first Y characters of the SHA-256 hash. We can generate one instead of relying on a Bitcoin merkle root with:
d = Digest::SHA256.hexdigest('hello')
> "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
Let's take the first 6 characters, or: 2cf24d
Convert this to base 10:
'2cf24d'.to_i(16)
> 2945613
We now have a unique Fixnum based on our merkle root.
With X participants, let's say 17, we decide the winner with:
2945613 % 17
> 6
So assuming all entries know their order of entry, the sixth entrant can prove that they should be the winner.
Now -- what would be the best way to similarly pick N sub-winners? Let's say each of these entrants should get a smaller but still somewhat valuable prize.
Why not just use the hash for the seed?
[*1..17].shuffle(random: Random.new(0x2cf24d))
# => [15, 5, 9, 7, 14, 3, 16, 12, 2, 1, 17, 4, 6, 13, 11, 10, 8]
[*1..17].shuffle(random: Random.new(0x2cf24d))
# => [15, 5, 9, 7, 14, 3, 16, 12, 2, 1, 17, 4, 6, 13, 11, 10, 8]
EDIT: This is dependent on Ruby version though - I believe shuffle is different between JRuby and MRI, even though Random produces the same sequence. You could circumvent this by implementing shuffle yourself. See this question for more details. This workaround works consistently for me in both JRuby and MRI:
r = Random.new(0x2cf24d)
[*1..17].sort_by { r.rand }
# => [14, 11, 4, 10, 1, 3, 9, 13, 16, 17, 12, 5, 8, 2, 6, 7, 15]
r = Random.new(0x2cf24d)
[*1..17].sort_by { r.rand }
# => [14, 11, 4, 10, 1, 3, 9, 13, 16, 17, 12, 5, 8, 2, 6, 7, 15]

Need to understand answer of algorithm

I am trying to solve above Longest Monotonically Increasing Subsequence problem using javascript. In order to do that, I need to know about Longest Monotonically Subsequence. Current I am following wikipedia article. The thing I am not understanding this example is that the longest increasing subsequence is given as 0, 2, 6, 9, 13, 15 from 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15, … list. The question is Why the answer does not have 3 in between 2 and 6, and 8 between 6 and 9 etc? How does that answer come from that list?
Ist of all , consider the name "Longest Monotonically Increasing Subsequence" . So , from the given array you need to figure out the largest sequence where the numbers should be appeared in a strictly increasing fashion. There can be many sequence, where the sub array can be strictly increasing but you need to find the largest sub-Array.
So. lets debug this array. a[] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}
In here the some monotonously increasing sub-arrays are :
{0,8,12,14,15} Length = 5
{0,4,12,14,15} Length = 5
{0,1,9,13,15} Length = 5 and so on.
But if you calculate like this , you can find the largest sub-array will be :
{0, 2, 6, 9, 13, 15} , Length = 6, so this is the answer.
Every single little time you pick any number , the next number should be large than the previous one and must be present in the array. say {0, 2, 6, 9, 13, 15} this list, when you pick 9 , then the next number should be larger than 9. the immediate sequence shows 13>9, so you can pick 13. You can also pick 11. But that will create another branch of sub-array. Like :
{0, 2, 6, 9, 11, 15} which is another solution.
Hope this explanation will help you to understand the LIS (Longest Increasing Subsequence).Thanks.
First of all, the title of your question says: Longest increasing CONTIGUOUS subsequence which is a slight variation of the original problem of LIS in which the result need not have contiguous values from original array as pointed out in above examples. Follow this link for a decent explanation on LIS algorithm which has O(n^2) solution and it can be optimized to have a O(nlogn) solution:
http://www.algorithmist.com/index.php/Longest_Increasing_Subsequence
for the contiguous variant of LIS, here is a decent solution:
http://worldofbrock.blogspot.com/2009/10/how-to-find-longest-continuous.html

Is this equivalent to insertion sort?

Say we have a 0-indexed sequence S, take S[0] and insert it in a place in S where the next value is higher than S[0] and the previous value is lower than S[0]. Formally, S[i] should be placed in such a place where S[i-1] < S[i] < S[i+1]. Continue in order on the list doing the same with every item. Remove the element from the list before putting it in the correct place. After one iteration over the list the list should be ordered. I recently had an exam and I forgot insertion sort (don't laugh) and I did it like this. However, my professor marked it wrong. The algorithm, as far as I know, does produce a sorted list.
Works like this on a list:
Sorting [2, 8, 5, 4, 7, 0, 6, 1, 10, 3, 9]
[2, 8, 5, 4, 7, 0, 6, 1, 10, 3, 9]
[2, 8, 5, 4, 7, 0, 6, 1, 10, 3, 9]
[2, 5, 4, 7, 0, 6, 1, 8, 10, 3, 9]
[2, 4, 5, 7, 0, 6, 1, 8, 10, 3, 9]
[2, 4, 5, 7, 0, 6, 1, 8, 10, 3, 9]
[2, 4, 5, 0, 6, 1, 7, 8, 10, 3, 9]
[0, 2, 4, 5, 6, 1, 7, 8, 10, 3, 9]
[0, 2, 4, 5, 1, 6, 7, 8, 10, 3, 9]
[0, 1, 2, 4, 5, 6, 7, 8, 10, 3, 9]
[0, 1, 2, 4, 5, 6, 7, 8, 3, 9, 10]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Got [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Since every time an element is inserted into the list up to (n-1) numbers in the list may be moved and we must do this n times the algorithm should run in O(n^2) time.
I had a Python implementation but I misplaced it somehow. I'll try to write it again in a bit, but it's kinda tricky to implement. Any ideas?
The Python implementation is here: http://dpaste.com/hold/522232/. It was written by busy_beaver from reddit.com when it was discussed here http://www.reddit.com/r/compsci/comments/ejaaz/is_this_equivalent_to_insertion_sort/
It's a while since this was asked, but none of the other answers contains a proof that this bizarre algorithm does in fact sort the list. So here goes.
Suppose that the original list is v1, v2, ..., vn. Then after i steps of the algorithm, I claim that the list looks like this:
w1,1, w1,2, ..., w1,r(1), vσ(1), w2,1, ... w2,r(2), vσ(2), w3,1 ... ... wi,r(i), vσ(i), ...
Where σ is the sorted permutation of v1 to vi and the w are elements vj with j > i. In other words, v1 to vi are found in sorted order, possibly interleaved with other elements. And moreover, wj,k ≤ vj for every j and k. So each of the correctly sorted elements is preceded by a (possibly empty) block of elements less than or equal to it.
Here's a run of the algorithm, with the sorted elements in bold, and the preceding blocks of elements in italics (where non-empty). You can see that each block of italicised elements is less than the bold element that follows it.
[4, 8, 6, 1, 2, 7, 5, 0, 3, 9]
[4, 8, 6, 1, 2, 7, 5, 0, 3, 9]
[4, 6, 1, 2, 7, 5, 0, 3, 8, 9]
[4, 1, 2, 6, 7, 5, 0, 3, 8, 9]
[1, 4, 2, 6, 7, 5, 0, 3, 8, 9]
[1, 2, 4, 6, 7, 5, 0, 3, 8, 9]
[1, 2, 4, 6, 5, 0, 3, 7, 8, 9]
[1, 2, 4, 5, 6, 0, 3, 7, 8, 9]
[0, 1, 2, 4, 5, 6, 3, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
If my claim is true, then the algorithm sorts, because after n steps all the vi are in order, and there are no remaining elements to be interleaved. But is the claim really true?
Well, let's prove it by induction. It's certainly true when i = 0. Suppose it's true for i. Then when we run the (i + 1)st step, we pick vi+1 and move it into the first position where it fits. It certainly passes over all vj with j ≤ i and vj < vi+1 (since these are sorted by hypothesis, and each is preceded only by smaller-or-equal elements). It cannot pass over any vj with j ≤ i and vj ≥ vi+1, because there's some position in the block before vj where it will fit. So vi+1 ends up sorted with respect to all vj with j ≤ i. So it ends up somewhere in the block of elements before the next vj, and since it ends up in the first such position, the condition on the blocks is preserved. QED.
However, I don't blame your professor for marking it wrong. If you're going to invent an algorithm that no-one's seen before, it's up to you to prove it correct!
(The algorithm needs a name, so I propose fitsort, because we put each element in the first place where it fits.)
Your algorithm seems to me very different from insertion sort. In particular, it's very easy to prove that insertion sort works correctly (at each stage, the first however-many elements in the array are correctly sorted; proof by induction; done), whereas for your algorithm it seems much more difficult to prove this and it's not obvious exactly what partially-sorted-ness property it guarantees at any given point in its processing.
Similarly, it's very easy to prove that insertion sort always does at most n steps (where by a "step" I mean putting one element in the right place), whereas if I've understood your algorithm correctly it doesn't advance the which-element-to-process-next pointer if it's just moved an element to the right (or, to put it differently, it may sometimes have to process an element more than once) so it's not so clear that your algorithm really does take O(n^2) time in the worst case.
Insertion sort maintains the invariant that elements to the left of the current pointer are sorted. Progress is made by moving the element at the pointer to the left into its correct place and advancing the pointer.
Your algorithm does this, but sometimes it also does an additional step of moving the element at the pointer to the right without advancing the pointer. This makes the algorithm as a whole not an insertion sort, though you could call it a modified insertion sort due to the resemblance.
This algorithm runs in O(n²) on average like insertion sort (also like bubble sort). The best case for an insertion sort is O(n) on an already sorted list, for this algorithm it is O(n) but for a reverse-sorted list since you find the correct position for every element in a single comparison (but only if you leave the first, largest, element in place at the beginning when you can't find a good position for it).
A lot of professors are notorious for having the "that's not the answer I'm looking for" bug. Even if it's correct, they'll say it doesn't meet their criteria.
What you're doing seems like insertion sort, although using removes and inserts seems like it would only add unnecessary complexity.
What he might be saying is you're essentially "pulling out" the value and "dropping it back in" the correct spot. Your prof was probably looking for "swapping the value up (or down) until you found it's correct location."
They have the same result but they're different in implementation. Swapping would be faster, but not significantly so.
I have a hard time seeing that this is insert sort. Using insert sort, at each iteration, one more element would be placed correctly in the array. In your solution I do not see an element being "fully sorted" upon each iteration.
The insert sort algorithm begin:
let pos = 0
if pos == arraysize then return
find the smallest element in the remaining array from pos and swap it with the element at position pos
pos++
goto 2

Resources