【问题标题】:Count numbers deleted by removing consecutive digit pairs that don't sum to 17通过删除不等于 17 的连续数字对来计算删除的数字
【发布时间】:2021-01-23 15:38:36
【问题描述】:

以下是我的问题陈述:

你得到以 10 为底的数字,你必须通过选择两个连续的数字并删除它们来完全删除它。但是这2位数字之和不应该是17。我们把重复上述操作完全删除的数字称为“好”

例子:

  1. 9889 => 删除88 得到99
  2. 99 => 删除 99 以完全删除号码。 结论:9889。 注意:我们无法删除 9889,因为这 2 位数字的总和是 17

给定一个数字 N(偶数),您想找到 good N 位数字以 10^9 + 7 为模的数字。将包含前导零的 N 位数字也包括在计数中。

测试用例:

案例一:

Input: 2
Output: 98

案例 2:

Input: 4
Output: 9926

案例 3:

Input: 442
Output: 417551213

我尝试使用各种代码解决此问题,但无法得到结果。

【问题讨论】:

  • 首先我们从 9889 中去掉 88,所以数字变成了 99。现在 99 是连续的数字。
  • 请分享您的尝试。
  • @kriegaex- 这不是作业或任何项目。我也不是学生。当我理解动态编程时,这是我试图解决的问题之一。我无法找出任何解决方案来通过测试用例。我尝试了各种方法,但最多只能通过第一个测试用例。我并不是要我提供完整的解决方案,只是对哪些概念或如何处理它有很大帮助。
  • 这是来自 Codewars (codewars.com) 的 kata 还是来自 Project Euler (projecteuler.net) 或类似的问题?如果有,能否提供来源链接?
  • @concision 您可能对我的工作代码回答感兴趣。

标签: java algorithm dynamic-programming


【解决方案1】:

尝试使用树来尝试所有可能的解决方案。真正的问题是,您必须预测将保留哪个数字,以及是否可以在总和不为 17 的情况下删除它们。 例如,如果你有 9823,你可以删除 23,但最后你会被 98 阻止。

您可以尝试构建一棵树,其中每个分支都可能被删除。如果所有分支都被阻塞,则返回上一个节点

【讨论】:

  • 我之前没有处理过树,解决方案应该在 O(N^2) 内部。我想您建议的解决方案将需要更多时间。如果我错了,请纠正我。
  • Amiral 有一个很好的观点,除非你用数字计算出一些聪明的算术/微积分技巧,否则你将不得不使用回溯和一棵树.. 这样你就可以研究 N-queens 问题对于初学者来说,这是一个很好的例子!
【解决方案2】:

对于最后可能的不良状态的每个序列,必须有一个强制序列生成它。查看可能的通配符的位置(提供选择的数字当然是感兴趣的数字),并尝试找到一种模式。

在以下示例中,为了对称,将 9s 与 8s 切换; xs 是通配符:

输入长度4,错误结果9898:

9898

输入长度4,错误结果98:

989x
98x8
9x98
x898

从上面两个我们可以清楚地看到为什么我们会得到输出,9926 个好的 4 位数字。

输入长度6,错误结果9898:

98989x
9898x8
989x98
98x898
9x9898
x89898

输入长度 6,错误结果 9898 OR 98:

9898xx
989xx8
98xx98
9xx898
xx9898

输入长度6,错误结果98:

989x9x
98x8x8
...
9x989x
...

等等

Python 代码:

# https://gist.github.com/rougier/ebe734dcc6f4ff450abf
def binom(n,k):
  if not 0<=k<=n: return 0
  b=1
  for t in range(min(k,n-k)):
    b*=n; b//=t+1; n-=1
  return b

def f(n):
  bads = 0
  
  for k in range((n - 2) // 2 + 1):
    bads += 9**k * binom(n, k)
  
  return (10**n - 2 * bads) % (10**9 + 7) 
  
print(f(442)) # 417551213

【讨论】:

  • 不错!这是一个已知问题吗?你介意解释一下这句话“我们可以从上面两个清楚地看到为什么我们得到输出,9926 个好的 4 位数字”?这对我来说并不明显
  • @Youri 不知道有没有人知道,这是我第一次看到。 9898 是 1 错误;对于989x, 98x8, 9x98, x898 中的每一个,我们有 9 种方式,将x 替换为可以加入其邻居的数字。那是 1 + 4*9 = 37 个坏的。由于对称性,将 8 换成 9,我们将其翻倍,得到 74 个坏的。 10000 - 74 = 9926(我们使用 10000 来表示好和坏的总数,因为我们包括带有前导零的数字)。
  • 傻我,现在听起来确实很明显,我的想法缺少一步,谢谢你的解释!
【解决方案3】:

不想破坏编码,但是一个数字是否好,可以通过回溯来完成。

    solve(9889);

public static void solve(int num) {
    try {
        solve(num, new LinkedList<>());
        System.out.println("Not found");
    } catch (FoundException fe) {
        System.out.printf("%d%n", num);
        fe.result.forEach(pair -> System.out.printf("-> %d, having deleted %d%n",
            pair.getKey(), pair.getValue()));
    }
}

private static class FoundException extends RuntimeException {
    public final List<Pair<Integer, Integer>> result;

    public FoundException(List<Pair<Integer, Integer>> result) {
        this.result = result;
    }
}

private static void solve(int num, LinkedList<Pair<Integer, Integer>> partialResult) {
    if (num == 0) {
        throw new FoundException(partialResult);
    }
    int tenPower = 1;
    while (num >= tenPower) {
        int n = num / tenPower;
        int del = n % 100;
        if (del % 10 + del / 10 != 17) {
            int n2 = (n / 100) * tenPower + (num % tenPower);
            partialResult.addLast(new Pair<>(n2, del));
            solve(n2, partialResult);
            partialResult.removeLast();
        }
        tenPower *= 10;
    }
}

这个问题似乎被表述为int(31 位无符号整数)就足够了。 因此,我尝试使用 int 而不是数字列表。

另一个特性:使用异常从内部递归返回到顶层并获得肯定的结果。传统的方法是检查递归调用的结果。

注意:实际问题是一个更数学的问题。

【讨论】:

  • @גלעדברקן 这确实是更好的可读性(删除 xx)。由于 java 标记和这可能是一项任务,我只是想打破任何心理编程障碍。以及诸如能够使用原始 int 之类的技术细节,甚至可能是堆栈展开的异常。
猜你喜欢
  • 1970-01-01
  • 2017-02-11
  • 2021-02-22
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 2016-01-12
  • 1970-01-01
  • 2020-03-03
相关资源
最近更新 更多