TopCoder algorithm problem - how to make progress on this one?
I've recently joined TopCoder and have been practicing in the Practice Rooms for the last few days. I came across this problem which I cant seem to solve. Any help will be appreciated.
The problem
The product value of a string is the product of all the digits ('0'-'9') in the string. For example, the product value of "123" is 1 * 2 * 3 = 6. A string is called colorful if it contains only digits and the product value of each of its nonempty contiguous substrings is distinct.
For example, the string "263" has six substrings: "2", "6", "3", "26", "63" and "263". The product values of these substrings are: 2, 6, 3, 2 * 6 = 12, 6 * 3 = 18 and 2 * 6 * 3 = 36, respectively. Since all six product values are distinct, "263" is colorful.
On the other hand, "236" is not colorful because two of its substrings, "6" and "23", have the same product value (6 = 2 * 3).
Return the k-th (1-based) lexicographically smallest colorful string of length n. If there are less than k colo开发者_高级运维rful strings of length n, return an empty string instead.
My approach
We can't have '0' and '1' as digits in n. All digits must be distinct. So to begin with, n should be smaller than 9. (only the digits 2, 3, 4, 5, 6, 7, 8, 9 can be used, each of them only once).
Since we know that, we can start with "23" (the smallest 2-digit colorful string) as the base string and add one of the allowed digits (check if the string is still colorful or not, on each addition) until we reach length n.
Once we reach length n, we can "play around" with the digits to find the k-smallest.
My question
I feel like this approach will not be fast enough. Even if it is, in what systematic way should I play around with the digits, so that I start from the smallest and make my way through the kth-smallest?
How can I make progress on this problem with this approach? Or are there smarter ways to follow in these kind of problems?
I'm not asking for any solutions or anything. I'm just asking for some clues and some lead.
Some problems I solve in seconds, some take hours of thinking and some like this I can't do it. But I believe all it takes is some practice, but I cannot make progress without someone leading the way.
Thanks in advance =)
*by the way, this question is from SRM 464 DIV 2 - 500pt. problem. All copyright goes to TopCoder.
Topcoder has a forum in which they create a thread for each SRM (464 is here). Maybe your question is already answered there :)
I feel like this approach will not be fast enough.
Why not? I wouldn't even bother being "smart" about it: You have 8 digits, each of which can be used at most once. This has a total count of 8*7 + 8*7*6 + 8*7*6*5 + ... 8*7*6*5*4*3*2*1 = 109592, which is quick for a computer to run through.
Enumerate all of these in lexicographical order, and check each one to see if it's "colorful" or not.
One way to reduce the search space is to consider this: A string of length n
can be colorful only if the substring given by its first n-1
characters is also colorful. That this assertion is true should be fairly obvious.
Suppose you have a function colorful(n)
which returns the set of all colorful strings of length n
. You could implement it recursively, like this:
colorful(n):
if n = 1:
return { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }
def colorful_subs = colorful(n-1)
def colorfuls
for each sub in colorful_subs:
remaining_digits = { 2, 3, 4, 5, 6, 7, 8, 9 } - digits_in(sub)
for each digit in remaining_digits:
if is_colorful(sub, digit):
colorfuls += (sub + digit)
return colorfuls
And the supporting function is_colorful
can take advantage of the fact that the substring given as the first argument is already known to be colorful and to not contain the appended digit.
Then call colorful(n)
and select the k
th element of the returned set. (note that we do have to include "0" and "1" in the base case, otherwise it would give the wrong answer for n
=1)
This is basically a dynamic programming approach. I'm sure this could be improved -- there might be a clever way to figure out if appending a certain digit to a colorful number would make the number no longer colorful without actually doing it and checking. But this certainly does check considerably fewer numbers than all of the possible permutations of 2-9.
Here's a quick a code I put together, seemed like a fun question... I hope I didn't misunderstand the problem.
Cheers
public class Colorful {
/**
* Find the k-th colorful number that has n digits
* @param n The number of digits
* @param k The k-th colorful position
* @return The colorful number
*/
public static String findColorfulNumber(int n, int k) {
int start=(int) Math.pow(10, n-1);
int end=(int) Math.pow(10, n);
Stack<String> colorfulNumbers=new Stack<String>();
for(int i=start;i<end;i++){
String currentNumber=i+"";
if(isColorful(currentNumber)){
colorfulNumbers.push(currentNumber);
if(colorfulNumbers.size()==k)
break;
}
}
return colorfulNumbers.size()==k?"":colorfulNumbers.pop();
}
/**
* Checks if a given number is colorful
* @param number The number to check
* @return Returns <code>true</code> if the number is colorful, <code>false</code> otherwise
*/
private static boolean isColorful(String number) {
char[] numberAsArray = number.toCharArray();
Set<Integer> uniqueProducts=new LinkedHashSet<Integer>();
return generateUniqueNumbers(numberAsArray,1,uniqueProducts);
}
/**
* Recursive function that checks whether a number is colorful or not
* @param numberAsArray The number as an array
* @param charCount The sequence size of a number of characters to check at a given recursive iteration, starts from 0 ends at array length...
* @param uniqueProducts The set of unique products computed until current iteration
* @return
*/
private static boolean generateUniqueNumbers(char[] numberAsArray, int charCount,
Set<Integer> uniqueProducts) {
if(charCount>numberAsArray.length)
return true;
for(int i=0;(i+charCount-1)<numberAsArray.length;i++){
int product=1;
for(int j=0;j<charCount;j++){
product=product*Integer.parseInt(new String(numberAsArray[i+j]+""));
}
if(!uniqueProducts.add(product))
return false;
}
return generateUniqueNumbers(numberAsArray,charCount+1,uniqueProducts);
}
}
精彩评论