Ruby - Max Array Sum from non-adjacent integers in array - arrays

This code walks through the array and returns the largest sum of non-adjacent integers. This is from HackerRank - Can anyone explain why this works? Its a solution I found online but I don't understand it and didn't figure this out myself.
Thanks!
https://www.hackerrank.com/challenges/max-array-sum/problem?h_l=interview&playlist_slugs%5B%5D=interview-preparation-kit&playlist_slugs%5B%5D=dynamic-programming
def maxSubsetSum(arr)
incl = 0
excl = 0
temp = 0
for i in 0...arr.size
temp = incl
incl = [arr[i]+excl, temp].max
excl = temp
end
return [incl, excl].max
end
maxSubsetSum([1,3,5,2,4,6,8])

This is some pretty ugly (by ugly I mean unidiomatic) Ruby code so let's clean it up before we proceed:
def maxSubsetSum(arr)
incl = 0
excl = 0
temp = 0
arr.each do |value|
temp = incl
incl = [value + excl, temp].max
excl = temp
end
[incl, excl].max
end
maxSubsetSum([1,3,5,2,4,6,8])
Now we can start to analyze this code. I've gone through and written the values of each variable at each step in the loop:
value = 1
temp = 0
incl = 1
excl = 0
value = 3
temp = 1
incl = 3
excl = 1
value = 5
temp = 3
incl = 6
excl = 3
value = 2
temp = 6
incl = 6
excl = 6
value = 4
temp = 6
incl = 10
excl = 6
value = 6
temp = 10
incl = 12
excl = 10
value = 8
temp = 12
incl = 18
excl = 12
(return 18)
At any given point, the program is determining whether or not it should "use" a value -- the disadvantage to using a value is that you cannot use the value after it, as that is adjacent. At every step in the process, it's comparing adding the current value to excl (which represents the best sum at the previous step without including that value) with incl (technically temp but temp holds incl at that stage), which represents the value at the previous iteration of including the value.
temp is not remembered across loops; after each iteration of the loop, the only values that matter are incl and excl. To reiterate, at the end of each loop, incl holds the best sum that includes the previous number, and excl holds the best sum that does not include the previous number. At each step in the loop, incl and excl are re-computed to reflect the inclusion or exclusion of the new value.
To show that this process does work, let's consider the above array but with an extra element at the end, 7. So now our array looks like this: [1,3,5,2,4,6,8,7]. We already have most of the work done from the previous listing. We set temp to 18, incl becomes [7 + 12, 18].max which is 19, and excl becomes 18. Now we can see that including this last number means that we get a number larger than the previous result, so we have to use it, and that means that we can't use the 8 we previously used to get our result.
This process is known as dynamic programming, where in order to determine the answer to the overall question, you break the problem down and add complexity to it. In this case, we break the array down and then slowly add back each value, keeping track of what the best results for the previous part are.

Understand the algorithm
The code is fairly straightforward once you understand the algorithm being used. A Google search turned up many hits. See, for example, this article. They all seem to use the same dynamic programming approach.
The general solution produces both the maximum sum and the array of elements from the original array that produce that sum. Here only the sum is needed so the solution is simplified slightly. I will first describe the algorithm for producing the general solution, then will simplify to compute only the maximum sum.
Compute general solution
If the array is a, the nth step computes two values: the maximum sum among the first n elements, a[0], a[1],...,a[n-1], if the nth element is included and the maxium sum if that element is excluded. This is easy because those two results have already been computed for the previous element, a[n-2]. When the last element of the array has been processed the maximum sum equals the larger of the maximum sum when the last element is included and the maximum sum when the last element is excluded. To construct the array that yields the maximum sum a simple walk-back is employed.
Let b be an array of hashes that we will build. Initially,
b[0] = { included: 0, excluded: 0 }
Then for each n = 1,..., m, where m = a.size,
b[n] = { included: a[n-1] + b[n-1][:excluded],
excluded: [b[n-1][:included], b[n-1][:excluded]].max }
After b[m] has been computed, the maximum total equals
[b[m][:included], b[m][:excluded]].max
The walk-back to construct the array that yields the largest sum is outlined in the example below.
Consider the following.
arr = [1, 3, -2, 7, 4, 6, 8, -3, 2]
b = (1..arr.size).each_with_object([{ included: 0, excluded: 0 }]) do |n,b|
b[n] = { included: arr[n-1] + b[n-1][:excluded],
excluded: [b[n-1][:included], b[n-1][:excluded]].max }
end
#=> [{:included=> 0, :excluded=> 0}, n arr[n-1]
# {:included=> 1, :excluded=> 0}, 1 1
# {:included=> 3, :excluded=> 1}, 2 3
# {:included=>-1, :excluded=> 3}, 3 -2
# {:included=>10, :excluded=> 3}, 4 7
# {:included=> 7, :excluded=>10}, 5 4
# {:included=>16, :excluded=>10}, 6 6
# {:included=>18, :excluded=>16}, 7 8
# {:included=>13, :excluded=>18}, 8 -3
# {:included=>20, :excluded=>18}] 9 2
I've included arr[-1] for each value of n above for easy reference. The largest sum is seen to be [20, 18].max #=> 20, which includes the last element, arr[9] #=> 2. Hence, arr[8] could not be included. Note that b[8][:excluded] + arr[8] #=> 18 + 2 => 20, which is b[9][:included].
Since arr[8] is excluded arr[7] could be included or excluded. We see that b[7][:included] == b[8][:excluded] == 18 and b[7][:excluded] == 16 < 18 == b[8][:exclued], which tells us that arr[7] is included. The same reasoning is used to walk back to the beginning of b, demonstrating that the elements that sum to 20 form the array are [3, 7, 8, 2]. In general, multiple optimal solutions are of course possible.
Compute maximum sum only
If, as in this question, only the maximum sum is required, and not the array of elements that produce it, there is no need for b to be an array. We may simply write
b = { included: a[0], excluded: 0 }
Then for each n = 1,..., m-1
b[:included], b[:excluded] =
a[n] + b[:excluded], [b[:included], b[:excluded]].max
We may wrap this in a method as follows.
def max_subset_sum(arr)
arr.size.times.with_object({ included: 0, excluded: 0 }) do |n,h|
h[:included], h[:excluded] =
arr[n] + h[:excluded], [h[:included], h[:excluded]].max
end.values.max
end
max_subset_sum arr
#=> 20 (= 3+7+8+2)
If desired, we can write this with two-element arrays rather than hashes (closer to the code in the question), though I don't think it's as clear.
def optimize(arr)
arr.size.times.with_object([0, 0]) do |n,a|
a[0], a[1] = arr[n] + a[1], [a[0], a[1]].max
end.max
end
optimize arr
#=> 20
Notice that I've used parallel assignment to avoid the create of a temporary variable.

Related

How to iterate through a circular array multiple times in python?

I want to circle through the array multiple times. When I reach the last index, the next index should be the first one.
For example, I have an array of 6 elements
array1 = [1,2,3,4,5,6]
and I have K = 4. K will be the number of elements that I will skip.
In the above example, I will start from array1[0] and skip K elements including the array1[0] element.
So if I skip 4 elements, I will reach array1[4]. If I skip K elements once more, I should skip array1[4], array1[5], array1[0] and array1[1] and reach array1[2]. This process will repeat itself N times.
I tried searching for the solution online because I cannot think of a way to move through the array in circle. I found one solution that says to use modulo operator like this
print a[3 % len(a)]
but I cannot understand this since I am just starting out with python.
Understanding what modulo is will be helpful https://en.wikipedia.org/wiki/Modulo
To sum up, in this exercise you don't care how many times you went through the array. You only care about "at which position of the current iteration you are" lets say. Therefore, a modulo operation using the length of the array as modulo will give you the remainder of such division, which is exactly what you are looking for.
Example:
arr = [1,2,3,4,5]
k = 27
arrlength = len(arr) # 5
reminder = k % arrlength # 27 % 5 = 2
arr[reminder] # 3
So, the modulo operator returns the remainder from the division between two numbers.
Example:
6 % 2 = 0 # because 6/2 = 3 with no remainder
6 % 5 = 1 # because 6/5 = 1 (integer part) plus remainder 1
6 % 7 = 6 # because 7 doesn't fit in 6, so all the dividend goes into the remainder
So your problem can be solved by something like this:
arr = [1,2,3,4,5,6]
N = 5
step = 4
for i in range(5):
print(arr[(i+1)*step%len(arr)])
where N is the number of elements you want to print
This is the same as creating an extended list such as:
b = arr * 1000
and print each element in range(step,(N+1)*step,step).
Of course this method is not optimal since you don't now how many arrays arr you have to concatenate in order not to go out of bounds.
Hope it helped

Convert sorted array into low high array

Interview question:
Given a sorted array of this form :
1,2,3,4,5,6,7,8,9
( A better example would be 10,20,35,42,51,66,71,84,99 but let's use above one)
Convert it to the following low high form without using extra memory or a standard library
1,9,2,8,3,7,4,6,5
A low-high form means that we use the smallest followed by highest. Then we use the second smallest and second-highest.
Initially, when he asked, I had used a secondary array and used the 2 pointer approach. I kept one pointer in front and the second pointer at last . then one by one I copied left and right data to my new array and then moved left as left ++ and right as --right till they cross or become same.
After this, he asked me to do it without memory.
My approach to solving it without memory was on following lines . But it was confusing and not working
1) swap 2nd and last in **odd** (pos index 1)
1,2,3,4,5,6,7,8,9 becomes
1,9,3,4,5,6,7,8,2
then we reach even
2) swap 3rd and last in **even** (pos index 2 we are at 3 )
1,9,3,4,5,6,7,8,2 becomes (swapped 3 and 2_ )
1,9,2,4,5,6,7,8,3
and then sawp 8 and 3
1,9,2,4,5,6,7,8,3 becomes
1,9,2,4,5,6,7,3,8
3) we reach in odd (pos index 3 we are at 4 )
1,9,2,4,5,6,7,3,8
becomes
1,9,2,8,5,6,7,3,4
4) swap even 5 to last
and here it becomes wrong
Let me start by pointing out that even registers are a kind of memory. Without any 'extra' memory (other than that occupied by the sorted array, that is) we don't even have counters! That said, here goes:
Let a be an array of n > 2 positive integers sorted in ascending order, with the positions indexed from 0 to n-1.
From i = 1 to n-2, bubble-sort the sub-array ranging from position i to position n-1 (inclusive), alternatively in descending and ascending order. (Meaning that you bubble-sort in descending order if i is odd and in ascending order if it is even.)
Since to bubble-sort you only need to compare, and possibly swap, adjacent elements, you won't need 'extra' memory.
(Mind you, if you start at i = 0 and first sort in ascending order, you don't even need a to be pre-sorted.)
And one more thing: as there was no talk of it in your question, I will keep very silent on the performance of the above algorithm...
We will make n/2 passes and during each pass we will swap each element, from left to right, starting with the element at position 2k-1, with the last element. Example:
pass 1
V
1,2,3,4,5,6,7,8,9
1,9,3,4,5,6,7,8,2
1,9,2,4,5,6,7,8,3
1,9,2,3,5,6,7,8,4
1,9,2,3,4,6,7,8,5
1,9,2,3,4,5,7,8,6
1,9,2,3,4,5,6,8,7
1,9,2,3,4,5,6,7,8
pass 2
V
1,9,2,3,4,5,6,7,8
1,9,2,8,4,5,6,7,3
1,9,2,8,3,5,6,7,4
1,9,2,8,3,4,6,7,5
1,9,2,8,3,4,5,7,6
1,9,2,8,3,4,5,6,7
pass 3
V
1,9,2,8,3,4,5,6,7
1,9,2,8,3,7,5,6,4
1,9,2,8,3,7,4,6,5
1,9,2,8,3,7,4,5,6
pass 4
V
1,9,2,8,3,7,4,5,6
1,9,2,8,3,7,4,6,5
This should take O(n^2) swaps and uses no extra memory beyond the counters involved.
The loop invariant to prove is that the first 2k+1 positions are correct after iteration k of the loop.
Alright, assuming that with constant space complexity, we need to lose some of our time complexity, the following algorithm possibly works in O(n^2) time complexity.
I wrote this in python. I wrote it as quickly as possible so apologies for any syntactical errors.
# s is the array passed.
def hi_low(s):
last = len(s)
for i in range(0, last, 2):
if s[i+1] == None:
break
index_to_swap = last
index_to_be_swapped = i+1
while s[index_to_be_swapped] != s[index_to_swap]:
# write your own swap func here
swap(s[index_to_swap], s[index_to_swap-1])
index_to_swap -=1
return s
Quick explanation:
Suppose the initial list given to us is:
1 2 3 4 5 6 7 8 9
So in our program, initially,
index_to_swap = last
meaning that it is pointing to 9, and
index_to_be_swapped = i+1
is i+1, i.e one step ahead of our current loop pointer. [Also remember we're looping with a difference of 2].
So initially,
i = 0
index_to_be_swapped = 1
index_to_swap = 9
and in the inner loop what we're checking is: until the values in both of these indexes are same, we keep on swapping
swap(s[index_to_swap], s[index_to_swap-1])
so it'll look like:
# initially:
1 2 3 4 5 6 7 8 9
^ ^---index_to_swap
^-----index_to_be_swapped
# after 1 loop
1 2 3 4 5 6 7 9 8
^ ^-----index_to_swap
^----- index_to_be_swapped
... goes on until
1 9 2 3 4 5 6 7 8
^-----index_to_swap
^-----index_to_be_swapped
Now, the inner loop's job is done, and the main loop is run again with
1 9 2 3 4 5 6 7 8
^ ^---- index_to_swap
^------index_to_be_swapped
This runs until it's behind 2.
So the outer loop runs for almost n\2 times, and for each outer loop the inner loop runs for almost n\2 times in the worst case so the time complexity if n/2*n/2 = n^2/4 which is the order of n^2 i.e O(n^2).
If there are any mistakes please feel free to point it out.
Hope this helps!
It will work for any sorted array
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let i = arr[0];
let j = arr[arr.length - 1];
let k = 0;
while(k < arr.length) {
arr[k] = i;
if(arr[k+1]) arr[k+1] = j;
i++;
k += 2;
j--;
}
console.log(arr);
Explanation: Because its a sorted array, you need to know 3 things to produce your expected output.
Starting Value : let i = arr[0]
Ending Value(You can also find it with the length of array by the way): let j = arr[arr.length -1]
Length of Array: arr.length
Loop through the array and set the value like this
arr[firstIndex] = firstValue, arr[thirdIndex] = firstValue + 1 and so on..
arr[secondIndex] = lastValue, arr[fourthIndex] = lastValue - 1 and so on..
Obviously you can do the same things in a different way. But i think that's the simplest way.

Fast Algorithm For Making Change With 6 Denominations: Interview Practice

I came to a solution for this problem, but it takes O(n^2). Is it possible to do better?
Problem: Suppose we want to make change for D dollars. We have an array A with N elements. The denominations exist within the array as dollar values, but we do not know the exact denominations in advanced. However, we are given that 0 < A[j] < 125*N. The restrictions are, we only have 6 of each type of denomination and we must be able to determine if we can give change using exactly 6 total bills (we can repeat bills and assume bills come in any type, so we can have 4$ bills)..
Ex:
If A = [3,4,6,5,20,18,10,30] and D = 50. Then the algorithm returns true since 5+5+5+5+10+20.
My attempts:
I tried sorting and then dividing but then I get stuck because I am not sure how to eliminate possible choices since I do not know exactly what is in the array. Better yet, without explicitly going through in O(n^2) time, I am not sure how to for sure say that it is not possible. Is it possible to take advantage of the fact that I know I am restricted to exactly 6 bills?
To me it looks like a typical recursion problem. Lets write a function that will check if we can make change for the D dollars. For that we will take the first bill (lets say it's $3), remove it from the the D and then recursively check if we can make change for the D - 3 dollars.
We can make this solution much faster if we don't check the combinations that we have already checked. So if we already know that bills 3, 5, 10 don't fit our needs then we don't need to check the combination 5, 10, 3 either. For that we need firstly to sort the A array and then pass the number of last used bill (last_bill_id) to the check function. Inside the function we don't need to check any combinations with bills with number less than last_bill_id.
Full solution in python:
A = [3, 4, 6, 5, 20, 18, 10, 30]
D = 50
def check(counters, current_sum, depth, last_bill_id):
global A
if depth > 6: # max amount of bills is 6
return False
if depth == 6: # we used 6 bill, did we get the correct sum?
return current_sum == 0
if current_sum <= 0: # we gave too much change
return False
# current_sum > 0 and depth < 6
for i in xrange(last_bill_id, len(A)):
if counters[i] < 6:
# we can use i-th bill another time
counters[i] += 1
if check(counters, current_sum - A[i], depth + 1, i):
return True
counters[i] -= 1
return False
# init counters with zeros
counters = [0] * len(A)
# check if we can change for `D`
A = sorted(A) # sort A before the function
print 'Can make change:', check(counters, D, 0, 0)
# print bills with counters
for i, c in enumerate(counters):
if c > 0:
print '$%d x %d' % (A[i], c)
Output:
Can make change: True
$3 x 4
$18 x 1
$20 x 1
EDIT
Previous solution has complexity O(n^6). But actually we can make it even faster with memoization (or, we put it in the other way, dynamic programming). Lets sort the A array and repeat every number in it 6 times, so we'll get something like A = [3, 3, 3, 3, 3, 3, 5, 5, ...]. Now lets fill the 3D matrix M[,,], where M[bills_num, i, d] is true iff we can make change for the d dollars with bills_num bills starting in i-th position of the A array. The result will be in the cell M[6, 0, D]. This matrix has size 6 x (6 * n) x D, so we can fill it in O(6 * (6 * n) * D) == O(n * D) time (with the recursive approach similar to the solution before). Code in python:
A = [3, 4, 6, 5, 20, 18, 10, 30]
D = 50
# sort A and repeat 6 times
A = sorted(A * 6)
# create matrix M, where:
# 0 == uncomputed, 1 == True, -1 == False
arr1d = lambda x: [0] * x
arr2d = lambda x, y: [arr1d(y) for i in xrange(x)]
arr3d = lambda x, y, z: [arr2d(y, z) for i in xrange(x)]
M = arr3d(6 + 1, len(A), D + 1)
def fill_m(bills_num, start_pos, d):
global A, M
if d == 0: # can make change for 0 only with 0 bills
return True if bills_num == 0 else False
if d < 0 or bills_num <= 0 or start_pos >= len(A):
return False
if M[bills_num][start_pos][d] == 0:
# need to compute cell value
if fill_m(bills_num, start_pos + 1, d):
M[bills_num][start_pos][d] = 1
elif fill_m(bills_num - 1, start_pos + 1, d - A[start_pos]):
M[bills_num][start_pos][d] = 1
else:
M[bills_num][start_pos][d] = -1
return M[bills_num][start_pos][d] == 1
print 'Can make change for $', D, fill_m(6, 0, D)

Number of ways of partitioning an array

Given an array of n elements, a k-partitioning of the array would be to split the array in k contiguous subarrays such that the maximums of the subarrays are non-increasing. Namely max(subarray1) >= max(subarray2) >= ... >= max(subarrayK).
In how many ways can an array be partitioned into valid partitions like the ones mentioned before?
Note: k isn't given as input or anything, I mereley used it to illustrate the general case. A partition could have any size from 1 to n, we just need to find all the valid ones.
Example, the array [3, 2, 1] can be partitioned in 4 ways, you can see them below:
The valid partitions :[3, 2, 1]; [3, [2, 1]]; [[3, 2], 1]; [[3], [2], [1]].
I've found a similar problem related to linear partitioning, but I couldn't find a way to adapt the thinking to this problem. I'm pretty sure this is dynamic programming, but I haven't been able to properly identify
how to model the problem using a recurrence relation.
How would you solve this?
Call an element of the input a tail-max if it is at least as great as all elements that follow. For example, in the following input:
5 9 3 3 1 2
the following elements are tail-maxes:
5 9 3 3 1 2
^ ^ ^ ^
In a valid partition, every subarray must contain the next tail-max at or after the subarray's starting position; otherwise, the next tail-max will be the max of some later subarray, and the condition of non-increasing subarray maximums will be violated.
On the other hand, if every subarray contains the next tail-max at or after the subarray's starting position, then the partition must be valid, as the definition of a tail-max ensures that the maximum of a later subarray cannot be greater.
If we identify the tail-maxes of an array, for example
1 1 9 2 1 6 5 1
. . X . . X X X
where X means tail-max and . means not, then we can't place any subarray boundaries before the first tail-max, because if we do, the first subarray won't contain a tail-max. We can place at most one subarray boundary between a tail-max and the next; if we place more, we get a subarray that doesn't contain a tail-max. The last tail-max must be the last element of the input, so we can't place a subarray boundary after the last tail-max.
If there are m non-tail-max elements between a tail-max and the next, that gives us m+2 options: m+1 places to put an array boundary, or we can choose not to place a boundary between these elements. These factors are multiplicative.
We can make one pass from the end of the input to the start, identifying the lengths of the gaps between tail-maxes and multiplying together the appropriate factors to solve the problem in O(n) time:
def partitions(array):
tailmax = None
factor = 1
result = 1
for i in reversed(array):
if tailmax is None:
tailmax = i
continue
factor += 1
if i >= tailmax:
# i is a new tail-max.
# Multiply the result by a factor indicating how many options we
# have for placing a boundary between i and the old tail-max.
tailmax = i
result *= factor
factor = 1
return result
Update: Sorry I misunderstanding the problem. In this case, split the arrays to sub-arrays where every tails is the max element in the array, then it will work in narrow cases. e.g. [2 4 5 9 6 8 3 1] would be split to [[2 4 5 9] 6 8 9 3 1] first. Then we can freely chose range 0 - 5 to decide whether following are included. You can use an array to record the result of DP. Our goal is res[0]. We already have res[0] = res[5] + res[6] + res[7] + res[8] + res[9] + res[10] in above example and res[10] = 1
def getnum(array):
res = [-1 for x in range(len(array))]
res[0] = valueAt(array, res, 0)
return res[0]
def valueAt(array, res, i):
m = array[i]
idx = i
for index in range(i, len(array), 1):
if array[index] > m:
idx = index
m = array[index]
value = 1;
for index in range(idx + 1, len(array), 1):
if res[index] == -1:
res[index] = valueAt(array, res, index)
value = value + res[index]
return value;
Worse than the answer above in time consuming. DP always costs a lot.
Old Answer: If no duplicate elements in an array is allowed, the following way would work:
Notice that the number of sub-arrays is not depends on the values of elements if no duplicate. We can remark the number is N(n) if there is n elements in array.
The largest element must be in the first sub-arrays, other elements can be in or not in the first sub-array. Depends on whether they are in the first sub-array, the number of partitions for the remaining elements varies.
So,
N(n) = C(n-1, 1)N(n-1) + C(n-1, 2)N(n-2) + ... + C(n-1, n-1)N(0)
where C(n,k) means:
Then it can be solved by DP.
Hope this helps

Counting appropriate number of subarrays in an array excluding some specific pairs?

Let's say, I have an array like this:
1 2 3 4 5
And given pair is (2,3), then number of possible subarrays that don't have (2,3) present in them will be,,
1. 1
2. 2
3. 3
4. 4
5. 5
6. 1 2
7. 3 4
8. 4 5
9. 3 4 5
So, the answer will be 9.
Obviously, there can be more of such pairs.
Now, one method that I thought of is of O(n^2) which involves finding all such elements of maximum length n. Can I do better? Thanks!
Let's see, this adhoc pseudocode should be O(n):
array = [1 2 3 4 5]
pair = [2 3]
length = array.length
n = 0
start = 0
while (start < length)
{
# Find next pair
pair_pos = start
while (pair_pos < length) and (array[pair_pos,pair_pos+1] != pair) # (**1)
{
pair_pos++
}
# Count subarrays
n += calc_number_of_subarrays(pair_pos-start) # (**2)
# Continue after the pair
start = pair_pos+2
}
print n
Note **1: This seems to involve a loop inside the outer loop. Since every element of the array is visited exactly once, both loops together are O(n). In fact, it is probably easy to refactor this to use only one while loop.
Note **2: Given an array of length l, there are l+(l-1)+(l-2)+...+1 subarrays (including the array itself). Which is easy to calculate in O(1), there is no loop involved. c/f Euler. :)
You don't need to find which subarrays are in an array to know how many of them there are. Finding where the pair is in the array is at most 2(n-1) array operations. Then you only need to do a simple calculation with the two lengths you extract from that. The amount of subarrays in an array of length 3 is, for example, 3 + 2 + 1 = 6 = (n(n+1))/2.
The solution uses that in a given array [a, ..., p1, p2, ..., b], the amount of subarrays without the pair is the amount of subarrays for [a, ..., p1] + the amount of subarrays for [p2, ..., b]. If multiple of such pairs exist, we repeat the same trick on [p2, ..., b] as if it was the whole array.
function amount_of_subarrays ::
index := 1
amount := 0
lastmatch := 0
while length( array ) > index do
if array[index] == pair[1] then
if array[index+1] == pair[2] then
length2 := index - lastmatch
amount := amount + ((length2 * (length2 + 1)) / 2)
lastmatch := index
fi
fi
index := index + 1
od
//index is now equal to the length
length2 := index - lastmatch
amount := amount + ((length2 * (length2 + 1)) / 2)
return amount
For an array [1, 2, 3, 4, 5] with pair [2, 3], index will be 2 when the two if-statements are true. amount will be updated to 3 and lastmatch will be updated to 2. No more matches will be found, so lastmatch is 2 and index is 5. amount will be 3 + 6 = 9.

Resources