简体   繁体   English

将 long 转换为二进制然后将二进制字符串连接为 long 时出现运行时异常

[英]Getting runtime exception while converting long to binary and then concatenated binary String to long

I was trying this question on HackerEarth platform You are given a number n.我在 HackerEarth 平台上尝试了这个问题,你得到了一个数字 n。 Find the decimal value of the number formed by concatenation of binary representation of the first n positive integer.求前 n 个正数 integer 的二进制表示串联形成的数的十进制值。

Sample Input 3样本输入 3

Sample OutPut 27 (1: 1, 2: 10, 3: 11, result: 11011)样品 OutPut 27(1:1、2:10、3:11,结果:11011)

My Solution:我的解决方案:

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);
    }
}

Can someone please suggest efficient way to do this?有人可以建议有效的方法吗?

As mentioned in a comment, for a more efficient solution, use << bit-shift operator, and the Integer.numberOfLeadingZeros(i) method:如评论中所述,要获得更有效的解决方案,请使用<<位移运算符和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;
}

For a potentially 1 even more efficient solution, it can be done without the numberOfLeadingZeros() method:对于一个可能更有效的解决方案,可以在没有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) Method numberOfLeadingZeros() is annotated with @HotSpotIntrinsicCandidate , so it may be super-fast using a native solution, which means that this Java code alternative might not be faster. 1) 方法numberOfLeadingZeros()使用@HotSpotIntrinsicCandidate注释,因此使用本机解决方案可能会超快,这意味着此 Java 代码替代方案可能不会更快。

Test测试

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

Output Output

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

To support values of n greater than 17, return type must be changed to a BigInteger :要支持大于 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;
}

Test测试

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));

Output Output

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

Use a StringBuilder to contain the binary number.使用 StringBuilder 来包含二进制数。

To append the bits of the next number, use a mask of the highest one bit and AND the value with the mask, shifting the mask right 1 bit until 0.到 append 下一个数字的位,使用最高一位的掩码并将值与掩码进行与,将掩码右移 1 位直到 0。

Say v = 1100
highest 1 bit is 1000
  • v & 1000 = 1 so append a 1 v & 1000 = 1所以 append a 1
  • v & 0100 = 1 so append a 1 v & 0100 = 1所以 append a 1
  • v & 0010 = 0 so append a 0 v & 0010 = 0所以 append a 0
  • v & 0001 = 0 so append a 0 v & 0001 = 0所以 append a 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;
}

Prints印刷

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM