【问题标题】:Getting runtime exception while converting long to binary and then concatenated binary String to long在将 long 转换为二进制然后将二进制字符串连接为 long 时出现运行时异常
【发布时间】:2020-09-11 03:31:08
【问题描述】:

我在 HackerEarth 平台上尝试过这个问题 给你一个数字 n。求前n个正整数的二进制表示串联形成的数字的十进制值。

示例输入 3

样本输出 27(1:1、2:10、3:11,结果:11011)

我的解决方案:

public class test {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter wr = new PrintWriter(System.out);
        long n = Long.parseLong(br.readLine().trim());

        long out_ = FindBigNum(n);
        wr.println(out_);
        wr.close();
        br.close();
    }

    static long FindBigNum(long n) {
        // Write your code here
        String str = "";
        for (long i = 1; i <=n; i++) {
            str += Long.toBinaryString(i);
        }
        return Long.parseLong(str, 2);
    }
}

有人可以建议有效的方法吗?

【问题讨论】:

  • 不要解释代码,显示代码。
  • 就像安德烈亚斯说的,你在正确的轨道上,但我很确定你的代码中存在错误。
  • 更有效的解决方案:使用&lt;&lt;位移运算符,以及可选的Integer.numberOfLeadingZeros(i)方法,但可以不使用该方法。
  • @Andreas 我已添加代码

标签: java string binary long-integer


【解决方案1】:

正如评论中提到的,要获得更有效的解决方案,请使用&lt;&lt; 位移运算符和Integer.numberOfLeadingZeros(i) 方法:

static long binaryConcatRange(int n) {
    if (n < 0 || n > 17)
        throw new IllegalArgumentException("Out of range (0-17): " + n);
    long result = 0;
    for (int i = 1; i <= n; i++) {
        int bitLen = 32 - Integer.numberOfLeadingZeros(i);
        result = (result << bitLen) | i;
    }
    return result;
}

对于一个可能1更有效的解决方案,它可以在没有numberOfLeadingZeros() 方法的情况下完成:

static long binaryConcatRange(int n) {
    if (n < 0 || n > 17)
        throw new IllegalArgumentException("Out of range (0-17): " + n);
    long result = 0;
    for (int bitLen = 0, nextLenAt = 1, i = 1; i <= n; i++) {
        if (i == nextLenAt) {
            bitLen++;
            nextLenAt <<= 1;
        }
        result = (result << bitLen) | i;
    }
    return result;
}

1) 方法 numberOfLeadingZeros() 使用 @HotSpotIntrinsicCandidate 注释,因此使用本机解决方案可能会超快,这意味着此 Java 代码替代方案可能不会更快。

测试

for (int n = 0; n < 18; n++)
    System.out.printf("%s: %s%n", n, binaryConcatRange(n));

输出

0: 0
1: 1
2: 6
3: 27
4: 220
5: 1765
6: 14126
7: 113015
8: 1808248
9: 28931977
10: 462911642
11: 7406586283
12: 118505380540
13: 1896086088653
14: 30337377418462
15: 485398038695407
16: 15532737238253040
17: 497047591624097297

要支持大于 17 的 n 值,必须将返回类型更改为 BigInteger

static BigInteger binaryConcatRange(int n) {
    if (n < 0 || n == Integer.MAX_VALUE)
        throw new IllegalArgumentException("Out of range: " + n);
    BigInteger result = BigInteger.ZERO;
    for (int i = 1; i <= n; i++) {
        int bitLen = 32 - Integer.numberOfLeadingZeros(i);
        result = result.shiftLeft(bitLen).or(BigInteger.valueOf(i));
    }
    return result;
}

测试

for (int n = 18; n < 32; n++)
    System.out.printf("%s: %s%n", n, binaryConcatRange(n));
for (int n = 32; n <= 256; n *= 2)
    System.out.printf("%s: %s%n", n, binaryConcatRange(n));

输出

18: 15905522931971113522
19: 508976733823075632723
20: 16287255482338420247156
21: 521192175434829447909013
22: 16678149613914542333088438
23: 533700787645265354658830039
24: 17078425204648491349082561272
25: 546509606548751723170641960729
26: 17488307409560055141460542743354
27: 559625837105921764526737367787355
28: 17908026787389496464855595769195388
29: 573056857196463886875379064614252445
30: 18337819430286844380012130067656078270
31: 586810221769179020160388162164994504671
32: 37555854193227457290264842378559648298976
64: 471483835060474447584605138071473227083738554722043752192205889593231757234798071314332600270577600
128: 685385418402711161486992779215452480197156956593160845028648293349782283935659509581295718147533155031188929619519081596427609304635849304708531968190976802229890594798789934166770532152593884743090295308624351511929798643557538430848
256: 246422532279457970240939131862416256957912100676567284022182930350788567839691502682935548861928505318417306075544389639956672552326580169008528080129830322429712508593083839769096175727133924908330823876506697567963272081220317027757129623022363719594776044926884107531078136465754901556922215598679264299348040837049670711753684521748473384638643859758271742330378295219493243936419532611365679896772551640598210176805609455785828091793688653809020045393677303410807761070390084298154799431073337833749694111293934995919750974732669988765440

【讨论】:

    【解决方案2】:

    使用 StringBuilder 来包含二进制数。

    要附加下一个数字的位,请使用最高一位的掩码 并将值与掩码相加,将掩码右移 1 位直到 0。

    Say v = 1100
    highest 1 bit is 1000
    
    • v &amp; 1000 = 1 所以附加一个1
    • v &amp; 0100 = 1 所以附加一个1
    • v &amp; 0010 = 0 所以附加一个0
    • v &amp; 0001 = 0 所以附加一个0
    StringBuilder sb = new StringBuilder();
        
    for (int i = 1; i < 15; i++) {
        appendBinary(sb, i);
        System.out.println(i + " : "
                + new BigInteger(sb.toString(), 2));
    }
    }
        
    public static StringBuilder appendBinary(StringBuilder sb, int v) {
        int mask = Integer.highestOneBit(v);
        while (mask != 0) {
            char bit = ((v & mask) == 0) ? '0' : '1';
            sb.append(bit);
            // In case v is negative.  Then mask will be negative.
            // So shift accordingly.
            mask >>>= 1;
        }
        // Convenience return.
        // Same object as provided.
        return sb;
    }
    

    打印

    1 : 1
    2 : 6
    3 : 27
    4 : 220
    5 : 1765
    6 : 14126
    7 : 113015
    8 : 1808248
    9 : 28931977
    10 : 462911642
    11 : 7406586283
    12 : 118505380540
    13 : 1896086088653
    14 : 30337377418462
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-01
      • 2019-01-10
      • 1970-01-01
      • 1970-01-01
      • 2021-02-24
      • 1970-01-01
      相关资源
      最近更新 更多