【题目描述】
给你一个整数 n ,以二进制字符串的形式返回该整数的 负二进制(base -2)表示。注意,除非字符串就是 "0",否则返回的字符串中不能含有前导零。
示例 1:
输入:n = 2
输出:"110"
解释:(-2)2 + (-2)1 = 2
示例 2:
输入:n = 3
输出:"111"
解释:(-2)2 + (-2)1 + (-2)0 = 3
示例 3:
输入:n = 4
输出:"100"
解释:(-2)2 = 4
提示:
0 <= n <= 109
【题目链接】. - 力扣(LeetCode)
【解题代码】
package number;
public class BaseNeg2 {
public static void main(String[] args) {
System.out.println("计算结果:" + new BaseNeg2().baseNeg2(4));
}
public String baseNeg2(int n) {
// 定义一个字符串生成器
StringBuilder sb = new StringBuilder();
// 当前数据总和
int sum = 0;
// 当前位数值
int curDigitVal = 1;
// 当前最高值
int top = 2;
while (true) {
// 如果计入当前位数值,计算当前剩余数值
int remaining = n - sum - curDigitVal;
// 计算当前剩余数值是否合法:即目前后面位数不得为1
if ((remaining & (top - 1)) == 0) {
// 如果合法,计入当前位数值,字符串生成器加“1”
sum += curDigitVal;
sb.append(1);
} else {
// 如果不合法,计入当前位数值,字符串生成器加“0”
sb.append(0);
}
// 如果当前数据总和等于目标值,跳出循环
if (sum == n) {
break;
}
// 当前负二进制位数左移1位
curDigitVal *= -2;
// 当前最高位左移1位
top <<= 1;
}
return sb.reverse().toString();
}
// 第一次的老代码
public String baseNeg21(int n) {
StringBuilder sb = new StringBuilder();
int sum = 0;
int i = 0;
while (true) {
int curDigitVal = (int) Math.pow(-2, i++);
int mask = (1 << i) - 1;
int tmp = n - sum - curDigitVal;
if (tmp % 2 == 0 && (tmp & mask) == 0) {
sum += curDigitVal;
sb.append(1);
} else {
sb.append(0);
}
if (sum == n) {
break;
}
}
return sb.reverse().toString();
}
}
【解题思路】
拿到题目第一眼感觉没有什么思路,于是看了下提示:
意思是根据提示可得知此题的关键点就在于检查当前负二进制位是否计入数值,然后再逐个左移检查,根据示例可以猜想出当前二进制位是否合理点:
- 目标值减去当前所有计入数值负二进制位之和的余数,能被2整除;
- 目标值减去当前所有计入数值负二进制位之和的余数,不可以包含低位2进制。因为往后添加的都是高位二进制;
按照这个思路很快写出代码,并提交成功
但运行结果执行用时分布是1MS,不是理想的0MS,应该哪里可以优化一下, 仔细检查了下代码,看到m,k等数值存在重复计算,于是又优化了一下。最终达到预计的0毫秒
【解题步骤】
- 定义字符串生成器,当前数据总和,当前位数值,当前最高值等变量;
StringBuilder sb = new StringBuilder(); int sum = 0; int curDigitVal = 1; int top = 2;
- 开启一个循环逐个检查当前负二进制位,计算出如果计入当前负二进制位数值,前剩余数值;
while (true) { int remaining = n - sum - curDigitVal;
- 如果剩余数值合法,计入当前位数值,字符串生成器加“1”,否则字符串生成器加“0”
if ((remaining & (top - 1)) == 0) { sum += curDigitVal; sb.append(1); } else { sb.append(0); }}
- 如果当前数据总和等于目标值,跳出循环
if (sum == n) { break; }
- 当前负二进制位数左移1位,当前最高位左移1位
curDigitVal *= -2; top <<= 1;
- 字符串生成器中逆序返回结果字符串
return sb.reverse().toString();
【思考总结】
- 此题解法的关键点就在于“目标值减去当前所有计入数值负二进制位之和的余数,不可以包含低位2进制”
- 程序员对于与、或、非、移位等这些位操作基本功一定要十分精通,了然于胸;
- 算法优化要精益求精:关键点要斤斤计较,拒绝重复计算;
- LeetCode解题之前,一定不要看题解,看了就“破功”了!