2020年6月23日 二进制求和 addBinary
默认格式:
class Solution {
public String addBinary(String a, String b) {
}
}
解题思路:
这道题非常简单,主要就是考察对于二进制理解,有两种将二进制变为十进制的方式与运算+位移和读取字符判断然后根据位数加上一个数。
这道题需要求的是二进制的结果,所以不适合转为数字来计算,应该直接处理字符串。
题目中给出了字符串的一些约定,所有我们可以直接通过判断得出结果字符串的长度。
在做的过程中发现,这道题实际考察的是对字符串的处理和底层计算机加法寄存器的理解。我们需要用代码来模拟一个加法寄存器。
代码部分:
虽然把功能给实现了,但是我是不满意的,我希望能够再进一步,所以对原算法进行处理。
public String addBinary(String a, String b) {
//取出字符数组方便处理,不增加空间复杂度,因为chars是存在String对象中的
char[] aChars=a.toCharArray();
char[] bChars=b.toCharArray();
//标志位,记录进阶数
boolean flag=false;
//记录当前数值
char ca;
char cb;
StringBuilder res=new StringBuilder();
//循环条件,只要有一个没有结束,循环就不结束
for (int i=0;i<aChars.length||i<bChars.length;i++){
//确认a没有越界,读取a对应的字符,越界之后记为0
if (aChars.length-i>0){
ca=aChars[aChars.length-1-i];
}
else
{
ca='0';
}
//确认b没有越界,读取b对应的字符,越界之后记为0
if (bChars.length-i>0){
cb=bChars[bChars.length-1-i];
}
else
{
cb='0';
}
//对读取到的数进行计算
//a,b都为1
if (ca=='1'&&cb=='1'){
//进位为1,结果为1
if (flag){
res.insert(0,'1' );
}
//进位为0时,结果为0
else
{
res.insert(0,'0' );
}
//进位变为1
flag=true;
}
//如果其中一个为1
else if ((ca=='1'&&cb=='0')||(ca=='0'&&cb=='1')){
//进位为1时,结果是0,进位是1
if (flag){
res.insert(0,'0' );
}
//进位是1时,结果是0,进位为1
else {
res.insert(0,'1' );
}
}
//两个都为0的情况
else {
//进位为0,结果为0
if (flag){
res.insert(0,'1' );
}
//进位是1时,结果是1
else {
res.insert(0,'0' );
}
//进位置0
flag=false;
}
}
//结尾的时候进制如果还有值,再加一个
if (flag)
res.insert(0,'1' );
return res.toString();
}
优化:
1,自己实现字符串的插入功能。
我们知道二进制的加法得到的长度不会超过原本的长度+1,比如两个3位长度的最大值111+111=1110最大的长度也只能加1,而这个最高位就是计算最后得到的进位,也就是说,我们完全可以构建一个长度为a,b中最长的那个数组的长度,然后先计算结果,最后加上进制。
这么做的好处是节省了字符串的拼接工作,虽然有StringBulider来帮助我们改变字符串,但是字符串本身是不可变的特性导致这个修改字符串的功能必定需要大量的时间复杂度。
最后的结果在2-3之间徘徊。
public String addBinary(String a, String b) {
//取出字符数组方便处理,不增加空间复杂度,因为chars是存在String对象中的
char[] aChars=a.toCharArray();
char[] bChars=b.toCharArray();
char[] res;
if (a.length()>b.length())
{
res=new char[a.length()];
}else
res=new char[b.length()];
//标志位,记录进阶数
boolean flag=false;
//记录当前数值
char ca;
char cb;
//循环条件,只要有一个没有结束,循环就不结束
for (int i=0;i<res.length;i++){
//确认a没有越界,读取a对应的字符,越界之后记为0
if (aChars.length-i>0){
ca=aChars[aChars.length-1-i];
}
else
{
ca='0';
}
//确认b没有越界,读取b对应的字符,越界之后记为0
if (bChars.length-i>0){
cb=bChars[bChars.length-1-i];
}
else
{
cb='0';
}
//对读取到的数进行计算
//a,b都为1
if (ca=='1'&&cb=='1'){
//进位为1,结果为1
if (flag){
res[res.length-i-1]='1';
}
//进位为0时,结果为0
else
{
res[res.length-i-1]='0';
}
//进位变为1
flag=true;
}
//如果其中一个为1
else if ((ca=='1'&&cb=='0')||(ca=='0'&&cb=='1')){
//进位为1时,结果是0,进位是1
if (flag){
res[res.length-i-1]='0';
}
//进位是1时,结果是0,进位为1
else {
res[res.length-i-1]='1';
}
}
//两个都为0的情况
else {
//进位为0,结果为0
if (flag){
res[res.length-i-1]='1';
}
//进位是1时,结果是1
else {
res[res.length-i-1]='0';
}
//进位置0
flag=false;
}
}
//结尾的时候进制如果还有值,再加一个
if (flag)
return '1'+new String(res);
return new String(res);
}
2,由于需要经常读取res.length,而这个参数是通过计算得到的,而又不会变动,所以我们完全可以记录下这个长度,免得每次都要去查数组的长度。
OK,大概率使用2ms的运行时间了