【问题标题】:Is there any way to use one while loop in this code instead of 2?有没有办法在这段代码中使用一个while循环而不是2?
【发布时间】:2021-09-01 17:01:15
【问题描述】:

我对此有点陌生,刚刚学习了循环。所以我想输入 187654321, 998765432 但我认为我写的这个东西效率太低以至于它只是超时:/它适用于较小的数字!将不胜感激任何帮助/提示呵呵:')

import java.util.*;

class PowerOf3 {
  
  public static void main(String[] args) {
    
    Scanner sc = new Scanner(System.in);
    
    System.out.print("Enter start and end: ");
    int start = sc.nextInt();
    int end = sc.nextInt();
    
    int ans = countNumbers(start, end);
    
    
    System.out.println("Answer = "+ans);
  }
  
  // Count the number of integers from start to
  // end (both inclusive) that are power of 3
  public static int countNumbers(int start, int end) {
    int count = 0;
    if (start == 1) {
      count = -1;
    } else {
    count =0;
    }
    while (end>=start) {
      double n = end;
      while (n>1) {
        n = (double) n/3;
      }
      if (n==1) {
        count++;
      }
      end--;
    }
    return count;  // stub, to be replaced by your code
  }
}

【问题讨论】:

  • 你能举个小数字的例子吗?这将帮助其他人了解您的代码将做什么?可能会提供更好的解决方案。
  • 如果inner-while循环对应库中的数学函数,你可以尝试使用它。
  • 在 1 和 Integer.MAX_VALUE 之间只有 3 的 20 次幂。您可以将这些存储在一个列表中,然后只计算开始和结束之间的数字。
  • @AntiqTech 哦,是的,我刚刚看到了!我现在就试试看!谢谢你

标签: java loops while-loop


【解决方案1】:

替换以下代码

double n = end;
      while (n>1) {
        n = (double) n/3;
      }
      if (n==1) {
        count++;
      }

有了这个并尝试运行,

int n = end;
      while (n%3 == 0) {
        n /= 3;
      }
      if (n==1) {
        count++;
      }

mod 和整数运算可以节省时间。

【讨论】:

  • 此修改将您的运行时间从 103407 毫秒减少到仅 2559 毫秒,输入 (start = 187654321 & end = 998765432) @chickennugget。
【解决方案2】:

我已经尝试使用存储所有 powers_of_3 的 HashSet(从 3^03^19,考虑整数)。该代码产生的时间几乎与 @abhimanyu 相似。

然后我修改@abhimanyue的代码,记住程序实际在做什么,这是我的代码。

class PowerOf3_final 
{
    //public static Set<Integer> powerOf3 = new HashSet<Integer>();
    
    public static void main(String[] args) 
    {
        Scanner sc = new Scanner(System.in);
        
        //System.out.print("Enter start and end: ");
        
        int start = 19683;      //int start = sc.nextInt(); 
        int end = 1162261467;   //int end = sc.nextInt();
        
        long st = System.currentTimeMillis();
        
        /*
        int pow3=1;
        for(int i =0; i<20; i++) {
            powerOf3.add(pow3);
            pow3 *= 3;
        }
        */
        
        System.out.println("Answer = "+countNumbers(start, end));
        
        long en = System.currentTimeMillis();
        
        System.out.println("Execution time = "+(en-st)+" milli seconds.");
    }
      
    // Count the number of integers from start to
    // end (both inclusive) that are power of 3
    public static int countNumbers(int start, int end) 
    {
        int count = 0;
        
        if (start == 1) {
          count = -1;
        } 
        
        while (end>=start) 
        {
            /*
            double n = end;         
            while (n>1) {
                n = (double) n/3;
            }
            if (n==1) {
                count++;
            }
            */
            
            int n = end;
            while (n%3 == 0) {
              n /= 3;
            }
            if (n==1) {
              count++;
              end /=3;  // no need to check other values,
            }
            
            /*
            if(powerOf3.contains(end)) {
                count++;
            }
            */
            
            else end--;
        }
        return count;  // stub, to be replaced by your code
    }
}

此代码对所有输入(在整数范围内)运行 superfast。 这段代码的时序仍有改进的余地。

【讨论】:

  • “仍有改进此代码时序的空间。”确实:尝试使用 end = 1162261466。
  • 你好!我真的不知道时间,但天哪,对于像我这样的初学者来说,这是最容易理解的! (我什至不明白我的教授试图解释的方法哈哈)我真的很感谢你的帮助!
【解决方案3】:

您的代码的问题不是效率。您的代码遭受无限循环的影响

您使用(int 变量)类型,最大值为 2147483647

当您在循环内(增量 ++)超过此数字时,循环不会结束,而是数字将像以下 1 2 3 4 然后 -4 - 3 -2 -1 或在您的示例中一样循环: 2147483646、2147483647、然后是2147483647-、2147483646-等。

【讨论】:

    【解决方案4】:

    快速执行此操作的关键不是检查所有数字,您正在使用while (end&gt;=start) { /* ... */ end--; }

    在 1 和 Integer.MAX_VALUE(输入的极端情况)之间大约有 20 亿个数字,其中只有 20 个是 3 的幂。

    而且,如果你能找到 3 的幂,你可以通过乘以 3 直接找到下一个最大的幂。当然,最简单的起点是 1。

    由于您的范围内只有 20 个可能的值,只需遍历所有 20 个(或直到您超过 end),计算恰好落在输入范围内的数字。这将是如此之快,以至于不必担心尝试从范围内的更大的 3 幂开始。

    从 30 开始,一直到 319

    int limit = 1 + (int) Math.floor(Math.log(Integer.MAX_VALUE) / Math.log(3));  // 20.
    
    return (int)
        IntStream.iterate(1, i -> i * 3)    // A stream containing only powers of 3
            .limit(limit)                   // Stop before you overflow
            .takeWhile(i -> i <= end)
            .filter(i -> i >= start)        // Take the ones in the range.
            .count();
    

    或者,使用基本循环:

    int count = 0;
    int p = 1;
    while (p <= end) {
      if (p >= start) ++count;
    
      if (p > Integer.MAX_VALUE / 3) break;
    
      p *= 3;
    }
    return count;
    

    这种方法takes <1μs 解决最坏情况的问题(1 到Integer.MAX_VALUE)(一旦预热);并且在没有预热的情况下似乎只会慢 10 倍左右。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-21
      • 1970-01-01
      • 2020-08-11
      • 1970-01-01
      • 2019-12-23
      • 2022-12-17
      相关资源
      最近更新 更多