【问题标题】:Comparing digits in number比较数字中的数字
【发布时间】:2021-12-16 11:26:51
【问题描述】:

始终对称地比较数字与其中间数字。如果第一个数字大于最后一个数字,第一个是获胜的,我必须显示它,否则我显示最后一个并保持直到我达到中间数字(这是如果我有奇数个数字),如果数字没有任何东西与它相比自动获胜。

例如数字是 13257,答案是 7 5 2。

另一个 583241 答案是 5 8 3。 现在我只试图捕捉位数为奇数的情况。卡住了..这是我的代码。问题是这段代码不显示任何数字,而是在 if 语句中比较它们(我在调试时检查过)。

#include <iostream>
using namespace std;
int countDigit(int n) {
    int count = 0;
    while (n != 0) {
        count++;
        n /= 10;
    }
    return count;
}
int main() {
    int n;
    cin >> n;
    int middle;
    int count = countDigit(n);
    
    if (count % 2 == 0) {
        cout<<"No mid digit exsist!!";
    }
    else {
        int lastDigit = n % 10;

        middle = (count + 1) / 2;

        for (int i = 0; i < middle; i++) {

            for (int j = lastDigit; j<middle; j--) {
                if (i > j) {
                    cout << i <<' ';
                }
                else {
                    cout << j;
                }
            }
        }
    }

    return 0;
}

【问题讨论】:

  • “卡住了” -- 所以你来到了这里,但你还没有提出合适的问题。 “Can someone help me?” is not an actual question. 你应该在你的代码中找出一个特定的问题,询问它,然后把你的例子集中在那个单一的步骤上(c.f minimal reproducible example -- 虚拟化其他步骤)。如果你必须告诉我们你的作业作为一个整体的功能,你(很可能)要么不够专注,要么不够抽象地思考,无法为 Stack Overflow 提出一个好的问题。
  • 问题是这段代码不显示任何数字。即使他们错了也应该这样做。
  • 这是一个值得询问的问题。为了使您的问题变得更好,请将您的代码缩减为(可能)仅是 if 语句(即您在调试时跟踪的语句)。跳过循环并进行概念验证。将ij 初始化为您选择的值,然后使用if 语句。如果你仍然没有得到输出,你已经消除了很多“噪音”(在调试这个问题时可以忽略的问题的代码)。如果确实得到了输出,请慢慢添加代码,直到问题再次出现。

标签: c++ numbers cycle digits


【解决方案1】:

在我看来,一个更简单的方法是使用字符串。您可以检查字符串的大小。如果有偶数个字符,你可以只比较前半个字符,后半个字符。如果有奇数,则打印中间字符。

这是我对奇数位数所做的:

string n;
cin>>n;
int i,j;
for(i=0,j=n.size()-1;i<n.size()/2,j>=(n.size()+1)/2;i++,j--)
{
    if(n[i]>n[j]) cout<<n[i]<<" ";
    else cout<<n[j]<<" ";
}
cout<<n[n.size()/2]<<endl;

【讨论】:

  • 我忘了说,我不能使用数组或字符串我只能使用循环和语句以及库 iostream
【解决方案2】:

我们分析需求,然后提出设计。

如果我们有一个由数字组成的数字,我们希望将“左”值与“右”值进行比较。因此,以某种方式从数字的左右数字索引开始。

Look at this number:   123456789
Index:                 012345678
Length: 9

在 C 和 C++ 中,索引以 0 开头。

那么,我们该怎么办?

  1. 比较索引 0 和索引 8
  2. 比较索引 1 和索引 7
  3. 比较索引 2 和索引 6
  4. 比较索引 3 和索引 5
  5. 比较索引 4 和索引 4

所以,左边的索引向上运行,右边的索引向下运行。

只要左索引小于或等于右索引,我们就会继续。所有这些都可以在forwhile 循环中完成。

无所谓,位数是奇数还是偶数。

当然,我们还需要返回数字长度和给定位置的数字位数的函数。但我看到您已经知道如何编写这些函数。所以,这里就不多解释了。

我给你看 3 个不同的例子。

  1. 非常简单而且非常冗长。效率很低,因为我们没有数组。
  2. 仍然简单,但更加压缩。效率很低,因为我们没有数组。
  3. C++ 解决方案,在您的情况下不允许

  1. 详细
#include <iostream>

// Get the length of a number
unsigned int length(unsigned long long number) {

    unsigned int length = 0;
    while (number != 0) {
        number /= 10;
        ++length;
    }
    return length;
}
// Get a digit at a given index of a number
unsigned int digitAt(unsigned int index, unsigned long long number) {
    index = length(number) - index - 1;
    unsigned int result = 0;
    unsigned int count = 0;

    while ((number != 0) && (count <= index)) {
        result = number % 10;
        number /= 10;
        ++count;
    }
    return result;
}
// Test
int main() {
    unsigned long long number;
    if (std::cin >> number) {

        unsigned int indexLeft = 0;
        unsigned int indexRight = length(number) - 1;

        while (indexLeft <= indexRight) {

            if (digitAt(indexLeft, number) > digitAt(indexRight, number)) {
                std::cout << digitAt(indexLeft, number);
            }
            else {
                std::cout << digitAt(indexRight, number);
            }
            ++indexLeft;
            --indexRight;
        }
    }
}


压缩

#include <iostream>

// Get the length of a number
size_t length(unsigned long long number) {
    size_t length{};
    for (; number; number /= 10) ++length;
    return length;
}
// Get a digit at a given index of a number
unsigned int digitAt(size_t index, unsigned long long number) {
    index = length(number) - index - 1;
    unsigned int result{}, count{};
    for (; number and count <= index; ++count, number /= 10)
        result = number % 10;
    return result;
}
// Test
int main() {
    if (unsigned long long number; std::cin >> number) {

        // Iterate from left and right at the same time
        for (size_t indexLeft{}, indexRight{ length(number) - 1 }; indexLeft <= indexRight; ++indexLeft, --indexRight)
            std::cout << ((digitAt(indexLeft,number) > digitAt(indexRight, number)) ? digitAt(indexLeft, number) : digitAt(indexRight, number));
    }
}

更现代的 C++

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

int main() {

    if (std::string numberAsString{}; std::getline(std::cin, numberAsString) and not numberAsString.empty() and
        std::all_of(numberAsString.begin(), numberAsString.end(), std::isdigit)) {

        for (size_t indexLeft{}, indexRight{ numberAsString.length() - 1 }; indexLeft <= indexRight; ++indexLeft, --indexRight) 
            std::cout << ((numberAsString[indexLeft] > numberAsString[indexRight]) ? numberAsString[indexLeft] : numberAsString[indexRight]);
    }
}

【讨论】:

    【解决方案3】:

    您正在尝试做一些与嵌套 for-cycles 混淆的事情。这显然是错误的,因为整个任务中没有任何“二次”(相对于位数)。此外,您的代码似乎不包含任何可以确定最高位数字的内容。

    我建议你从一些非常简单的事情开始:string'验证数字,然后遍历字符串中的数字。这显然既不优雅也不特别快,但它会是一个可行的解决方案,您可以在以后改进它。

    顺便说一句,你越早改掉using namespace std; 的坏习惯越好。这是一种反模式,请避免。

    旁注:无需区别对待奇数和偶数位数。只需让算法将中间数字(如果存在)与自身进行比较并选择它;没什么大不了。这是一个很小的效率缺陷,以换取代码简单性的巨大好处。

    #include <cstdint>
    #include <iostream>
    #include <string>
    
    using std::size_t;
    using std::uint64_t;
    
    uint64_t extract_digits(uint64_t source) {
      const std::string digits{std::to_string(source)};
      auto i = digits.begin();
      auto j = digits.rbegin();
      const auto iend = i + (digits.size() + 1) / 2;
      uint64_t result{0};
      for (; i < iend; ++i, ++j) {
        result *= 10;
        result += (*i > *j ? *i : *j) - '0';
      }
      return result;
    }
    
    
    int main() {
      uint64_t n;
      std::cin >> n;
      std::cout << extract_digits(n) << std::endl;
    }
    

    如果任务不允许使用strings 和数组,您可以尝试使用纯算术,方法是构造数字的“数字反转”版本,然后使用除法和模数迭代这两个数字。这将(仍然)具有明显的限制,这些限制源于数据类型大小、某些数字无法正确反转等。(Use GNU MP for unlimited integers.)

    #include <cstdint>
    #include <iostream>
    
    using std::size_t;
    using std::uint64_t;
    
    uint64_t extract_digits(uint64_t source) {
      uint64_t inverted{0};
      size_t count{0};
      for (uint64_t div = source; div; div /= 10) {
        inverted *= 10;
        inverted += div % 10;
        ++count;
      }
      count += 1;
      count /= 2;
      uint64_t result{0};
      if (count) for(;;) {
        const uint64_t a{source % 10}, b{inverted % 10};
        result *= 10;
        result += a > b ? a : b;
        if (!--count) break;
        source /= 10;
        inverted /= 10;
      }
      return result;
    }
    
    
    int main() {
      uint64_t n;
      std::cin >> n;
      std::cout << extract_digits(n) << std::endl;
    }
    

    最后但并非最不重要的一点是,我强烈建议您在拥有可构建和可运行的东西之后提出问题。让其他人解决家庭作业违背了家庭作业的目的。

    【讨论】:

    • 是的,我知道,但我没有想法。这个解决方案对我不起作用,因为我不能使用数组或字符串,我只能使用循环和语句以及库 iostream
    • @tupkon 好的,我添加了string-free 和 array-free 版本。
    • 谢谢你我现在明白了!
    猜你喜欢
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 2014-04-29
    • 2019-11-13
    • 1970-01-01
    • 1970-01-01
    • 2022-10-25
    • 2016-04-05
    相关资源
    最近更新 更多