Problem Statement
The Price Is Right is a television game show. In the final round of competition, the contestant is shown the prizes which he can win. To win everything, he must make an educated guess and arrange the prizes in increasing order of price.
Once the contestant has completed ordering prizes, the host begins to reveal the price of each prize in any order that he wishes. To make the show more interesting however, the host reveals prices in such a way that as many prices are revealed as possible before an error in the order is revealed.
Each element in prices represents the price of a prize. The order of prices represents what the contestant thought the order was when arranging prices.
Given a int[] of prices as ordered by the contestant, return a int[] with two elements. The first element should be the maximum possible number of prices revealed before the order of prices is broken, while the second element should be the total number of ways of achieving that maximum number.
For example, prices = {30, 10, 20, 40, 50}
The host could reveal the following prices: 30 * * 40 50. The next price revealed (either 10 or 20) will cause an error in the ordering to be revealed. In this case, 3 prices were revealed. Alternatively, the host could reveal the following prices: * 10 20 40 50. Once again, the next price revealed will cause an error in the ordering to be revealed. However, in this case, 4 prices were revealed and thus the host would prefer to reveal the prices this way. Note that there is only 1 way of revealing 4 prices. The method should return {4,1}.
Definition
Class:
ThePriceIsRight
Method:
howManyReveals
Parameters:
int[]
Returns:
int[]
Method signature:
int[] howManyReveals(int[] prices)
(be sure your method is public)
Notes
-
The host DOES NOT work out any intermediate deductions. He reveals prices until the sequence order is broken. See examples 5 and 6.
Constraints
-
prices will have between 1 and 50 elements inclusive.
-
prices will not have any repeated elements.
-
each element in prices will be between 1 and 1000000 inclusive.
Examples
0)
{30,10,20,40,50}
Returns: { 4, 1 }
See above.
1)
{39,88,67,5,69,87,82,64,58,61}
Returns: { 4, 2 }
The maximum number of prices that can be revealed is 4, and there are 2 ways of achieving it. The host could either reveal 39 * 67 * 69 87 * * * * or 39 * 67 * 69 * 82 * * *. The method should return {4,2}.
2)
{1,2,3,4,5,6,7,8,9,10}
Returns: { 10, 1 }
3)
{10,9,8,7,6,5,4,3,2,1}
Returns: { 1, 10 }
4)
{29,31,73,70,14,5,6,34,53,30,15,86}
Returns: { 5, 2 }
The host could either reveal 29 31 * * * * * 34 53 * * 86 or * * * * * 5 6 34 53 * * 86. The method should return {5,2}
5)
{100,99,1,2,3}
Returns: { 3, 1 }
In theory, because elements in prices are at least 1 (due to constraints), it is enough to reveal any of 1, 2 or 3 to know that the sequence of prices is broken. However, the host DOES NOT make these intermediate deductions and will reveal * * 1 2 3.
6)
{10,20,11,12}
Returns: { 3, 1 }
In theory, because there can be no price between 10 and 11, it is enough to reveal both 10 and 11 to know that the sequence of prices is broken. However, the host DOES NOT make these intermediate deductions and will reveal 10 * 11 12.
This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.
It should not take long to realize that this is the longest increasing subsequence problem. Intuitively, we could produce all possible sequences, find all increasing sequences, and then find the longest of those sequences. However, this is not a very good idea, because the number of sequences we need to consider for input of size n is 2^n - 1. Since n can be as high as 50, such a solution would definitely time-out. Recursion is another way to solve this problem, but as many coders found - it also timed-out.
So how do we solve this problem? Well, we use the power of dynamic programming of course. We begin by creating two auxiliary arrays S and L. S[i] will store the longest increasing subsequence that ends with prices[i], while L[i] will store the total number of ways of achieving S[i].
We can notice a recurrence relationship:
The longest increasing subsequence ending at prices[i] can be formed by appending it to the longest increasing subsequence to the left of i that ends on a number smaller than prices[i].
We also notice the following:
The total number of ways of achieving the longest increasing subsequence ending at prices[i] is equal to the sum of the total number of ways of achieving the longest increasing subsequence ending at prices[j], where j<i and prices[j] < prices[i].
Based on the above relationships we can derive the following pseudo-code:
initialize int[] out to {0,0}
for all i<prices.length
initialize temp to 0
for all k<i
if prices[k]<prices[i] then temp = Max{temp, S[k]}
for all k<i
if S[k] == temp and prices[k]<prices[i] then increment L[i] by L[k]
if L[i] is still 0 then L[i] = 1
S[i] = 1 + temp
out[0] = Max{out[0], S[i]}
for all i<prices.length
if S[i] == out[0] then increment out[1] by L[i]
return out
To compute each S[i] value we must make (i-1) comparisons. Thus, the time complexity of this algorithm is O(n^2). By using advanced data structures we can improve the complexity to O(n*log(n)). Surprisingly, this problem has parallels with real-world applications. The same algorithm is used for finding common subsequences in DNA strands, and is closely related to spelling correction algorithms.
Code
using System;
using System.Text;
using System.Collections.Generic;
public class ThePriceIsRight
{
public int[] howManyReveals(int[] prices)
{
int n = prices.Length;
if (n == 1) return new int[] { 1, 1 };
int[] st = new int[n];
int[] cnt = new int[n];
st[0] = 1;
cnt[0] = 1;
for (int i = 1; i < n; ++i)
{
for (int j = 0; j < i; ++j)
{
st[i] = Math.Max(st[i], prices[j] < prices[i] ? st[j] + 1 : 1);
}
if (st[i] == 1) cnt[i] = 1;
else
{
for (int j = 0; j < i; ++j)
{
if (prices[i] > prices[j] && st[i] == st[j] + 1) cnt[i] += cnt[j];
}
}
}
int max = 0;
for (int i = 1; i < n; ++i)
{
max = Math.Max(st[i], max);
}
int ct = 0;
for (int i = 0; i < n; ++i)
{
if (st[i] == max) ct += cnt[i];
}
return new int[2] { max, ct };
}
}
// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003] Modified for C# by ysn
// Powered by CodeProcessor