• [算法]谷歌笔试题:Beautiful Numbers


    题目描述

     

    思路

    这道题就是在说,由多个1组成的数是beautiful的,现在想求出r进制中的r,使得给出的数字转换成r进制,得到beautiful的数字,如果有多种方式转换,那么取1的个数最多的那种情况,也就是r最小的情况。

    这道题其实就是10进制和r进制的转化,这里就不详述了,但是注意题目中的一点就是给了两种数据集,小数据集的N最大为1000,大数据集的N最大为10^18,大数据集非常棘手。

    先看看小数据集的常规思路,就从二进制开始进行循环,每次循环判断一下该进制下进行转换得到的数字是否为beautiful的,见下面第一个代码。这种思路的时间复杂度是NlogN,因为N最大为1000,所以很快。

    再看看大数据集,如果我们采用上面那种方式的话,N为10^18,这样带进去差不多是64*10^18的计算,假设计算机1秒执行10^8次计算,这样的耗时也是非常巨大的。

    因此对于大数据集的思路是,我们先看一下,10^18的数字,转成二进制,最多的话,也是64个1,所以我们就设开始是64个1,然后递减,计算每次该个数的1能不能由某一进制转换成功。在计算进制的过程中,可以采用二分查找,这样总共的时间复杂度就是logN*logN*logN,相当于64*64*64,还是非常小的。最后因为可能数据溢出,所以用long,用long也可能在计算过程中溢出,所以做了一下处理,这里同样可以采用BigInteger。

    代码

    小数据集的代码(常规思路):

    package interview.google;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.util.Scanner;
    
    public class BeautifulNumber {
    
      public static void main(String[] args) {
        Scanner in = new Scanner(
            new BufferedReader(new InputStreamReader(System.in)));
        int cases = in.nextInt();
        for (int i = 1; i <= cases; ++i) {
          long n = in.nextLong();
          System.out.println("Case #" + i + ": "
              + beautiful(n));
        }
      }
    
      private static long beautiful(long n) {
        for (long radix = 2; radix < n; radix++) {
          if (isBeautiful(n, radix)) {
            return radix;
          }
        }
    
        throw new IllegalStateException("Should not reach here.");
      }
    
      private static boolean isBeautiful(long n, long radix) {
        while (n > 0) {
          if (n % radix != 1) {
            return false;
          }
          n /= radix;
        }
        return true;
      }
    }

    大数据集的代码(同样适用于小数据集):

    package interview.google;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.util.Scanner;
    
    public class BeautifulNumberLarge {
    
      public static void main(String[] args) {
        Scanner in = new Scanner(
            new BufferedReader(new InputStreamReader(System.in)));
        int cases = in.nextInt();
        for (int i = 1; i <= cases; ++i) {
          long n = in.nextLong();
          System.out.println("Case #" + i + ": "
              + beautiful(n));
        }
      }
    
      private static long beautiful(long n) {
        for (int bits = 64; bits >= 2; bits--) {
          long radix = getRadix(n, bits);
          if (radix != -1) {
            return radix;
          }
        }
    
        throw new IllegalStateException("Should not reach here.");
      }
    
      /**
       * Gets radix so that n is 111...1 (bits 1 in total) in that
       * radix.二分查找,最大值需要+1.
       *
       * @return the radix. -1 if there's no such radix.
       */
      private static long getRadix(long n, int bits) {
        long minRadix = 2;
        long maxRadix = n;
        while (minRadix < maxRadix) {
          long m = minRadix + (maxRadix - minRadix) / 2;
          long t = convert(m, bits);
          if (t == n) {
            return m;
          } else if (t < n) {
            minRadix = m + 1;
          } else {
            maxRadix = m;
          }
        }
        return -1;
      }
    
      /**
       * Returns the value of 111...1 (bits 1 in total) in radix.
       */
      private static long convert(long radix, int bits) {
        long component = 1;
        long sum = 0;
        for (int i = 0; i < bits; i++) {
          if (Long.MAX_VALUE - sum < component) {
            sum = Long.MAX_VALUE;
          } else {
            sum += component;
          }
    
          if (Long.MAX_VALUE / component < radix) {
            component = Long.MAX_VALUE;
          } else {
            component *= radix;
          }
        }
        return sum;
      }
    }
  • 相关阅读:
    每周必写
    每周必写
    每周必写
    中国历史上成功的两人合作, 改进, 提高的例子
    每周必写(3)
    结对编程进度及自己的理解
    每周必写
    IT行业的“创新”、“模仿”
    工作时间内容,感想和思考
    周阅读内容
  • 原文地址:https://www.cnblogs.com/DarrenChan/p/10316551.html
Copyright © 2020-2023  润新知