Pseudocode to find the longest run within an array - pseudocode

I know that A run is a sequence of adjacent repeated values , How would you write pseudo code for computing the length of the longest run in an array e.g.
5 would be the longest run in this array of integers.
1 2 4 4 3 1 2 4 3 5 5 5 5 3 6 5 5 6 3 1
Any idea would be helpful.

def longest_run(array):
result = None
prev = None
size = 0
max_size = 0
for element in array:
if (element == prev):
size += 1
if size > max_size:
result = element
max_size = size
else:
size = 0
prev = element
return result
EDIT
Wow. Just wow! This pseudocode is actually working:
>>> longest_run([1,2,4,4,3,1,2,4,3,5,5,5,5,3,6,5,5,6,3,1])
5

max_run_length = 0;
current_run_length = 0;
loop through the array storing the current index value, and the previous index's value
if the value is the same as the previous one, current_run_length++;
otherwise {
if current_run_length > max_run_length : max_run_length = current_run_length
current_run_length = 1;
}

Here a different functional approach in Python (Python looks like Pseudocode). This code works only with Python 3.3+. Otherwise you must replace "return" with "raise StopIteration".
I'm using a generator to yield a tuple with quantity of the element and the element itself. It's more universal. You can use this also for infinite sequences. If you want to get the longest repeated element from the sequence, it must be a finite sequence.
def group_same(iterable):
iterator = iter(iterable)
last = next(iterator)
counter = 1
while True:
try:
element = next(iterator)
if element is last:
counter += 1
continue
else:
yield (counter, last)
counter = 1
last = element
except StopIteration:
yield (counter, last)
return
If you have a list like this:
li = [0, 0, 2, 1, 1, 1, 1, 1, 5, 5, 6, 7, 7, 7, 12, 'Text', 'Text', 'Text2']
Then you can make a new list of it:
list(group_same(li))
Then you'll get a new list:
[(2, 0),
(1, 2),
(5, 1),
(2, 5),
(1, 6),
(3, 7),
(1, 12),
(2, 'Text'),
(1, 'Text2')]
To get longest repeated element, you can use the max function.
gen = group_same(li) # Generator, does nothing until iterating over it
grouped_elements = list(gen) # iterate over the generator until it's exhausted
longest = max(grouped_elements, key=lambda x: x[0])
Or as a one liner:
max(list(group_same(li)), key=lambda x: x[0])
The function max gives us the biggest element in a list. In this case, the list has more than one element. The argument key is just used to get the first element of the tuple as max value, but you'll still get back the tuple.
In : max(list(group_same(li)), key=lambda x: x[0])
Out: (5, 1)
The element 1 occurred 5 times repeatedly.

int main()
{
int a[20] = {1, 2, 4, 4, 3, 1, 2, 4, 3, 5, 5, 5, 5, 3, 6, 5, 5, 6, 3, 1};
int c=0;
for (int i=0;i<19;i++)
{
if (a[i] == a[i+1])
{
if (i != (i+1))
{
c++;
}
}
}
cout << c-1;
return 0;
}

Related

Detect outlier in repeating sequence

I have a repeating sequence of say 0~9 (but may start and stop at any of these numbers). e.g.:
3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2
And it has outliers at random location, including 1st and last one, e.g.:
9,4,5,6,7,8,9,0,1,2,3,4,8,6,7,0,9,0,1,2,3,4,1,6,7,8,9,0,1,6
I need to find & correct the outliers, in the above example, I need correct the first "9" into "3", and "8" into "5", etc..
What I came up with is to construct a sequence with no outlier of desired length, but since I don't know which number the sequence starts with, I'd have to construct 10 sequences each starting from "0", "1", "2" ... "9". And then I can compare these 10 sequences with the given sequence and find the one sequence that match the given sequence the most. However this is very inefficient when the repeating pattern gets large (say if the repeating pattern is 0~99, I'd need to create 100 sequences to compare).
Assuming there won't be consecutive outliers, is there a way to find & correct these outliers efficiently?
edit: added some explanation and added the algorithm tag. Hopefully it is more appropriate now.
I'm going to propose a variation of #trincot's fine answer. Like that one, it doesn't care how many outliers there may be in a row, but unlike that one doesn't care either about how many in a row aren't outliers.
The base idea is just to let each sequence element "vote" on what the first sequence element "should be". Whichever gets the most votes wins. By construction, this maximizes the number of elements left unchanged: after the 1-liner loop ends, votes[i] is the number of elements left unchanged if i is picked as the starting point.
def correct(numbers, mod=None):
# this part copied from #trincot's program
if mod is None: # if argument is not provided:
# Make a guess what the range is of the values
mod = max(numbers) + 1
votes = [0] * mod
for i, x in enumerate(numbers):
# which initial number would make x correct?
votes[(x - i) % mod] += 1
winning_count = max(votes)
winning_numbers = [i for i, v in enumerate(votes)
if v == winning_count]
if len(winning_numbers) > 1:
raise ValueError("ambiguous!", winning_numbers)
winning_number = winning_numbers[0]
for i in range(len(numbers)):
numbers[i] = (winning_number + i) % mod
return numbers
Then, e.g.,
>>> correct([9,4,5,6,7,8,9,0,1,2,3,4,8,6,7,0,9,0,1,2,3,4,1,6,7,8,9,0,1,6])
[3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]
but
>>> correct([1, 5, 3, 7, 5, 9])
...
ValueError: ('ambiguous!', [1, 4])
That is, it's impossible to guess whether you want [1, 2, 3, 4, 5, 6] or [4, 5, 6, 7, 8, 9]. They both have 3 numbers "right", and despite that there are never two adjacent outliers in either case.
I would do a first scan of the list to find the longest sublist in the input that maintains the right order. We will then assume that those values are all correct, and calculate backwards what the first value would have to be to produce those values in that sublist.
Here is how that would look in Python:
def correct(numbers, mod=None):
if mod is None: # if argument is not provided:
# Make a guess what the range is of the values
mod = max(numbers) + 1
# Find the longest slice in the list that maintains order
start = 0
longeststart = 0
longest = 1
expected = -1
for last in range(len(numbers)):
if numbers[last] != expected:
start = last
elif last - start >= longest:
longest = last - start + 1
longeststart = start
expected = (numbers[last] + 1) % mod
# Get from that longest slice what the starting value should be
val = (numbers[longeststart] - longeststart) % mod
# Repopulate the list starting from that value
for i in range(len(numbers)):
numbers[i] = val
val = (val + 1) % mod
# demo use
numbers = [9,4,5,6,7,8,9,0,1,2,3,4,8,6,7,0,9,0,1,2,3,4,1,6,7,8,9,0,1,6]
correct(numbers, 10) # for 0..9 provide 10 as argument, ...etc
print(numbers)
The advantage of this method is that it would even give a good result if there were errors with two consecutive values, provided that there are enough correct values in the list of course.
Still this runs in linear time.
Here is another way using groupby and count from Python's itertools module:
from itertools import count, groupby
def correct(lst):
groupped = [list(v) for _, v in groupby(lst, lambda a, b=count(): a - next(b))]
# Check if all groups are singletons
if all(len(k) == 1 for k in groupped):
raise ValueError('All groups are singletons!')
for k, v in zip(groupped, groupped[1:]):
if len(k) < 2:
out = v[0] - 1
if out >= 0:
yield out
else:
yield from k
else:
yield from k
# check last element of the groupped list
if len(v) < 2:
yield k[-1] + 1
else:
yield from v
lst = "9,4,5,6,7,8,9,0,1,2,3,4,8,6,7,0,9,0,1,2,3,4,1,6,7,8,9,0,1,6"
lst = [int(k) for k in lst.split(',')]
out = list(correct(lst))
print(out)
Output:
[3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]
Edit:
For the case of [1, 5, 3, 7, 5, 9] this solution will return something not accurate, because i can't see which value you want to modify. This is why the best solution is to check & raise a ValueError if all groups are singletons.
Like this?
numbers = [9,4,5,6,7,8,9,0,1,2,3,4,8,6,7,0,9,0,1,2,3,4,1,6,7,8,9,0,1,6]
i = 0
for n in numbers[:-1]:
i += 1
if n > numbers[i] and n > 0:
numbers[i-1] = numbers[i]-1
elif n > numbers[i] and n == 0:
numbers[i - 1] = 9
n = numbers[-1]
if n > numbers[0] and n > 0:
numbers[-1] = numbers[0] - 1
elif n > numbers[0] and n == 0:
numbers[-1] = 9
print(numbers)

Length of maximum continuous subarray with 2 unique numbers

I have an array of numbers and I want to figure out the maximum length of a continuous subarray of 2 unique numbers repeating.
For example, [2, 3, 4, 3, 2, 2, 4] would return 3 since [3, 2, 2] is of length 3.
[2, 4, 2, 5, 1, 5, 4, 2] would return 3.
[7, 8, 7, 8, 7] would return 5.
Edit: I have considered an O(n^2) solution where I start at each value in the array and iterate until I see a third unique value.
for item in array:
iterate until third unique element
if length of this iteration is greater than existing max, update the max length
return maxlength
I do not, however, think this is an efficient solution.
It can be done O(n). The code is in python3. o and t are one and two respectively. m is the max and c is the current count variable.
a = [7, 8, 7, 8, 7]
m = -1
o = a[0]
t = a[1]
# in the beginning one and two are the first 2 numbers
c = 0
index = 0
for i in a:
if i == o or i == t:
# if current element is either one or two current count is increased
c += 1
else:
# if current element is neither one nor two then they are updated accordingly and max is updated
o = a[index - 1]
t = a[index]
m = max(m, c)
c = 2
index += 1
m = max(m, c)
print(m)
We can use two pointer technique to solve this problem in O(n) run time complexity. These two pointer for example startPtr and endPtr will represent the range in the array. We will maintain this range [startPtr, endPtr] in such way that it contains no more than 2 unique number. We can do this by keeping track of position of the 2 unique number. My implement in C++ is given below:
int main()
{
int array[] = {1,2,3,3,2,3,2,3,2,2,2,1,3,4};
int startPtr = 0;
int endPtr = 0;
// denotes the size of the array
int size= sizeof(array)/sizeof(array[0]);
// contain last position of unique number 1 in the range [startPtr, endPtr]
int uniqueNumPos1 = -1; // -1 value represents it is not set yet
// contain last position of unique number 2 in the range [startPtr, endPtr]
int uniqueNumPos2 = -1; // -1 value represents it is not set yet
// contains length of maximum continuous subarray with 2 unique numbers
int ans = 0;
while(endPtr < size) {
if(uniqueNumPos1 == -1 || array[endPtr] == array[uniqueNumPos1]) {
uniqueNumPos1 = endPtr;
}
else {
if(uniqueNumPos2 == -1 || array[endPtr] == array[uniqueNumPos2]) {
uniqueNumPos2 = endPtr;
}
else {
// for this new third unique number update startPtr with min(uniqueNumPos1, uniqueNumPos2) + 1
// to ensure [startPtr, endPtr] does not contain more that two unique
startPtr = min(uniqueNumPos1, uniqueNumPos2) + 1;
// update uniqueNumPos1 and uniqueNumPos2
uniqueNumPos1 = endPtr -1;
uniqueNumPos2 = endPtr;
}
}
// this conditon is to ensure the range contain exactly two unique number
// if you are looking for the range containing less than or equal to two unique number, then you can omit this condition
if (uniqueNumPos1 != -1 && uniqueNumPos2 !=-1) {
ans = max( ans, endPtr - startPtr + 1);
}
endPtr++;
}
printf("%d\n", ans);
}
Thanks #MBo for pointing out the mistakes.
import java.util.Arrays;
import static java.lang.System.out;
class TestCase{
int[] test;
int answer;
TestCase(int[] test,int answer){
this.test = test;
this.answer = answer;
}
}
public class Solution {
public static void main(String[] args) {
TestCase[] tests = {
new TestCase(new int[]{2, 3, 4, 3, 2, 2, 4},3),
new TestCase(new int[]{2, 3, 3, 3, 3, 4, 3, 3, 2, 2, 4},7),
new TestCase(new int[]{1,2,3,3,4,2,3,2,3,2,2,2,1,3,4},7),
new TestCase(new int[]{2, 7, 8, 7, 8, 7},5),
new TestCase(new int[]{-1,2,2,2,2,2,2,2,2,2,2,-1,-1,4},13),
new TestCase(new int[]{1,2,3,4,5,6,7,7},3),
new TestCase(new int[]{0,0,0,0,0},0),
new TestCase(new int[]{0,0,0,2,2,2,1,1,1,1},7),
new TestCase(new int[]{},0)
};
for(int i=0;i<tests.length;++i){
int ans = maxContiguousArrayWith2UniqueElements(tests[i].test);
out.println(Arrays.toString(tests[i].test));
out.println("Expected: " + tests[i].answer);
out.println("Returned: " + ans);
out.println("Result: " + (tests[i].answer == ans ? "ok" : "not ok"));
out.println();
}
}
private static int maxContiguousArrayWith2UniqueElements(int[] A){
if(A == null || A.length <= 1) return 0;
int max_subarray = 0;
int first_number = A[0],second_number = A[0];
int start_index = 0,same_element_run_length = 1;
for(int i=1;i<A.length;++i){
if(A[i] != A[i-1]){
if(first_number == second_number){
second_number = A[i];
}else{
if(A[i] != first_number && A[i] != second_number){
max_subarray = Math.max(max_subarray,i - start_index);
start_index = i - same_element_run_length;
first_number = A[i-1];
second_number = A[i];
}
}
same_element_run_length = 1;
}else{
same_element_run_length++;
}
}
return first_number == second_number ? max_subarray : Math.max(max_subarray,A.length - start_index);
}
}
OUTPUT:
[2, 3, 4, 3, 2, 2, 4]
Expected: 3
Returned: 3
Result: ok
[2, 3, 3, 3, 3, 4, 3, 3, 2, 2, 4]
Expected: 7
Returned: 7
Result: ok
[1, 2, 3, 3, 4, 2, 3, 2, 3, 2, 2, 2, 1, 3, 4]
Expected: 7
Returned: 7
Result: ok
[2, 7, 8, 7, 8, 7]
Expected: 5
Returned: 5
Result: ok
[-1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, 4]
Expected: 13
Returned: 13
Result: ok
[1, 2, 3, 4, 5, 6, 7, 7]
Expected: 3
Returned: 3
Result: ok
[0, 0, 0, 0, 0]
Expected: 0
Returned: 0
Result: ok
[0, 0, 0, 2, 2, 2, 1, 1, 1, 1]
Expected: 7
Returned: 7
Result: ok
[]
Expected: 0
Returned: 0
Result: ok
Algorithm:
So, we maintain 2 variables first_number and second_number which will hold those 2 unique numbers.
As you know, there could be many possible subarrays we have to consider to get the max subarray length which has 2 unique elements. Hence, we need a pointer variable which will point to start of a subarray. In this, that pointer is start_index.
Any subarray breaks when we find a third number which is not equal to first_number or second_number. So, now, we calculate the previous subarray length(which had those 2 unique elements) by doing i - start_index.
Tricky part of this question is how to get the start_index of the next subarray.
If you closely observe, second_number of previous subarray becomes first_number of current subarray and third number we encountered just now becomes second_number of this current subarray.
So, one way to calculate when this first_number started is to run a while loop backwards to get that start_index. But that would make the algorithm O(n^2) if there are many subarrays to consider(which it will be).
Hence, we maintain a variable called same_element_run_length which just keeps track of the length or frequency of how many times the number got repeated and gets updated whenever it breaks. So, start_index for the next subarray after we encounter the third number becomes start_index = i - same_element_run_length.
Rest of the computation done is self-explanatory.
Time Complexity: O(n), Space Complexity : O(1).

Dynamic programming (Solve combination of scores) [duplicate]

It was one of my interview question, and I could not think of the good way to get number N. (plus, I did not understand the American football scoring system as well)
6 points for the touchdown
1 point for the extra point (kicked)
2 points for a safety or a conversion (extra try after a touchdown)
3 points for a field goal
What would be an efficient algorithm to get all combinations of point-accumulations necessary to get a certain score N?
Assuming here you are looking for a way to get number of possibilities and not the actual possibilities.
First let's find a recursive function:
f(n) = (f(n-6) >= 0? f(n-6) : 0) + (f(n-1) >= 0 ? f(n-1) : 0) + (f(n-2) >= 0 ? f(n-2) : 0) + (f(n-3) >= 0 ? f(n-3) : 0)
base: f(0) = 1 and f(n) = -infinity [n<0]
The idea behind it is: You can always get to 0, by a no scoring game. If you can get to f(n-6), you can also get to f(n), and so on for each possibility.
Using the above formula one can easily create a recursive solution.
Note that you can even use dynamic programming with it, initialize a table with [-5,n], init f[0] = 0 and f[-1] = f[-2] = f[-3] = f[-4] = f[-5] = -infinity and iterate over indexes [1,n] to achieve the number of possibilities based on the the recursive formula above.
EDIT:
I just realized that a simplified version of the above formula could be:
f(n) = f(n-6) + f(n-1) + f(n-2) + f(n-3)
and base will be: f(0) = 1, f(n) = 0 [n<0]
The two formulas will yield exactly the same result.
This is identical to the coin change problem, apart from the specific numbers used. See this question for a variety of answers.
You could use dynamic programming loop from 1 to n, here is some pseudo code:
results[1] = 1
for i from 1 to n :
results[i+1] += results[i]
results[i+2] += results[i]
results[i+3] += results[i]
results[i+6] += results[i]
this way complexity is O(N), instead of exponential complexity if you compute recursively by subtracting from the final score... like computing a Fibonacci series.
I hope my explanation is understandable enough..
I know this question is old, but all of the solutions I see help calculate the number of scoring permutations rather than the number of scoring combinations. (So I think either something like this should be an answer or the question title should be changed.)
Some code such as the following (which could then be converted into a dp) will calculate the number of possible combinations of different scores:
int getScoreCombinationCount(int score, int scoreVals[], int scoreValIndex) {
if (scoreValIndex < 0)
return 0;
if (score == 0)
return 1;
if (score < 0)
return 0;
return getScoreCombinationCount(score - scoreVals[scoreValIndex], scoreVals, scoreValIndex) +
getScoreCombinationCount(score, scoreVals, scoreValIndex - 1);
}
This solution, implemented based on a solution in the book Elements of Programming Interviews seems to be correct for counting the number of 'combinations' (no duplicate sets) for a set of score points.
For example, if points = {7, 3, 2}, there are 2 combinations for a total score of 7:
{7} and {3, 2, 2}.
public static int ScoreCombinationCount(int total, int[] points)
{
int[] combinations = new int[total + 1];
combinations[0] = 1;
for (var i = 0; i < points.Length; i++)
{
int point = points[i];
for (var j = point; j <= total; j++)
{
combinations[j] += combinations[j - point];
}
}
return combinations[total];
}
I am not sure I understand the logic though. Can someone explain?
The answer to this question depends on whether or not you allow the total number of combinations to include duplicate unordered combinations.
For example, in American football, you can score 2, 3, or 7 points (yes, I know you can miss the extra point on a touchdown, but let's ignore 1 point).
Then if your target N is 5, then you can reach it with {2, 3} or {3, 2}. If you count that as two combinations, then the Dynamic Programming solution by #amit will work. However, if you count those two combinations as one combination, then the iterative solution by #Maximus will work.
Below is some Java code, where findWays() corresponds to counting all possible combinations, including duplicates, and findUniqueWays() corresponds to counting only unique combinations.
// Counts the number of non-unique ways to reach N.
// Note that this algorithm counts {1,2} separately from {2,1}
// Applies a recurrence relationship. For example, with values={1,2}:
// cache[i] = cache[i-1] + cache[i-2]
public static long findWays(int N, int[] values) {
long cache[] = new long[N+1];
cache[0] = 1;
for (int i = 1; i <= N; i++) {
cache[i] = 0;
for (int value : values) {
if (value <= i)
cache[i] += cache[i-value];
}
}
return cache[N];
}
// Counts the number of unique ways to reach N.
// Note that this counts truly unique combinations: {1,2} is the same as {2,1}
public static long findUniqueWays(int N, int[] values) {
long [] cache = new long[N+1];
cache[0] = 1;
for (int i = 0; i < values.length; i++) {
int value = values[i];
for (int j = value; j <= N; j++) {
cache[j] += cache[j-value];
}
}
return cache[N];
}
Below is a test case where the possible points are {2,3,7}.
private static void testFindUniqueWaysFootball() {
int[] points = new int[]{2, 3, 7}; // Ways of scoring points.
int[] NValues = new int[]{5, 7, 10}; // Total score.
long result = -1;
for (int N : NValues) {
System.out.printf("\nN = %d points\n", N);
result = findWays(N, points);
System.out.printf("findWays() result = %d\n", result);
result = findUniqueWays(N, points);
System.out.printf("findUniqueWays() result = %d\n", result);
}
}
The output is:
N = 5 points
findWays() result = 2
findUniqueWays() result = 1
N = 7 points
findWays() result = 4
findUniqueWays() result = 2
N = 10 points
findWays() result = 9
findUniqueWays() result = 3
The results above show that to reach N=7 points, then there 4 non-unique ways to do so (those ways are {7}, {2,2,3}, {2,3,2}, {3,2,2}). However, there are only 2 unique ways (those ways are {7} and {2,2,3}). However, .
Below is a python program to find all combinations ignoring the combination order (e.g. 2,3,6 and 3,2,6 are considered one combination). This is a dynamic programming solution with order(n) time. Scores are 2,3,6,7.
We traverse from row score 2 to row score 7 (4 rows). Row score 2 contains the count if we only consider score 2 in calculating the number of combinations. Row score 3 produces each column by taking the count in row score 2 for the same final score plus the previous 3 count in its own row (current position minus 3). Row score 6 uses row score 3, which contains counts for both 2,3 and adds in the previous 6 count (current position minus 6). Row score 7 uses row score 6, which contains counts for row scores 2,3,6 plus the previous 7 count.
For example, numbers[1][12] = numbers[0][12] + numbers[1][9] (9 = 12-3) which results in 3 = 1 + 2; numbers[3][12] = numbers[2][12] + numbers[3][9] (9 = 12-3) which results in 7 = 6 + 1;
def cntMoney(num):
mSz = len(scores)
numbers = [[0]*(1+num) for _ in range(mSz)]
for mI in range(mSz): numbers[mI][0] = 1
for mI,m in enumerate(scores):
for i in range(1,num+1):
numbers[mI][i] = numbers[mI][i-m] if i >= m else 0
if mI != 0: numbers[mI][i] += numbers[mI-1][i]
print('m,numbers',m,numbers[mI])
return numbers[mSz-1][num]
scores = [2,3,6,7]
num = 12
print('score,combinations',num,cntMoney(num))
output:
('m,numbers', 2, [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
('m,numbers', 3, [1, 0, 1, 1, 1, 1, 2, 1, 2, 2, 2, 2, 3])
('m,numbers', 6, [1, 0, 1, 1, 1, 1, 3, 1, 3, 3, 3, 3, 6])
('m,numbers', 7, [1, 0, 1, 1, 1, 1, 3, 2, 3, 4, 4, 4, 7])
('score,combinations', 12, 7)
Below is a python program to find all ordered combinations (e.g. 2,3,6 and 3,2,6 are considered two combinations). This is a dynamic programming solution with order(n) time. We build up from the start, adding the combinations calculated from previous score numbers, for each of the scores (2,3,6,7).
'vals[i] += vals[i-s]' means the current value equals the addition of the combinations from the previous values for the given scores. For example, for column vals[12] = the addition of scores 2,3,6,7: 26 = 12+9+3+2 (i-s = 10,9,6,5).
def allSeq(num):
vals = [0]*(num+1)
vals[0] = 1
for i in range(num+1):
for s in scores:
if i-s >= 0: vals[i] += vals[i-s]
print(vals)
return vals[num]
scores = [2,3,6,7]
num = 12
print('num,seqsToNum',num,allSeq(num))
Output:
[1, 0, 1, 1, 1, 2, 3, 4, 6, 9, 12, 18, 26]
('num,seqsToNum', 12, 26)
Attached is a program that prints the sequences for each score up to the given final score.
def allSeq(num):
seqs = [[] for _ in range(num+1)]
vals = [0]*(num+1)
vals[0] = 1
for i in range(num+1):
for sI,s in enumerate(scores):
if i-s >= 0:
vals[i] += vals[i-s]
if i == s: seqs[i].append(str(s))
else:
for x in seqs[i-s]:
seqs[i].append(x + '-' + str(s))
print(vals)
for sI,seq in enumerate(seqs):
print('num,seqsSz,listOfSeqs',sI,len(seq),seq)
return vals[num],seqs[num]
scores = [2,3,6,7]
num = 12
combos,seqs = allSeq(num)
Output:
[1, 0, 1, 1, 1, 2, 3, 4, 6, 9, 12, 18, 26]
('num,seqsSz,listOfSeqs', 0, 0, [])
('num,seqsSz,listOfSeqs', 1, 0, [])
('num,seqsSz,listOfSeqs', 2, 1, ['2'])
('num,seqsSz,listOfSeqs', 3, 1, ['3'])
('num,seqsSz,listOfSeqs', 4, 1, ['2-2'])
('num,seqsSz,listOfSeqs', 5, 2, ['3-2', '2-3'])
('num,seqsSz,listOfSeqs', 6, 3, ['2-2-2', '3-3', '6'])
('num,seqsSz,listOfSeqs', 7, 4, ['3-2-2', '2-3-2', '2-2-3', '7'])
('num,seqsSz,listOfSeqs', 8, 6, ['2-2-2-2', '3-3-2', '6-2', '3-2-3', '2-3-3', '2-6'])
('num,seqsSz,listOfSeqs', 9, 9, ['3-2-2-2', '2-3-2-2', '2-2-3-2', '7-2', '2-2-2-3', '3-3-3', '6-3', '3-6', '2-7'])
('num,seqsSz,listOfSeqs', 10, 12, ['2-2-2-2-2', '3-3-2-2', '6-2-2', '3-2-3-2', '2-3-3-2', '2-6-2', '3-2-2-3', '2-3-2-3', '2-2-3-3', '7-3', '2-2-6', '3-7'])
('num,seqsSz,listOfSeqs', 11, 18, ['3-2-2-2-2', '2-3-2-2-2', '2-2-3-2-2', '7-2-2', '2-2-2-3-2', '3-3-3-2', '6-3-2', '3-6-2', '2-7-2', '2-2-2-2-3', '3-3-2-3', '6-2-3', '3-2-3-3', '2-3-3-3', '2-6-3', '3-2-6', '2-3-6', '2-2-7'])
('num,seqsSz,listOfSeqs', 12, 26, ['2-2-2-2-2-2', '3-3-2-2-2', '6-2-2-2', '3-2-3-2-2', '2-3-3-2-2', '2-6-2-2', '3-2-2-3-2', '2-3-2-3-2', '2-2-3-3-2', '7-3-2', '2-2-6-2', '3-7-2', '3-2-2-2-3', '2-3-2-2-3', '2-2-3-2-3', '7-2-3', '2-2-2-3-3', '3-3-3-3', '6-3-3', '3-6-3', '2-7-3', '2-2-2-6', '3-3-6', '6-6', '3-2-7', '2-3-7'])
~

Generate a new array from an array of numbers

I found this question on Glassdoor:
Generate a new array from an array of numbers. Start from the beginning. Put the number of some number first, and then that number. For example, from array 1, 1, 2, 3, 3, 1 You should get 2, 1, 1, 2, 2, 3, 1, 1 Write a program to solve this problem.
I am not sure if I get the idea, how come 1, 1, 2, 3, 3, 1 transforms into 2, 1, 1, 2, 2, 3, 1, 1? I first thought they are number of occurrences of a number followed by the number itself. But from the given example, it seems like something else is wanted.
What is this transformation?
I first thought they are number of occurrences of a number followed by the number itself.
Your first thought was correct.
Break the first array down to be:
1, 1,
2,
3, 3,
1
And the second to be:
2, 1,
1, 2,
2, 3,
1, 1
Then it should make more sense.
Sample implementation:
#!/usr/bin/env python
import sys
array = map(int, sys.argv[1:])
print array
count = 0
current = array[0]
index = 1
output = []
for number in array:
if current != number:
output.append(count)
output.append(current)
current = number
count = 0
count += 1
output.append(count)
output.append(current)
print output
Demo:
> ./arrays.py 1 1 2 3 3 1
[1, 1, 2, 3, 3, 1]
[2, 1, 1, 2, 2, 3, 1, 1]
what u think is correct. its the number of times the distinct element comes and then the element itself.
here is pseudocode:
array1 = given input array
array2 = output array
int previous = array1[0];
int currentCount = 0;
for each entry x in array1 {
if(x == previous) {
currentCount++;
}
else {
array2.add(currentCount);
array2.add(x);
//reset global variables for next elements
previous = x;
currentCount = 0;
}
}
And the Haskell version...yup, that's the whole thing.
import Data.List
countArray list = concat [[length l, fromIntegral (head l)] | l <- group list]

Algorithm to get all combinations of (American) football point-accumulations necessary to get a certain score N

It was one of my interview question, and I could not think of the good way to get number N. (plus, I did not understand the American football scoring system as well)
6 points for the touchdown
1 point for the extra point (kicked)
2 points for a safety or a conversion (extra try after a touchdown)
3 points for a field goal
What would be an efficient algorithm to get all combinations of point-accumulations necessary to get a certain score N?
Assuming here you are looking for a way to get number of possibilities and not the actual possibilities.
First let's find a recursive function:
f(n) = (f(n-6) >= 0? f(n-6) : 0) + (f(n-1) >= 0 ? f(n-1) : 0) + (f(n-2) >= 0 ? f(n-2) : 0) + (f(n-3) >= 0 ? f(n-3) : 0)
base: f(0) = 1 and f(n) = -infinity [n<0]
The idea behind it is: You can always get to 0, by a no scoring game. If you can get to f(n-6), you can also get to f(n), and so on for each possibility.
Using the above formula one can easily create a recursive solution.
Note that you can even use dynamic programming with it, initialize a table with [-5,n], init f[0] = 0 and f[-1] = f[-2] = f[-3] = f[-4] = f[-5] = -infinity and iterate over indexes [1,n] to achieve the number of possibilities based on the the recursive formula above.
EDIT:
I just realized that a simplified version of the above formula could be:
f(n) = f(n-6) + f(n-1) + f(n-2) + f(n-3)
and base will be: f(0) = 1, f(n) = 0 [n<0]
The two formulas will yield exactly the same result.
This is identical to the coin change problem, apart from the specific numbers used. See this question for a variety of answers.
You could use dynamic programming loop from 1 to n, here is some pseudo code:
results[1] = 1
for i from 1 to n :
results[i+1] += results[i]
results[i+2] += results[i]
results[i+3] += results[i]
results[i+6] += results[i]
this way complexity is O(N), instead of exponential complexity if you compute recursively by subtracting from the final score... like computing a Fibonacci series.
I hope my explanation is understandable enough..
I know this question is old, but all of the solutions I see help calculate the number of scoring permutations rather than the number of scoring combinations. (So I think either something like this should be an answer or the question title should be changed.)
Some code such as the following (which could then be converted into a dp) will calculate the number of possible combinations of different scores:
int getScoreCombinationCount(int score, int scoreVals[], int scoreValIndex) {
if (scoreValIndex < 0)
return 0;
if (score == 0)
return 1;
if (score < 0)
return 0;
return getScoreCombinationCount(score - scoreVals[scoreValIndex], scoreVals, scoreValIndex) +
getScoreCombinationCount(score, scoreVals, scoreValIndex - 1);
}
This solution, implemented based on a solution in the book Elements of Programming Interviews seems to be correct for counting the number of 'combinations' (no duplicate sets) for a set of score points.
For example, if points = {7, 3, 2}, there are 2 combinations for a total score of 7:
{7} and {3, 2, 2}.
public static int ScoreCombinationCount(int total, int[] points)
{
int[] combinations = new int[total + 1];
combinations[0] = 1;
for (var i = 0; i < points.Length; i++)
{
int point = points[i];
for (var j = point; j <= total; j++)
{
combinations[j] += combinations[j - point];
}
}
return combinations[total];
}
I am not sure I understand the logic though. Can someone explain?
The answer to this question depends on whether or not you allow the total number of combinations to include duplicate unordered combinations.
For example, in American football, you can score 2, 3, or 7 points (yes, I know you can miss the extra point on a touchdown, but let's ignore 1 point).
Then if your target N is 5, then you can reach it with {2, 3} or {3, 2}. If you count that as two combinations, then the Dynamic Programming solution by #amit will work. However, if you count those two combinations as one combination, then the iterative solution by #Maximus will work.
Below is some Java code, where findWays() corresponds to counting all possible combinations, including duplicates, and findUniqueWays() corresponds to counting only unique combinations.
// Counts the number of non-unique ways to reach N.
// Note that this algorithm counts {1,2} separately from {2,1}
// Applies a recurrence relationship. For example, with values={1,2}:
// cache[i] = cache[i-1] + cache[i-2]
public static long findWays(int N, int[] values) {
long cache[] = new long[N+1];
cache[0] = 1;
for (int i = 1; i <= N; i++) {
cache[i] = 0;
for (int value : values) {
if (value <= i)
cache[i] += cache[i-value];
}
}
return cache[N];
}
// Counts the number of unique ways to reach N.
// Note that this counts truly unique combinations: {1,2} is the same as {2,1}
public static long findUniqueWays(int N, int[] values) {
long [] cache = new long[N+1];
cache[0] = 1;
for (int i = 0; i < values.length; i++) {
int value = values[i];
for (int j = value; j <= N; j++) {
cache[j] += cache[j-value];
}
}
return cache[N];
}
Below is a test case where the possible points are {2,3,7}.
private static void testFindUniqueWaysFootball() {
int[] points = new int[]{2, 3, 7}; // Ways of scoring points.
int[] NValues = new int[]{5, 7, 10}; // Total score.
long result = -1;
for (int N : NValues) {
System.out.printf("\nN = %d points\n", N);
result = findWays(N, points);
System.out.printf("findWays() result = %d\n", result);
result = findUniqueWays(N, points);
System.out.printf("findUniqueWays() result = %d\n", result);
}
}
The output is:
N = 5 points
findWays() result = 2
findUniqueWays() result = 1
N = 7 points
findWays() result = 4
findUniqueWays() result = 2
N = 10 points
findWays() result = 9
findUniqueWays() result = 3
The results above show that to reach N=7 points, then there 4 non-unique ways to do so (those ways are {7}, {2,2,3}, {2,3,2}, {3,2,2}). However, there are only 2 unique ways (those ways are {7} and {2,2,3}). However, .
Below is a python program to find all combinations ignoring the combination order (e.g. 2,3,6 and 3,2,6 are considered one combination). This is a dynamic programming solution with order(n) time. Scores are 2,3,6,7.
We traverse from row score 2 to row score 7 (4 rows). Row score 2 contains the count if we only consider score 2 in calculating the number of combinations. Row score 3 produces each column by taking the count in row score 2 for the same final score plus the previous 3 count in its own row (current position minus 3). Row score 6 uses row score 3, which contains counts for both 2,3 and adds in the previous 6 count (current position minus 6). Row score 7 uses row score 6, which contains counts for row scores 2,3,6 plus the previous 7 count.
For example, numbers[1][12] = numbers[0][12] + numbers[1][9] (9 = 12-3) which results in 3 = 1 + 2; numbers[3][12] = numbers[2][12] + numbers[3][9] (9 = 12-3) which results in 7 = 6 + 1;
def cntMoney(num):
mSz = len(scores)
numbers = [[0]*(1+num) for _ in range(mSz)]
for mI in range(mSz): numbers[mI][0] = 1
for mI,m in enumerate(scores):
for i in range(1,num+1):
numbers[mI][i] = numbers[mI][i-m] if i >= m else 0
if mI != 0: numbers[mI][i] += numbers[mI-1][i]
print('m,numbers',m,numbers[mI])
return numbers[mSz-1][num]
scores = [2,3,6,7]
num = 12
print('score,combinations',num,cntMoney(num))
output:
('m,numbers', 2, [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
('m,numbers', 3, [1, 0, 1, 1, 1, 1, 2, 1, 2, 2, 2, 2, 3])
('m,numbers', 6, [1, 0, 1, 1, 1, 1, 3, 1, 3, 3, 3, 3, 6])
('m,numbers', 7, [1, 0, 1, 1, 1, 1, 3, 2, 3, 4, 4, 4, 7])
('score,combinations', 12, 7)
Below is a python program to find all ordered combinations (e.g. 2,3,6 and 3,2,6 are considered two combinations). This is a dynamic programming solution with order(n) time. We build up from the start, adding the combinations calculated from previous score numbers, for each of the scores (2,3,6,7).
'vals[i] += vals[i-s]' means the current value equals the addition of the combinations from the previous values for the given scores. For example, for column vals[12] = the addition of scores 2,3,6,7: 26 = 12+9+3+2 (i-s = 10,9,6,5).
def allSeq(num):
vals = [0]*(num+1)
vals[0] = 1
for i in range(num+1):
for s in scores:
if i-s >= 0: vals[i] += vals[i-s]
print(vals)
return vals[num]
scores = [2,3,6,7]
num = 12
print('num,seqsToNum',num,allSeq(num))
Output:
[1, 0, 1, 1, 1, 2, 3, 4, 6, 9, 12, 18, 26]
('num,seqsToNum', 12, 26)
Attached is a program that prints the sequences for each score up to the given final score.
def allSeq(num):
seqs = [[] for _ in range(num+1)]
vals = [0]*(num+1)
vals[0] = 1
for i in range(num+1):
for sI,s in enumerate(scores):
if i-s >= 0:
vals[i] += vals[i-s]
if i == s: seqs[i].append(str(s))
else:
for x in seqs[i-s]:
seqs[i].append(x + '-' + str(s))
print(vals)
for sI,seq in enumerate(seqs):
print('num,seqsSz,listOfSeqs',sI,len(seq),seq)
return vals[num],seqs[num]
scores = [2,3,6,7]
num = 12
combos,seqs = allSeq(num)
Output:
[1, 0, 1, 1, 1, 2, 3, 4, 6, 9, 12, 18, 26]
('num,seqsSz,listOfSeqs', 0, 0, [])
('num,seqsSz,listOfSeqs', 1, 0, [])
('num,seqsSz,listOfSeqs', 2, 1, ['2'])
('num,seqsSz,listOfSeqs', 3, 1, ['3'])
('num,seqsSz,listOfSeqs', 4, 1, ['2-2'])
('num,seqsSz,listOfSeqs', 5, 2, ['3-2', '2-3'])
('num,seqsSz,listOfSeqs', 6, 3, ['2-2-2', '3-3', '6'])
('num,seqsSz,listOfSeqs', 7, 4, ['3-2-2', '2-3-2', '2-2-3', '7'])
('num,seqsSz,listOfSeqs', 8, 6, ['2-2-2-2', '3-3-2', '6-2', '3-2-3', '2-3-3', '2-6'])
('num,seqsSz,listOfSeqs', 9, 9, ['3-2-2-2', '2-3-2-2', '2-2-3-2', '7-2', '2-2-2-3', '3-3-3', '6-3', '3-6', '2-7'])
('num,seqsSz,listOfSeqs', 10, 12, ['2-2-2-2-2', '3-3-2-2', '6-2-2', '3-2-3-2', '2-3-3-2', '2-6-2', '3-2-2-3', '2-3-2-3', '2-2-3-3', '7-3', '2-2-6', '3-7'])
('num,seqsSz,listOfSeqs', 11, 18, ['3-2-2-2-2', '2-3-2-2-2', '2-2-3-2-2', '7-2-2', '2-2-2-3-2', '3-3-3-2', '6-3-2', '3-6-2', '2-7-2', '2-2-2-2-3', '3-3-2-3', '6-2-3', '3-2-3-3', '2-3-3-3', '2-6-3', '3-2-6', '2-3-6', '2-2-7'])
('num,seqsSz,listOfSeqs', 12, 26, ['2-2-2-2-2-2', '3-3-2-2-2', '6-2-2-2', '3-2-3-2-2', '2-3-3-2-2', '2-6-2-2', '3-2-2-3-2', '2-3-2-3-2', '2-2-3-3-2', '7-3-2', '2-2-6-2', '3-7-2', '3-2-2-2-3', '2-3-2-2-3', '2-2-3-2-3', '7-2-3', '2-2-2-3-3', '3-3-3-3', '6-3-3', '3-6-3', '2-7-3', '2-2-2-6', '3-3-6', '6-6', '3-2-7', '2-3-7'])
~

Resources