【问题标题】:Given a number, find whether it is brilliant or not给定一个数字,判断它是否出色
【发布时间】:2023-03-14 08:31:01
【问题描述】:

这是一个编程难题,类似于:“如果一个数字的子字符串的所有数字的乘积都具有唯一值,则该数字被认为是出色的。”

示例:263(2、6、3、2*6 = 12、6*3 = 18)非常出色。

但是 236 (2, 3, 6, 2*3 = 6, 3*6 = 18) 并不出色。

我们只取子串,不取子序列。

我在想也许我们可以在这里应用动态规划,因为重复的产品计算?我们还有什么其他的解决方案? (这不是作业题。)

【问题讨论】:

  • 这是只检查严格子集还是所有子集?换句话说,你在第一个例子中检查2*6*3吗?
  • 您能具体说明一下您对彩色数字的定义吗? “我认为只有严格”并不是那么具体。您可以添加其他示例以及计算吗?
  • 包含非严格子字符串仅对十进制数字中带有01 的数字很重要,如果其中至少有3位数字,它们已经保证不会很出色号码;否则总产品必然大于任何子产品。我认为唯一重要的数字是 x0x11x 用于 x ≠ 0,再加上 10
  • 对于 263 ,子字符串是 , 2 ,6,3,26,63 。 263 不考虑在内。
  • DP 确实不是 FWIW 的必需品。只需枚举所有具有增加左边框的子字符串。时间复杂度是O(n^2),和DP解一样。

标签: algorithm language-agnostic


【解决方案1】:

这是使用动态编程解决它的一种方法:

假设我们有数字 d0 d1 ... dN 作为输入。 p>

想法是创建一个表格,其中单元格(ij)存储产品di ·di+1 ·...·dj。这可以有效地完成,因为 (i, j) 处的单元格可以通过将 (i-1, 处的数字相乘来计算>j) 由 di.

由于i(起始索引)必须小于或等于j(结束索引),我们将关注表格的左下三角.

生成表格后,我们检查重复条目。

这是输入 2673 的具体示例解决方案:

  1. 我们分配一个矩阵,M,尺寸为 4 × 4。

  2. 我们首先用di填充对角线Mi,i

  3. 然后我们一行一行的往里走,在Mi,j中填入di ·Mi-1,j

  4. 结果看起来像

  5. 为了检查重复,我们收集产品 (2, 12, 6, 84, 42, 7, 252, 126, 21, 3),对它们进行排序 (2, 3, 6, 7, 12, 21, 42, 84, 126, 252),然后循环查看两个连续的数字是否相等。如果是,则返回 false,否则返回 true。

在 Java 代码中:

这是一个有效的 DP 解决方案,O(n2)。

public static boolean isColorful(int num) {

    // Some initialization
    String str = "" + num;
    int[] digits = new int[str.length()];
    for (int i = 0; i < str.length(); i++)
        digits[i] = str.charAt(i) - '0';
    int[][] dpmatrix = new int[str.length()][str.length()];

    // Fill in diagonal: O(N)
    for (int i = 0; i < digits.length; i++)
        dpmatrix[i][i] = digits[i];

    // Fill in lower left triangle: O(N^2)
    for (int i = 0; i < str.length(); i++)
        for (int j = 0; j < i; j++)
            dpmatrix[i][j] = digits[i] * dpmatrix[i-1][j];

    // Check for dups: O(N^2)
    int[] nums = new int[digits.length * (digits.length+1) / 2];
    for (int i = 0, j = 0; i < digits.length; i++, j += i)
        System.arraycopy(dpmatrix[i], 0, nums, j, i+1);

    Arrays.sort(nums);

    for (int i = 0; i < nums.length - 1; i++)
        if (nums[i] == nums[i+1])
            return false;

    return true;
}

对于 DP 感兴趣的读者,我可以在这里推荐一些类似的问题/答案:

【讨论】:

  • 介意解释一下算法吗?
  • 请注意,由于 OP 只需要严格的子字符串,因此不应包含左下角。
  • 没有超过 8 位的辉煌数字 (没有数字可以重复,也不能有 01,这意味着幼稚的解决方案需要最大64 次迭代,而动态规划解决方案最多需要 36 次迭代。对于现代处理器来说,这两者实际上都不算什么。
  • 对于基数 10 是的。您甚至可以展开循环或列出代码中所有出色的数字以获得 O(1)。从复杂性的角度来看,我会假设基础是固定的但任意的。这让问题变得更有趣了。
  • @BlueRaja-DannyPflughoeft:哈哈,这很有趣。解决问题的方法......
【解决方案2】:

使用动态编程可能是要走的路: 不是计算所有 O(n^2) 子串,然后使用 ~n 乘法命令来计算它们中的每一个,而是将先前计算的结果存储在矩阵 M 中,其中 M(i,j) 是长度 j,从位置 i 开始。

(即,如果你的号码是 123456789,那么 M(1,5) 是 5!,而 M(1,6) 是 6!,只需要将 M(1,5) 乘以 6 - 恒功)

这会将运行时间从 n 位的 O(n^3) 提高到 O(n^2)。

【讨论】:

    【解决方案3】:

    动态规划解决方案确实没有必要,因为没有大量数字的精彩数字(如果任何数字出现多次,则该数字不精彩)

    Here 是每个精彩号码的列表。共有 57,281 个。

    这个文件在我的电脑上生成的时间不到一秒,即使没有使用动态编程:)

    【讨论】:

      【解决方案4】:

      如果我们不将数字视为一个大字符串,那么散列会有所帮助;

       int brill(int A) {
          map<long long int,bool> m;
          vector<int> arr(10,0);
          int i=0;
          while(A){
              arr[i++]=A%10;
              A/=10;
          }
      
          for(int j=0;j<i;j++){
      
              long long int temp=1;
      
              for(int k=j;k>=0;k--){
                  temp*=arr[k];
      
                  if(m.find(temp)!=m.end()){
                      return 0;
                  }
                  else{
                      m[temp]=true;
                  }
              }
          }
          return 1;
      
      }
      

      【讨论】:

        【解决方案5】:

        n 是包含数字的字符串。

        由于在失败状态之前该数字不能大于 8 位,因此其 O(1)。

        function isBrill(n) {
          var set = {};
          set[parseInt(n.charAt(0))] = true;
          for(var i=0; i < n.length - 1; i++) {
            var a = parseInt(n.charAt(i));
            var b = parseInt(n.charAt(i+1));
            if(set[b] === true) { return false; }
            set[b] = true;
            if(set[a * b] === true) { return false; }
            set[a * b] = true;
          }
          return true;
        }
        isBrill("263"); // true
        isBrill("236"); // false
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-12
          • 2022-12-30
          • 2011-05-24
          相关资源
          最近更新 更多