【问题标题】:TopCoder algorithm problem - how to make progress on this one?TopCoder 算法问题 - 如何在这方面取得进展?
【发布时间】:2010-07-19 21:23:12
【问题描述】:

我最近加入了 TopCoder,最近几天一直在练习室练习。我遇到了这个我似乎无法解决的问题。任何帮助将不胜感激。

问题

字符串的乘积值为 中所有数字('0'-'9')的乘积 字符串。例如,产品 “123”的值为 1 * 2 * 3 = 6。A 如果字符串被称为彩色 仅包含数字和产品 每个非空的值 连续的子串是不同的。

例如,字符串“263”有六个 子字符串:“2”、“6”、“3”、“26”、“63” 和“263”。这些产品的价值 子串是:2、6、3、2 * 6 = 12、6 * 3 = 18 和 2 * 6 * 3 = 36,分别。由于所有六种产品 值是不同的,“263”是 丰富多彩的。

另一方面,“236”不是 丰富多彩,因为它的两个 子字符串“6”和“23”具有 相同的产品价值(6 = 2 * 3)。

返回第 k 个(从 1 开始) 字典最小的彩色 长度为 n 的字符串。如果少 比 k 个长度为 n 的彩色字符串, 而是返回一个空字符串。

我的方法

我们不能将“0”和“1”作为 n 中的数字。 所有数字必须是不同的。所以首先,n 应该小于 9。(只能使用数字 2、3、4、5、6、7、8、9,每个数字只能使用一次)。

既然我们知道,我们可以从“23”(最小的 2 位彩色字符串)作为基本字符串并添加一个允许的数字(检查字符串是否仍然是彩色的,每次添加)直到我们达到长度 n。

一旦我们达到长度 n,我们就可以“玩弄”这些数字来找到 k 最小的。

我的问题

我觉得这种方法不够快。即使是这样,我应该以什么系统的方式来玩弄数字,以便我从最小的开始,通过第 k 个最小的方式?

我怎样才能用这种方法在这个问题上取得进展?还是有更聪明的方法来解决这类问题?

我不要求任何解决方案或任何东西。我只是在寻求一些线索和线索。

有些问题我可以在几秒钟内解决,有些需要几个小时的思考,有些我做不到。但我相信只需要一些练习,但如果没有人带路,我就无法取得进步。

提前致谢 =)

*顺便说一句,这个问题来自 SRM 464 DIV 2 - 500pt。问题。所有版权归 TopCoder 所有。

【问题讨论】:

  • 根据问题陈述,0 是有效数字。它只是使产品价值不明显。数字 1(一)也是有效的。它可能会或可能不会使产品价值与众不同;取决于剩余的数字。
  • @Thomas 但如果产品价值不明显,则根据定义,该数字不是“彩色”,因此不是潜在的解决方案。
  • “0”是第一个长度为1的彩色字符串。还有9个

标签: algorithm language-agnostic


【解决方案1】:

Topcoder 有一个论坛,他们在其中为每个 SRM 创建一个线程(464 是 here)。也许你的问题已经在那里回答了:)

【讨论】:

【解决方案2】:

我觉得这种方法不够快。

为什么不呢?我什至不会费心让它变得“聪明”:你有 8 位数字,每个数字最多可以使用一次。总数为 8*7 + 8*7*6 + 8*7*6*5 + ... 8*7*6*5*4*3*2*1 = 109592,这对于要运行的计算机。

按字典顺序列举所有这些,并检查每一个,看看它是否“多彩”。

【讨论】:

  • 是的,我想你是对的。当我第一次阅读这个问题时,我试图想一个不穷尽的方法,认为蛮力会花费很多时间。但是,要以“更智能”的方式做到这一点,而不产生所有可能性,可以做些什么呢?
  • 除了7!等条款是错误的。例如,一个两位数将有 8 x 7 = 56 种可能的组合,而不是 2! = 2. 你在看 8!/0! + 8!/1! + 8!/2! + ... + 8!/6!可能性。当然,这仍然足够小,可以在任何中途现代计算机上枚举 32 位整数。
  • @David -- 对。我的意思是组合不是排列......呃,它也不是组合,因为排序很重要。总之,修好了。
  • 我刚刚意识到这需要的时间比提到的要长一些。因为检查色彩需要 2^n 时间。 (8!/0!)*2^8 + (8!/1!)*2^7 + .... > 10321920 可能很多?
  • @Murat - 我很确定你可以在O(n) 中检查色彩,并且非常确定你可以在O(n^2) 中进行检查。你不需要O(2^n)
【解决方案3】:

减少搜索空间的一种方法是考虑这一点:长度为n 的字符串只有在其第一个n-1 字符给出的子字符串也是彩色的时才可以是彩色的。这个断言是正确的应该是相当明显的。

假设您有一个函数colorful(n),它返回长度为n 的所有彩色字符串的集合。您可以递归地实现它,如下所示:

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

支持函数is_colorful 可以利用作为第一个参数给出的子字符串已经知道是彩色的并且不包含附加数字的事实

然后调用colorful(n) 并选择返回集合的kth 元素。 (请注意,我们确实必须在基本情况中包含“0”和“1”,否则会给出n=1 的错误答案)

这基本上是dynamic programming 方法。我确信这可以改进——可能有一种聪明的方法来确定是否将某个数字附加到一个彩色数字上是否会使数字不再是彩色的,而无需实际执行和检查。但这肯定比 2-9 的所有可能排列检查的数字要少得多。

【讨论】:

  • +1。我认为您不允许附加一个数字,该数字是前两位数字的乘积。否则,您将拥有两个相等的产品。例如:324 => 我们不能附加8,因为8 = 2*4。我们可以附加其他所有内容。我们只需要看后面两位数,因为任何三个不同数字> 1 的乘积是> 10
  • 感谢您的回答,这很有帮助。最后一件事,我如何在 O(N) 时间内检查色彩?
  • 您的remaining_digits 中好像少了一个“4”。 (我知道,多么毫无意义的挑剔...... :))
【解决方案4】:

这是我整理的快速代码,似乎是一个有趣的问题...... 我希望我没有误解这个问题。

干杯

    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);
    }
}

【讨论】:

  • 请不要回答已接受多年前答案的旧线程。用你的精力来帮助解决当前的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 2011-05-28
  • 2019-03-16
相关资源
最近更新 更多