在将long转换为二进制,然后将二进制String转换为long时获取运行时异常

时间:2020-05-24 13:05:18

标签: java string binary long-integer

我正在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);
    }
}

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

2 个答案:

答案 0 :(得分:0)

如评论中所述,要获得更有效的解决方案,请使用<<位移位运算符和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

答案 1 :(得分:0)

使用StringBuilder包含二进制数字。

要附加下一个数字的位,请使用最高一位的掩码 然后将值与掩码进行“与”运算,将掩码右移1位直到0。

Say v = 1100
highest 1 bit is 1000
  • v & 1000 = 1,因此请附加一个1
  • v & 0100 = 1,因此请附加一个1
  • v & 0010 = 0,因此请附加一个0
  • v & 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
相关问题