【问题标题】:How do I proceed with a question like this? [closed]我该如何处理这样的问题? [关闭]
【发布时间】:2019-12-26 20:39:20
【问题描述】:

大家晚上好。我不确定在这个平台上问这样的问题是否违反规则(如果是,请告诉我)。问题是“实践竞赛”。我可以完成 10 个测试用例中的 5 个,但我不确定这有什么问题。请提出任何更正/逻辑/提示...并且时间复杂度必须小于 O(n^2) (根据给定的输入)

我尝试的方法是:

int main() {
  /* Enter your code here. Read input from STDIN. Print output to STDOUT */
  signed long int t, n;
  scanf("%d", &t);
  for (int i = 1; i <= t; i++) {
    int count = 0;
    scanf("%d", &n);
    if (n <= 10)
      count = n;
    else {
      // count = 9;
      string s;
      s = to_string(n);
      int len = s.length();
      int x = n / (pow(10, len - 2));
      int h = x / 11;
      string y = to_string(x);
      if (y.length() <= 2)
        x = 0;
      count = (9 * (len - 1)) + x + h;
    }
    printf("%d\n", count);
  }
  return 0;
}

请提出任何您认为有帮助的建议。非常感谢。

【问题讨论】:

  • 您的标题不是描述性的。请写一个总结具体问题的标题。看看这里:ask good questions。此外,听起来您正试图让我们为您完成工作。 Understand the difference between "asking a question about your homework" and "asking a specific question about the code in your homework"
  • 在计算中可以避免使用 std::stringto_string(n).length() 可能会被 floor(log10(n) + 1) 替换。 to_string(x).length() &lt;= 2 -> x &lt; 100
  • 你有没有想过打印所有九个所谓的“美丽数字”,例如,三位数长,特别是 111 到 999,无需实际单独测试每个数字100到999看看是不是所谓的“美数”?如果你花点时间思考这个事实,并围绕它思考,你应该会想到一个更简单的解决方案,并且你应该意识到上面显示的所有代码都是完全错误的方法。
  • 另外,您将实际问题发布为图像而不是将其复制粘贴为文本的原因是什么?图片使问题更难理解,更难阅读。
  • @churill PrtScr ;)

标签: c++ logic


【解决方案1】:

对于这个问题,鉴于你正在处理的工作区域相对较小(小于 10^9 的漂亮数字的数量可以通过这些值的表格来合理处理),这里有一个版本的解决方案,使用预先生成的所有漂亮数字按排序顺序生成的表格。

一旦建立了表格,只需进行二分搜索以确定在输入值之前出现的漂亮数字的数量。表格中最接近的漂亮数字的位置就是我们需要的漂亮数字的个数。

二分查找是通过使用&lt;algorithm&gt; 函数std::upper_bound 完成的。此函数将返回一个迭代器,指向大于搜索项的项。然后为了得到位置,使用std::distance(我们减去1,因为std::upper_bound会给我们提供大于搜索项的项)。

表的生成可以在编译时完成(手动,只是初始化一个数组),或者如果你很懒,可以在运行时用一个简单的循环生成。这是一个这样的解决方案:

#include <algorithm>
#include <vector>
#include <iostream>

std::vector<int> values;

int generate_value(int digit, int numTimes)
{
    int total = 0;
    for (int i = 0; i < numTimes; ++i)
        total = 10 * total + digit;
    return total;
}

// I'm lazy, so let the program generate the table for me
void generate_values()
{
    size_t curIdx = 0;
    values.push_back(0);
    for (int i = 1; i <= 9; ++i)
    {
        for (int j = 1; j <= 9; ++j)
            values.push_back(generate_value(j, i));
    }
    values.push_back(1111111111);
}

// does a binary search and returns the position of the beautiful number
int beautiful(int num)
{
    if (num == 0)
        return 1;

    // get iterator to closest number equaling the beautiful number
    auto iter = std::upper_bound(values.begin(), values.end(), num);

    // get distance from beginning of vector
    return std::distance(values.begin(), iter) - 1;
}

int main()
{
    generate_values();
    std::cout << beautiful(18) << "\n";;
    std::cout << beautiful(1) << "\n";;
    std::cout << beautiful(9) << "\n";;
    std::cout << beautiful(100500) << "\n";;
    std::cout << beautiful(33) << "\n";;
    std::cout << beautiful(1000000000) << "\n";;
}

输出:

10
1
9
45
12
81

表的大小总共有 83 个条目,因此对该表的二进制搜索将不超过 log(83) 的检查来找到该值,也就是表中最多 7 个探针。

【讨论】:

  • 支持这项工作。所有这些 push_back 都会导致大量新分配。
  • push_backs 没有什么可关注的——我之所以这样做,是因为我决定以这种方式创建初始表。没有什么能阻止任何人简单地创建一个 83 的数组并将漂亮的数字硬编码到数组中。我在答案中提到了这一点。
  • constexpr std::array&lt;int, N&gt; generate_beautiful_numbers() 是另一种选择。
  • @PaulMcKenzie 晚上好。首先,先生,您提供了一种完全不同的方法来解决这个问题。我很惊讶生成一个漂亮的数字是多么容易(我想我必须大量提高我的逻辑技能)。显然这是时间和空间之间的权衡,但它确实有效。我想做的一个更正是return std::distance(values.begin(), iter) - 1; 会比我们需要的数字(距离)少一,因为向量从 0 开始计数。它给出了不同的结果。因此,通过直接返回 values.begin() 和 ter 之间的距离,程序就可以工作了。
  • @BeardedOwl -- 是的,我对是否应该减去 1 感到有些不安。但总的想法是,答案要么就在二分搜索结果的前面,要么就在下面。因此,这几乎可以归结为要求是什么问题,并且可能是在upper_bound 电话之后进行的健全性检查。
【解决方案2】:

这不是一个复杂的问题。 假设您的输入是正确的,因此我们不必进行任何我们观察到的检查:

  1. 如果数字 n 是个位数,则漂亮数字的个数为 b = n。
  2. 如果数n是两位数,第一个数是f,那么美数的个数b = 9 + x,其中x是所有小于n的美数的个数,
  3. 如果数字 n 是三位数且第一位是 f,则美丽数字的个数 b = 2 x 9 + x,其中 x 是所有小于 n 的美丽三位数的个数。
  4. 等等等等

因此我们可以推断:如果数字 n 有 d 个数字,那么漂亮数字的个数

s = (d-1) * 9 + x,

其中 x 是许多小于或等于 n 的漂亮的 d 位数。 所以你的问题被简化为找到x。这可以进一步减少。以数字 n = 44437 为例。这里重要的数字是第一个数字 f。很容易看到所有 5 位漂亮的数字都以小于 f 的个位数开始。在我们的示例中,11111、22222、33333 可以,而 444444 及更大的则不行。

所以你需要做的就是检查美丽的数字fffff是否小于或等于n。这可以通过输入字符串的简单遍历来完成。 所以你的解决方案是:

s = (d-1) * 9 + (f-1) + 超级秘密,

地点:

s - 解决方案

n - 你输入的年龄数

d – 位数,假设您的输入始终正确,则为 length(n)

f - 您号码的第一个数字 n

supersecretsauce – 如果 fff...f 小于或等于 n,则为 1,如果更大,则为 0。 甚至可以优化输入字符串的遍历,但我把它留给你。

哦,是的......这个解决方案的时间复杂度 O(n) = length(n) = log10(n)。

【讨论】:

  • 为什么复杂度是O(n)?如果这是您计算的结果,那么还有更快的方法可以做到这一点,与您的方法完全不同。例如,按排序顺序预先生成整张漂亮数字表,然后简单地对该表进行二分查找。
  • @PaulMcKenzie 复杂性实际上是长度(n),因为您实际上需要做的就是遍历数字 n 的输入字符串。或者,如果您在数域中工作,则必须构造一个长度为 d 的漂亮数字并将其与 n 进行比较,这也归结为 O(d)。你的提议可能很有希望,当然你会用时间要求换取空间要求,但由于漂亮的数字很少,它可能会奏效。对于每个漂亮的数字,您还必须预编译较小的漂亮数字的数量。
  • @PaulMcKenzie 请原谅我的错误。我做了一个关于 O(n) 的类型。我已经编辑了我的答案。复杂度实际上是 O(n) = length(n),取决于位数。
  • 当然,使用表格需要权衡空间。我会发布一个答案。
  • @user6694745 晚上好。我理解你的大部分逻辑(我觉得我们得出了相同的结论,但你做得很出色)。但我有一个问题:“supersecretsauce”背后的逻辑是什么?我认为它是用于单个数字的,让我解释一下。如果 n = 8,f = 8。d = 1。因此,count = 0 + 8 - 1 + supersecretsauce。在这种情况下,因为 (f
【解决方案3】:

关于早期设置的一些事情。

1) 从您给出的输入示例中,似乎 t 和每个 n 需要按顺序输入,但是您的代码会在收到下一个输入之前打印漂亮数字的数量。我建议先读入 t,然后循环遍历一个大小为 t 的数组以首先获取所有输入。

2) 未测试约束。我会测试 t 和前面提到的数组中的每个值是否满足约束,如果不满足,让用户再试一次,或者干脆中止。

【讨论】:

  • 如果我事先在一个数组中获取输入,我需要另一个循环来访问数组的元素并一个一个地传递输入,所以在这种情况下,我认为我应该这样做同时。
猜你喜欢
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多