How many distinct expressions are possible? - algorithm

I came across the following practice problem.
You are free to put any parentheses to the expression anywhere you want and as many as you want. However it should be a valid expression after you put the parentheses. The question is how many different numbers can you make? Ex. for 1 - 2 + 3 - 4 - 5 you can get six unique values as below:
1 - 2 + 3 - 4 - 5 = -7
1 - (2 + 3) - 4 - 5 = -13
1 - (2 + 3 - 4) - 5 = -5
1 - (2 + 3 - 4 - 5) = 5
1 - 2 + 3 - (4 - 5) = 3
1 - (2 + 3) - (4 - 5) = -3
I can't seem to figure out how to have a Dynamic Programming formulation for the problem. I just started solving problems involving Dynamic Programming and can't seem to figure out how to approach this problem.
EDIT The range of numbers is 0<=N<=100 and length of expression (<=30)

Basic idea
The parentheses are basically interposed between numbers and operators, any imbalance can be fixed at the ends of the entire expression.
Possible placements of parentheses
A ( immediatetly before either operator is illegal syntax.
A ( immediately after a + is legal but pointless, since it doesn't change the order of evaluation. I'll assume we don't do this.
A ( immediately after a - is legal and important.
A ) immediately before a + is legal and important iff there was a matching ( before.
A ) immediately before a - is legal but pointless, since opening a new pair of parenthesis after the following number gives the same sign-change and more options later on, because we will have one more open pair we can close. I'll assume we don't do this either.
This means the only parentheses we actually need are opening parentheses before negative numbers and closing parentheses after positive ones. If we stick to those two, the sign the next number is multiplied with in the summation depends only on the number of open parentheses being even or odd.
This gives us the
Substructure
Parsing the state from left to right, after every number the present sub-problem can be represented as a set of pairs of
the partial sum and
the number of open parentheses.
Working out the specific example
Reading in +1:
(1, 0)
That is, there is only one solution for this sub-problem: The partial sum so far is 1 and the number of open parentheses is 0. From now on in each sub-problem I'll have one line for the pairs arising from every pair in the previous sub-problem.
Reading in -2:
(-1, 1), (-1, 0)
I.e. the partial sum is -1, but we may or may not have inserted an opening parenthesis.
Reading in +3:
(-4,1),(-4,0)
(2,0)
New in this sub-problem: We could optionally close a pair of parentheses, but only if one was open.
Reading in -4:
(0,2), (0,1)
(-8,0), (-8,1)
(-2,0), (-2,1)
Reading in -5:
(-5,2), (-5,3)
(5,1), (5,2)
(-13,0), (-13, 1)
(-3,1), (-3,2)
(-7,0), (-7,1)
(3,1), (3,2)
In the end we get the possible sums by looking only at the first element of each pair and discarding duplicates.

Related

Split array into four boxes such that sum of XOR's of the boxes is maximum

Given an array of integers which are needed to be split into four
boxes such that sum of XOR's of the boxes is maximum.
I/P -- [1,2,1,2,1,2]
O/P -- 9
Explanation: Box1--[1,2]
Box2--[1,2]
Box3--[1,2]
Box4--[]
I've tried using recursion but failed for larger test cases as the
Time Complexity is exponential. I'm expecting a solution using dynamic
programming.
def max_Xor(b1,b2,b3,b4,A,index,size):
if index == size:
return b1+b2+b3+b4
m=max(max_Xor(b1^A[index],b2,b3,b4,A,index+1,size),
max_Xor(b1,b2^A[index],b3,b4,A,index+1,size),
max_Xor(b1,b2,b3^A[index],b4,A,index+1,size),
max_Xor(b1,b2,b3,b4^A[index],A,index+1,size))
return m
def main():
print(max_Xor(0,0,0,0,A,0,len(A)))
Thanks in Advance!!
There are several things to speed up your algorithm:
Build in some start-up logic: it doesn't make sense to put anything into box 3 until boxes 1 & 2 are differentiated. In fact, you should generally have an order of precedence to keep you from repeating configurations in a different order.
Memoize your logic; this avoids repeating computations.
For large cases, take advantage of what value algebra exists.
This last item may turn out to be the biggest saving. For instance, if your longest numbers include several 5-bit and 4-bit numbers, it makes no sense to consider shorter numbers until you've placed those decently in the boxes, gaining maximum advantage for the leading bits. With only four boxes, you cannot have a num from 3-bit numbers that dominates a single misplaced 5-bit number.
Your goal is to place an odd number of 5-bit numbers into 3 or all 4 boxes; against this, check only whether this "pessimizes" bit 4 of the remaining numbers. For instance, given six 5-digit numbers (range 16-31) and a handful of small ones (0-7), your first consideration is to handle only combinations that partition the 5-digit numbers by (3, 1, 1, 1), as this leaves that valuable 5-bit turned on in each set.
With a more even mixture of values in your input, you'll also need to consider how to distribute the 4-bits for a similar "keep it odd" heuristic. Note that, as you work from largest to smallest, you need worry only about keeping it odd, and watching the following bit.
These techniques should let you prune your recursion enough to finish in time.
We can use Dynamic programming here to break the problem into smaller sets then store their result in a table. Then use already stored result to calculate answer for bigger set.
For example:
Input -- [1,2,1,2,1,2]
We need to divide the array consecutively into 4 boxed such that sum of XOR of all boxes is maximised.
Lets take your test case, break the problem into smaller sets and start solving for smaller set.
box = 1, num = [1,2,1,2,1,2]
ans = 1 3 2 0 1 3
Since we only have one box so all numbers will go into this box. We will store this answer into a table. Lets call the matrix as DP.
DP[1] = [1 3 2 0 1 3]
DP[i][j] stores answer for distributing 0-j numbers to i boxes.
now lets take the case where we have two boxes and we will take numbers one by one.
num = [1] since we only have one number it will go into the first box.
DP[1][0] = 1
Lets add another number.
num = [1 2]
now there can be two ways to put this new number into the box.
case 1: 2 will go to the First box. Since we already have answer
for both numbers in one box. we will just use that.
answer = DP[0][1] + 0 (Second box is empty)
case 2: 2 will go to second box.
answer = DP[0][0] + 2 (only 2 is present in the second box)
Maximum of the two cases will be stored in DP[1][1].
DP[1][1] = max(3+0, 1+2) = 3.
Now for num = [1 2 1].
Again for new number we have three cases.
box1 = [1 2 1], box2 = [], DP[0][2] + 0
box1 = [1 2], box2 = [1], DP[0][1] + 1
box1 = [1 ], box2 = [2 1], DP[0][0] + 2^1
Maximum of these three will be answer for DP[1][2].
Similarly we can find answer of num = [1 2 1 2 1 2] box = 4
1 3 2 0 1 3
1 3 4 6 5 3
1 3 4 6 7 9
1 3 4 6 7 9
Also note that a xor b xor a = b. you can use this property to get xor of a segment of an array in constant time as suggested in comments.
This way you can break the problem in smaller subset and use smaller set answer to compute for the bigger ones. Hope this helps. After understanding the concept you can go ahead and implement it with better time than exponential.
I would go bit by bit from the highest bit to the lowest bit. For every bit, try all combinations that distribute the still unused numbers that have that bit set so that an odd number of them is in each box, nothing else matters. Pick the best path overall. One issue that complicates this greedy method is that two boxes with a lower bit set can equal one box with the next higher bit set.
Alternatively, memoize the boxes state in your recursion as an ordered tuple.

How to calculate how many bit sequences of size n with k bits set and c changes of bit values exist?

We know that calculating the number of n-length bit sequences with k bits set is equal to C(n,k)=n!/(k!(n-k)!)*.
But I've recently asked myself how can you think about this problem once another condition is set: The number of bit value changes. For instance, for n=4 and k=2 we have 6 solutions:
1-0011
2-0101
3-0110
4-1001
5-1010
6-1100
Now suppose we only want to get the sequences with two changes in bit values. Now there are only two solutions:
1-0110 (begins with 0, changes to 1, than changes to 0 after).
2-1001 (begins with 1, changes to 0, than changes to 1 after).
How can I quickly calculate the number of solutions(without generating every combination and counting)? I think one could count the initial bit as a change without changing the answer too much, so feel free to do it.
Extra question: Given a combination with k bits set and c number of bit changes, what is the quickest way to generate the next combination with the same amount of k bits set and c number of bit changes?
This is a balls-and-urns problem. You start with a sequence of alternating 0s and 1s with the required number of bit changes, and then you place the remaining 0s and 1s into the urns.
Example: n=20, k=8, c=4.
Consider the case where the bistring starts with 0. Start with (c+1) alternating bits, to get your c changes:
01010
At this point you still need to place 9 0s and 6 1s. Let's place the 0s first. How many ways can we place the 9 remaining 0s, without adding any bit changes? There are 3 "urns" to place the "balls" (0s):
0 ... 1 0 ... 1 0 ...
^ ^ ^
There are (9+3-1) choose 3 ways of placing 9 balls into 3 urns.
Once the 0s are placed, we also need to place the 1s. By similar reasoning, we have 6 balls (1s) to place in 2 urns, which can be done in (6+2-1) choose 2 ways.
Since the arrangement of 0s and 1s are independent, we multiply the results: there are ((9+3-1) choose 3) * ((6+2-1) choose 2) ways for a length-20 bitstring with 8 1s to have 4 bit changes, assuming you start with 0.
You still need to add the remaining case (starting with 1, so the first step results in 10101), which can be solved in exactly the same way.
Suppose we have a row of n indistinguishable objects, say red balls. How many ways can we divide them into k non-empty groups? That's pretty easy, right? The first group starts with the first object, and every other group has to start at some different object. So we can construct a partition by choosing the first object and k-1 of the n-1 remaining objects, which we can do in C(n-1, k-1) different ways.
Now suppose we have another row of m indistinguishable objects, say blue balls, and we want to divide them into j groups. But that's exactly the same problem, and the solution must be C(m-1, j-1).
OK, now suppose we want to construct a row of objects, of which n are red and m are blue, in which there are a total of c groups alternating between red and blue. Now, there are two possibilities:
The row will start with a red ball. If c is even, then there will be c/2 red groups interleaved with c/2 blue groups. If c is odd, there will be one more red group than blue group, so there will be ceil(c/2) red groups and floor(c/2) blue groups. (If c is even then both floor(c/2) and ceil(c/2) are exactly c/2. So we can use the floor and ceil formulas in both cases.)
In any event, we can divide the red balls into groups and the blue balls into groups independently, and then interleave them. So there are C(n - 1, ceil(c/2) - 1) × C(m - 1, floor(c/2) - 1) possible arrangements.
The row will start with a blue ball. Exactly the same analysis applies, except that n and m are reversed.
So the total number of arrangements is:
C(n - 1, ceil(c/2) - 1) × C(m - 1, floor(c/2) - 1) +
C(n - 1, floor(c/2) - 1) × C(m - 1, ceil(c/2) - 1)
This is just a rewriting of your problem, which had k ones and n-k zeros, with c-1 transitions (which leads to c groups). I'll leave the remaining algebra step to the reader (as well as the simplification for odd group counts).

SPOJ "abs(a-b) I" Wrong Answer issue

This is my approach for the problem statement http://www.spoj.com/problems/ABSP1/ - please check if there is any corner case on which my code is falling because according to my test cases it is giving correct answer.
Problem Statement:
You are given an array of N numbers in non-decreasing order. You have
to answer the summation of the absolute difference of all distinct
pairs in the given array.
scanf("%d",&TotalElements);
for(i=0;i<TotalElements;i++)
scanf("%d",&Array[i]);
FirstSum=TotalSum=0;
for(i=0;i<TotalElements;i++)
FirstSum+=abs(Array[i]-Array[0]);
TotalSum=FirstSum;
SumTillNow=Array[0];
for(i=1;i<TotalElements;i++){
Difference=Array[i]-Array[0];
NextSum=FirstSum-Difference*(TotalElements-i)-SumTillNow+(i)*Array[0];
TotalSum+=NextSum;
SumTillNow+=Array[i];
}
printf("%lld\n",TotalSum);
According to me your logic is fine.
I think the Wrong Answer may be related to the types of variables that you have used.
Let's look at this statement in your code closely.
NextSum=FirstSum-Difference*(TotalElements-i)-SumTillNow+(i)*Array[0];
Here FirstSum = summation( A[k] - A[0] ) for all k > 0
= summation( A[k] ) - N*A[0]
Difference = A[i] - A[0].
Hence the statement becomes:
NextSum = summation( A[k] ) - N*A[0] - (A[i] - A[0])*(N-i) - summation( A[j] ){j<i} + i*A[0]
= summation( A[m] ){m >= i} - A[i]*(N-i)
This sum takes into account all the absolute differences between A[i] and A[m] where m > i. This should give you the correct answer.
Also, there is a simpler way to carry out the summation. I include it for completeness.
If you look at the number of times each A[i] will appear in the sum of absolute differences,
"-A[0]" will appear N-1 times
"-A[1]" will appear N-2 times and A[1] will appear 1 time. Hence net effect will be (1 - (N-2))*A[1].
Similarly A[i]th term shall be (i - (N-i-1))*A[i] = (2i + 1 - N)*A[i].
You can calculate the series accordingly.
The problem setter doesn't seem to have enough experience. Here's why:
He says distinct pairs but it doesn't seem like it. Maybe what he meant to say was UNORDERED pairs.
The test data doesn't conform to the constraints. Asserts on input data verify this. Use 64 bit signed integers for input.
Make changes to your program keeping these two point in mind (especially point 2) and it should get accepted.
One things come to mind. SPOJ says:
Do you know what distinct pair means? Suppose you have an array of 3 elements: 3 5 6
Then all the distinct pairs are:
3 5
3 6
5 6
If you instead had the array of 3 elements: 3 3 4 then how many distinct pairs do you have? Similarly for: 3 3 3. SPOJ doesn't exactly clarify what a distinct pair is but I assume two pairs a1 a2 and b1 b2 are only distinct if a1 <> a2 or b1 <> b2. If this is the case then you will need to filter out all duplicates in the array.

Algorithm to find streets and same kind in a hand

This is actually a Mahjong-based question, but a Romme- or even Poker-based background will also easily suffice to understand.
In Mahjong 14 tiles (tiles are like cards in Poker) are arranged to 4 sets and a pair. A street ("123") always uses exactly 3 tiles, not more and not less. A set of the same kind ("111") consists of exactly 3 tiles, too. This leads to a sum of 3 * 4 + 2 = 14 tiles.
There are various exceptions like Kan or Thirteen Orphans that are not relevant here. Colors and value ranges (1-9) are also not important for the algorithm.
I'm trying to determine if a hand can be arranged in the way described above. For certain reasons it should not only be able to deal with 14 but any number of tiles. (The next step would be to find how many tiles need to be exchanged to be able to complete a hand.)
Examples:
11122233344455 - easy enough, 4 sets and a pair.
12345555678999 - 123, 456, 789, 555, 99
11223378888999 - 123, 123, 789, 888, 99
11223344556789 - not a valid hand
My current and not yet implemented idea is this: For each tile, try to make a) a street b) a set c) a pair. If none works (or there would be > 1 pair), go back to the previous iteration and try the next option, or, if this is the highest level, fail. Else, remove the used tiles from the list of remaining tiles and continue with the next iteration.
I believe this approach works and would also be reasonably fast (performance is a "nice bonus"), but I'm interested in your opinion on this. Can you think of alternate solutions? Does this or something similar already exist?
(Not homework, I'm learning to play Mahjong.)
The sum of the values in a street and in a set can be divided by 3:
n + n + n = 3n
(n-1) + n + (n + 1) = 3n
So, if you add together all the numbers in a solved hand, you would get a number of the form 3N + 2M where M is the value of the tile in the pair. The remainder of the division by three (total % 3) is, for each value of M :
total % 3 = 0 -> M = {3,6,9}
total % 3 = 1 -> M = {2,5,8}
total % 3 = 2 -> M = {1,4,7}
So, instead of having to test nine possible pairs, you only have to try three based on a simple addition. For each possible pair, remove two tiles with that value and move on to the next step of the algorithm to determine if it's possible.
Once you have this, start with the lowest value. If there are less than three tiles with that value, it means they're necessarily the first element of a street, so remove that street (if you can't because tiles n+1 or n+2 are missing, it means the hand is not valid) and move on to the next lowest value.
If there are at least three tiles with the lowest value, remove them as a set (if you ask "what if they were part of a street?" consider that if they were, then there are also three of tile n+1 and three of tile n+2, which can also be turned into sets) and continue.
If you reach an empty hand, the hand is valid.
For example, for your invalid hand the total is 60, which means M = {3,6,9}:
Remove the 3: 112244556789
- Start with 1: there are less than three, so remove a street
-> impossible: 123 needs a 3
Remove the 6: impossible, there is only one
Remove the 9: impossible, there is only one
With your second example 12345555678999, the total is 78, which means M = {3,6,9}:
Remove the 3: impossible, there is only one
Remove the 6: impossible, there is only one
Remove the 9: 123455556789
- Start with 1: there is only one, so remove a street
-> 455556789
- Start with 4: there is only one, so remove a street
-> 555789
- Start with 5: there are three, so remove a set
-> 789
- Start with 7: there is only one, so remove a street
-> empty : hand is valid, removals were [99] [123] [456] [555] [789]
Your third example 11223378888999 also has a total of 78, which causes backtracking:
Remove the 3: 11227888899
- Start with 1: there are less than three, so remove a street
-> impossible: 123 needs a 3
Remove the 6: impossible, there are none
Remove the 9: 112233788889
- Start with 1: there are less than three, so remove streets
-> 788889
- Start with 7: there is only one, so remove a street
-> 888
- Start with 8: there are three, so remove a set
-> empty, hand is valid, removals were : [99] [123] [123] [789] [888]
There is a special case that you need to do some re-work to get it right. This happens when there is a run-of-three and a pair with the same value (but in different suit).
Let b denates bamboo, c donates character, and d donates dot, try this hand:
b2,b3,b4,b5,b6,b7,c4,c4,c4,d4,d4,d6,d7,d8
d4,d4 should serve as the pair, and c4,c4,c4 should serve as the run-of-3 set.
But because the 3 "c4" tiles appear before the 2 d4 tiless, the first 2 c4 tiles will be picked up as the pair, leaving an orphan c4 and 2 d4s, and these 3 tiles won't form a valid set.
In this case, you'll need to "return" the 2 c4 tiles back to the hand (and keep the hand sorted), and search for next tile that meets the criteria (value == 4). To do that you'll need to make the code "remember" that it had tried c4 so in next iteration it should skip c4 and looks for other tiles with value == 4. The code will be a bit messy, but doable.
I would break it down into 2 steps.
Figure out possible combinations. I think exhaustive checking is feasible with these numbers. The result of this step is a list of combinations, where each combination has a type (set, street, or pair) and a pattern with the cards used (could be a bitmap).
With the previous information, determine possible collections of combinations. This is where a bitmap would come in handy. Using bitwise operators, you could see overlaps in usage of the same tile for different combinators.
You could also do a step 1.5 where you just check to see if enough of each type is available. This step and step 2 would be where you would be able to create a general algorithm. The first step would be the same for all numbers of tiles and possible combinations quickly.

Algorithm to count the number of valid blocks in a permutation [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Finding sorted sub-sequences in a permutation
Given an array A which holds a permutation of 1,2,...,n. A sub-block A[i..j]
of an array A is called a valid block if all the numbers appearing in A[i..j]
are consecutive numbers (may not be in order).
Given an array A= [ 7 3 4 1 2 6 5 8] the valid blocks are [3 4], [1,2], [6,5],
[3 4 1 2], [3 4 1 2 6 5], [7 3 4 1 2 6 5], [7 3 4 1 2 6 5 8]
So the count for above permutation is 7.
Give an O( n log n) algorithm to count the number of valid blocks.
Ok, I am down to 1 rep because I put 200 bounty on a related question: Finding sorted sub-sequences in a permutation
so I cannot leave comments for a while.
I have an idea:
1) Locate all permutation groups. They are: (78), (34), (12), (65). Unlike in group theory, their order and position, and whether they are adjacent matters. So, a group (78) can be represented as a structure (7, 8, false), while (34) would be (3,4,true). I am using Python's notation for tuples, but it is actually might be better to use a whole class for the group. Here true or false means contiguous or not. Two groups are "adjacent" if (max(gp1) == min(gp2) + 1 or max(gp2) == min(gp1) + 1) and contigous(gp1) and contiguos(gp2). This is not the only condition, for union(gp1, gp2) to be contiguous, because (14) and (23) combine into (14) nicely. This is a great question for algo class homework, but a terrible one for interview. I suspect this is homework.
Just some thoughts:
At first sight, this sounds impossible: a fully sorted array would have O(n2) valid sub-blocks.
So, you would need to count more than one valid sub-block at a time. Checking the validity of a sub-block is O(n). Checking whether a sub-block is fully sorted is O(n) as well. A fully sorted sub-block contains n·(n - 1)/2 valid sub-blocks, which you can count without further breaking this sub-block up.
Now, the entire array is obviously always valid. For a divide-and-conquer approach, you would need to break this up. There are two conceivable breaking points: the location of the highest element, and that of the lowest element. If you break the array into two at one of these points, including the extremum in the part that contains the second-to-extreme element, there cannot be a valid sub-block crossing this break-point.
By always choosing the extremum that produces a more even split, this should work quite well (average O(n log n)) for "random" arrays. However, I can see problems when your input is something like (1 5 2 6 3 7 4 8), which seems to produce O(n2) behaviour. (1 4 7 2 5 8 3 6 9) would be similar (I hope you see the pattern). I currently see no trick to catch this kind of worse case, but it seems that it requires other splitting techniques.
This question does involve a bit of a "math trick" but it's fairly straight forward once you get it. However, the rest of my solution won't fit the O(n log n) criteria.
The math portion:
For any two consecutive numbers their sum is 2k+1 where k is the smallest element. For three it is 3k+3, 4 : 4k+6 and for N such numbers it is Nk + sum(1,N-1). Hence, you need two steps which can be done simultaneously:
Create the sum of all the sub-arrays.
Determine the smallest element of a sub-array.
The dynamic programming portion
Build two tables using the results of the previous row's entries to build each successive row's entries. Unfortunately, I'm totally wrong as this would still necessitate n^2 sub-array checks. Ugh!
My proposition
STEP = 2 // amount of examed number
B [0,0,0,0,0,0,0,0]
B [1,1,0,0,0,0,0,0]
VALID(A,B) - if not valid move one
B [0,1,1,0,0,0,0,0]
VALID(A,B) - if valid move one and step
B [0,0,0,1,1,0,0,0]
VALID (A,B)
B [0,0,0,0,0,1,1,0]
STEP = 3
B [1,1,1,0,0,0,0,0] not ok
B [0,1,1,1,0,0,0,0] ok
B [0,0,0,0,1,1,1,0] not ok
STEP = 4
B [1,1,1,1,0,0,0,0] not ok
B [0,1,1,1,1,0,0,0] ok
.....
CON <- 0
STEP <- 2
i <- 0
j <- 0
WHILE(STEP <= LEN(A)) DO
j <- STEP
WHILE(STEP <= LEN(A) - j) DO
IF(VALID(A,i,j)) DO
CON <- CON + 1
i <- j + 1
j <- j + STEP
ELSE
i <- i + 1
j <- j + 1
END
END
STEP <- STEP + 1
END
The valid method check that all elements are consecutive
Never tested but, might be ok
The original array doesn't contain duplicates so must itself be a consecutive block. Lets call this block (1 ~ n). We can test to see whether block (2 ~ n) is consecutive by checking if the first element is 1 or n which is O(1). Likewise we can test block (1 ~ n-1) by checking whether the last element is 1 or n.
I can't quite mould this into a solution that works but maybe it will help someone along...
Like everybody else, I'm just throwing this out ... it works for the single example below, but YMMV!
The idea is to count the number of illegal sub-blocks, and subtract this from the total possible number. We count the illegal ones by examining each array element in turn and ruling out sub-blocks that include the element but not its predecessor or successor.
Foreach i in [1,N], compute B[A[i]] = i.
Let Count = the total number of sub-blocks with length>1, which is N-choose-2 (one for each possible combination of starting and ending index).
Foreach i, consider A[i]. Ignoring edge cases, let x=A[i]-1, and let y=A[i]+1. A[i] cannot participate in any sub-block that does not include x or y. Let iX=B[x] and iY=B[y]. There are several cases to be treated independently here. The general case is that iX<i<iY<i. In this case, we can eliminate the sub-block A[iX+1 .. iY-1] and all intervening blocks containing i. There are (i - iX + 1) * (iY - i + 1) such sub-blocks, so call this number Eliminated. (Other cases left as an exercise for the reader, as are those edge cases.) Set Count = Count - Eliminated.
Return Count.
The total cost appears to be N * (cost of step 2) = O(N).
WRINKLE: In step 2, we must be careful not to eliminate each sub-interval more than once. We can accomplish this by only eliminating sub-intervals that lie fully or partly to the right of position i.
Example:
A = [1, 3, 2, 4]
B = [1, 3, 2, 4]
Initial count = (4*3)/2 = 6
i=1: A[i]=1, so need sub-blocks with 2 in them. We can eliminate [1,3] from consideration. Eliminated = 1, Count -> 5.
i=2: A[i]=3, so need sub-blocks with 2 or 4 in them. This rules out [1,3] but we already accounted for it when looking right from i=1. Eliminated = 0.
i=3: A[i] = 2, so need sub-blocks with [1] or [3] in them. We can eliminate [2,4] from consideration. Eliminated = 1, Count -> 4.
i=4: A[i] = 4, so we need sub-blocks with [3] in them. This rules out [2,4] but we already accounted for it when looking right from i=3. Eliminated = 0.
Final Count = 4, corresponding to the sub-blocks [1,3,2,4], [1,3,2], [3,2,4] and [3,2].
(This is an attempt to do this N.log(N) worst case. Unfortunately it's wrong -- it sometimes undercounts. It incorrectly assumes you can find all the blocks by looking at only adjacent pairs of smaller valid blocks. In fact you have to look at triplets, quadruples, etc, to get all the larger blocks.)
You do it with a struct that represents a subblock and a queue for subblocks.
struct
c_subblock
{
int index ; /* index into original array, head of subblock */
int width ; /* width of subblock > 0 */
int lo_value;
c_subblock * p_above ; /* null or subblock above with same index */
};
Alloc an array of subblocks the same size as the original array, and init each subblock to have exactly one item in it. Add them to the queue as you go. If you start with array [ 7 3 4 1 2 6 5 8 ] you will end up with a queue like this:
queue: ( [7,7] [3,3] [4,4] [1,1] [2,2] [6,6] [5,5] [8,8] )
The { index, width, lo_value, p_above } values for subbblock [7,7] will be { 0, 1, 7, null }.
Now it's easy. Forgive the c-ish pseudo-code.
loop {
c_subblock * const p_left = Pop subblock from queue.
int const right_index = p_left.index + p_left.width;
if ( right_index < length original array ) {
// Find adjacent subblock on the right.
// To do this you'll need the original array of length-1 subblocks.
c_subblock const * p_right = array_basic_subblocks[ right_index ];
do {
Check the left/right subblocks to see if the two merged are also a subblock.
If they are add a new merged subblock to the end of the queue.
p_right = p_right.p_above;
}
while ( p_right );
}
}
This will find them all I think. It's usually O(N log(N)), but it'll be O(N^2) for a fully sorted or anti-sorted list. I think there's an answer to this though -- when you build the original array of subblocks you look for sorted and anti-sorted sequences and add them as the base-level subblocks. If you are keeping a count increment it by (width * (width + 1))/2 for the base-level. That'll give you the count INCLUDING all the 1-length subblocks.
After that just use the loop above, popping and pushing the queue. If you're counting you'll have to have a multiplier on both the left and right subblocks and multiply these together to calculate the increment. The multiplier is the width of the leftmost (for p_left) or rightmost (for p_right) base-level subblock.
Hope this is clear and not too buggy. I'm just banging it out, so it may even be wrong.
[Later note. This doesn't work after all. See note below.]

Resources