Fast lightweight method of detecting skipped values in a cyclic sequence - algorithm

I have a single value that, over time, increases from 1 to 6 and then returns to 1. So over several frames the sequence seen would be:
1, 2, 3, 4, 5, 6, 1, 2, 3, 4...
If a hardware device is defective one of those numbers may not read correctly and so the sequence may look like this:
1, 2, 6, 4, 5, 6, 1, 2, 6, 4...
What is a fast, short method of detecting this inconsistency?
Note:
This is designed for a hard real-time environment
My current method is to check that each new value every frame has a difference no greater than 1 from the last value, then there is a special case for the difference between 1 and 6 which is allowed to be 5
I am wondering whether there is a simple algorithm or trick to solving this problem
The sequence is also valid if it is in reverse, e.g.:
6, 5, 4, 3, 2, 1, 6, 5, 4, 3....

You can use the modulo operator:
(current_value - previous_value + 6) mod 6 == 1
The +6 is there to ensure a positive argument to mod. Different languages treat negative values differently, but if -5 mod 6 evaluates to 1 in yours, you can omit the +6.

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 do I add a random offset to values in a Pseq?

Given a Pseq similar to the following:
Pseq([1, 2, 3, 4, 5, 6, 7, 8], inf)
How would I randomise the values slightly each time? That is, not just randomly alter the 8 values once at initialisation time, but have a random offset added each time a value is sent to the stream?
Here's a neat way:
(Pseq([1, 2, 3, 4, 5, 6, 7, 8], inf) + Pgauss(0, 0.1))
First you need to know that Pgauss is just a pattern that generates gaussian random numbers. You can use any other kind of pattern such as Pwhite.
Then you need to know the really pleasant bit: performing basic math operations on Patterns (as above) composes the patterns (by wrapping them in Pbinop).

Combinatorial algorithm for assigning people to groups

A coworker came to me with an interesting problem, a practical one having to do with a "new people in town" group she's a part of.
18 friends want to have dinner in groups for each of the next 4 days. The rules are as follows:
Each day the group will split into 4 groups of 4, and a group of 2.
Any given pair of people will only see each other at most once over the course of the 4 days.
Any given person will only be part of the size 2 group at most once.
A brute force recursive search for a valid set of group assignment is obviously impractical. I've thrown in some simple logic for pruning parts of the tree as soon as possible, but not enough to make it practical.
Actually, I'm starting to suspect that it might be impossible to follow all the rules, but I can't come up with a combinatorial argument for why that would be.
Any thoughts?
16 friends can be scheduled 4x4 for 4 nights using two mutually orthogonal latin squares of order 4. Assign each friend to a distinct position in the 4x4 grid. On the first night, group by row. On the second, group by column. On the third, group by similar entry in latin square #1 (card rank in the 4x4 example). On the fourth, group by similar entry in latin square #2 (card suit in the 4x4 example). Actually, the affine plane construction gives rise to three mutually orthogonal latin squares, so a fifth night could be scheduled, ensuring that each pair of friends meets exactly once.
Perhaps the schedule for 16 could be extended, using the freedom of the unused fifth night.
EDIT: here's the schedule for 16 people over 5 nights. Each row is a night. Each column is a person. The entry is the group to which they're assigned.
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
[0, 1, 2, 3, 1, 0, 3, 2, 2, 3, 0, 1, 3, 2, 1, 0]
[0, 2, 3, 1, 1, 3, 2, 0, 2, 0, 1, 3, 3, 1, 0, 2]
[0, 3, 1, 2, 1, 2, 0, 3, 2, 1, 3, 0, 3, 0, 2, 1]

Diff two sequences of identifier

Given two sequences of identifier, how to find the smallest operation sequence that will transform the first sequence of identifier to the second one.
Operation can be :
Insert an identifier at a given position
Remove the identifier from a given position
Move an identifier from a position to another
Note: identifiers are unique and can't appear twice in a sequence
Example:
Sequence1 [1, 2, 3, 4, 5]
Sequence2 [5, 1, 2, 9, 3, 7]
Result (index are 0 based) :
- Remove at 3
- Move from 3 to 0
- Insert '9' at 3
- Insert '7' at 5
Thanks !
Start by finding the longest common subsequence. This will identify the elements that will not move:
[(1), (2), (3), 4, 5]
Elements of the LCS are enclosed in parentheses.
Go through both sequences from index 0, recording the operations required to make the sequences identical. If the current item of the first sequence is not part of the LCS, remove it, and mark the place where it has been before, in case you need to insert it at a later time. If the current element is part of the LCS, insert the element from the second sequence in front of it. This could be either a simple insertion, or a move. If the item that you are inserting is in the original list, make it a move; otherwise, make it an insert.
Here is a demo using your example. Curly braces show the current element
[{(1)}, (2), (3), 4, 5] vs [{5}, 1, 2, 9, 3, 7]
1 is a member of LCS, so we must insert 5. 5 is in the original sequence, so we record a move: MOVE 4 to 0
[5, {(1)}, (2), (3), 4] vs [5, {1}, 2, 9, 3, 7]
Items are the same, so we move on to the next one:
[5, (1), {(2)}, (3), 4] vs [5, 1, {2}, 9, 3, 7]
Again the numbers are the same - move to the next one:
[5, (1), (2), {(3)}, 4] vs [5, 1, 2, {9}, 3, 7]
3 is a member of LCS, so we must insert 9. The original element does not have 9, so it's a simple insertion: INSERT 9 at 3
[5, (1), (2), 9, {(3)}, 4] vs [5, 1, 2, 9, {3}, 7]
Yet again the numbers are the same - move to the next one:
[5, (1), (2), 9, (3), {4}] vs [5, 1, 2, 9, 3, {7}]
'4' is not a member of LCS, so it gets deleted: DEL at 5
[5, (1), (2), 9, (3)] vs [5, 1, 2, 9, 3, {7}]
We reached the end of the first sequence - we simply add the remaining items of the second sequence to the first one, paying attention to the list of prior deletions. For example, if 7 had been removed earlier, we would transform that deletion into a move at this time. But since the original list did not have 7, we record our final operation: INS 7 at 5.
This metric is called Levenshtein distance or more precisely Damerau–Levenshtein distance.
There are implementations for almost every possible programming language, that you can use resolve the problem you described.

Resources