[LintCode] Binary Representation

410 查看

Problem

Given a (decimal - e.g. 3.72) number that is passed in as a string, return the binary representation that is passed in as a string. If the fractional part of the number can not be represented accurately in binary with at most 32 characters, return ERROR.

Example

For n = "3.72", return "ERROR".

For n = "3.5", return "11.1".

Note

这道位操作的题目,主要分为整数部分和小数部分的转换。细节上还要考虑正负号和整数位的越界情况。首先,我们对字符串n.split("\\.")把小数点前后的部分分离,存入String[] parts,整数部分为parts[0],小数部分为parts[1]。然后将parts[0]通过Integer.parstInt()转化为int first,然后将first的正负设置为符号位boolean isNeg,建立StringBuilder sb
下面开始整数部分的转换,首先考虑越界情况:当first的值为Integer.MIN_VALUE的时候,二进制表达为32个1,放入sb即可。否则对first的绝对值进行运算。对first(的最低位)和整数1做与运算,结果存入sb,然后右移一位,进行上一位和整数1的与运算,如此直到first为0,转换完毕。
小数部分相对更麻烦一些。首先,只有parts[]有两个元素且parts[1]不为0时,sb加入小数点'.',然后创建double value,使用Double.parseDouble("0." + parts[1])将小数部分存入value,和整数部分的操作基本一致。
然后我们要考虑两个问题value是不是能够完全转换为二进制,以及保证能够在小数点后32位的范围内完成转换?
所以,我们针对这两点,写出返回ERROR的分支语句。首先在循环外部建立一个HashSet store,循环内会将出现过的value存入store。然后在while循环内判断,如果有重复出现的value,或者sb中小数部分的长度超过32,就说明该小数无法完全转换。
然后根据新的value大小进行十进制到二进制转换运算(value * 2(value < 0.5)value * 2 - 1(value >= 0.5)),将结果加入sb。如果之前的正负号isNegtrue,就在sb左边加上负号'-'
最后,返回sb.toString()

Solution

import java.math.*;
public class Solution {
    public String binaryRepresentation(String n) {
        if (n == null || n.length() == 0) {
            return n;
        }
        String[] parts = n.split("\\.");
        StringBuilder sb = new StringBuilder();
        int first = Integer.parseInt(parts[0]);
        boolean isNeg = first < 0;
        if (first == Integer.MIN_VALUE) {
            for (int i = 0; i < 32; i++) {
                sb.append("1");
            }
        } else {
            first = Math.abs(first);
            while (first != 0) {
                sb.insert(0, first & 1);
                first >>= 1;
            }
        }
        if (sb.length() == 0) {
            sb.append("0");
        }
        //now nail the decimal part
        if (parts.length == 2 && Long.parseLong(parts[1]) != 0) {
            sb.append(".");
            double value = Double.parseDouble("0." + parts[1]);
            Set<Double> store = new HashSet<>();
            while (value > 0) {
                if (sb.substring(sb.indexOf(".")).length() + 1 > 32 || store.contains(value)) {
                    return "ERROR";
                }
                store.add(value);
                if (value >= 0.5) {
                    sb.append("1");
                    value = value * 2 - 1;
                } else {
                    sb.append("0");
                    value = value * 2;
                }
            }
        }
        if (isNeg == true) {
            sb.insert(0, "-");
        }
        return sb.toString();
    }
}