【问题标题】:Which is considered better to get the individual digits of a number? Divide-modulus or string charAt?哪个被认为更好地获取数字的各个数字?除模还是字符串charAt?
【发布时间】:2015-07-23 17:13:57
【问题描述】:

方法一:

重复Division-modulus 操作。

long num = 123456789;
int count = 0;
while(num > 0)
{
 int digit = num % 10;
 if(digit == 1)
  count ++;
 num /= 10;
}

方法2:

将其转换为String,并获取该位置的字符。

long num = 123456789;
int count = 0;
String s = String.valueOf(num);
for(int i = 0; i < s.length(); i++)
{
 char ch = s.charAt(i);
 if(ch == '1')
    count ++;
}

第二次运算不需要每次都取余数和商。 charAt() 方法就足够了。

哪种方法被认为更好,为什么?

编辑 考虑从控制台获取输入。

1st Case: 
long num = scanner.nextLong();

2nd Case:
String s = scanner.nextLine();

在这里将number 转换为string 不会产生任何开销。

我们也假设它是正数。

【问题讨论】:

  • 为什么要在第二种情况下创建StringBuffer? (为什么要执行字符串连接?)只需使用String text = String.valueOf(num);
  • 要获得更好和更详细的答案,请考虑将其发布在Code Review

标签: java string optimization numbers


【解决方案1】:

在这种特殊情况下,我认为使用字符串表示是合理的。毕竟,与十进制字符串表示相比,您找到的计数本质上与其数值有关 - 如果您将其转换为十六进制,您会得到不同的值。

对于基本中立的操作,我通常会避免执行字符串转换。

请注意,第二种方法不需要StringBuffer。我会使用:

long num = 123456789;
int count = 0;
String text = String.valueOf(num);
for (int i = 0; i < text.length(); i++) {
    char ch = text.charAt(i);
    if (ch == '1') {
        count++;
    }
}

当然,这是假设性能无关紧要 - 根据我的经验,通常是。您的第一个选项几乎肯定会更有效,因为第二个需要先将数字转换为字符串。但除非您需要这种效率,否则我会坚持使用最容易理解的代码 - 在这种情况下,我建议使用基于文本的表示。

(作为一个例子:你对你的第一个例子适用于负数有多大信心?你的第二个例子同样的问题怎么样?)

【讨论】:

    【解决方案2】:

    我写了一个快速基准测试:

    public static void main(String[] args) {
            long num = 1657345918972817181L;
    
            long time = System.nanoTime();
            int i1 = byString(num);
            long t1 = System.nanoTime() - time;
    
            time = System.nanoTime();
            int i2 = byNumber(num);
            long t2 = System.nanoTime() - time;
    
            System.out.println("Result: " + i1 + " Time: " + t1 + "ns");
            System.out.println("Result: " + i2 + " Time: " + t2 + "ns");
        }
    
        static int byNumber(long num) {
            int count = 0;
            while (num > 0) {
                long digit = num % 10;
                if (digit == 1) {
                    count++;
                }
                num /= 10;
            }
            return count;
        }
    
        static int byString(long num) {
            int count = 0;
            String s = String.valueOf(num);
            for (int i = 0; i < s.length(); i++) {
                char ch = s.charAt(i);
                if (ch == '1') {
                    count++;
                }
            }
            return count;
        }
    

    结果异常:

    Result: 5 Time: 18923ns
    Result: 5 Time: 1924ns
    

    字符串表示需要更多时间来计算。我测试了这个更大和更小的数字。 如果我给我的方法 byString(String num) 一个字符串,我会得到这些结果:

    Result: 5 Time: 5453ns
    Result: 5 Time: 1924ns
    

    速度更快,但避免使用字符串方法仍然是更好的选择。

    【讨论】:

      【解决方案3】:

      第一种方法更好。

      要将整数转换为字符串,String.valueOf 函数必须执行重复的除法和模数,这是从整数转换为以 10 为底的字符串的唯一可能方法。

      所以方法一的操作次数为:

      2N (N = length of the string)
      

      虽然在方法二中它更高,因为在 String.valueOf 进行转换之后,您仍然需要获取每个单独的字符并进行处理。

      【讨论】:

        【解决方案4】:

        将数字转换为字符串需要与您的代码类似的代码,但字符串需要额外的内存和一些进一步的处理,因此您的 first 想法更好。

        【讨论】:

          【解决方案5】:

          第一个假设你的腿上有int。

          几乎可以肯定它更快,因为它不需要内存分配操作并且涉及的代码更少。

          但是,鉴于您可能会从控制台读取 int 或 String 的编辑,答案将是使用您面前的内容。

          在大多数实际系统中,如果仅用于输入验证,您可能希望在某个时候将输入作为字符串接收。 在那种情况下,将其拖入 int 以便将其数字解包出来只是不必要的逻辑。

          【讨论】:

          • 如果String s = scanner.nextLine()而不是维护一个重复的内存呢?
          • 您假设性能是这里最重要的要求。通常不是,IME。
          • 如果前面有这两个,请选择 #1。代码审查中的任何人都不应该决定用#2 代替#1。它只能阻碍。我同意这可能无关紧要,除非它是瓶颈,否则您不会用 #1 替换 #2。但毫无疑问,#2 是过度设计的。
          • @UmaKanth 该编辑是后来添加的。我已经更新了我的答案。正如我所说,这将是一个“处理你面前的东西”的问题。
          猜你喜欢
          • 2010-12-12
          • 1970-01-01
          • 2015-02-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-24
          • 1970-01-01
          • 2016-12-27
          相关资源
          最近更新 更多