「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」
前言
笔者除了大学时期选修过《算法设计与分析》和《数据结构》还是浑浑噩噩度过的(当时觉得和编程没多大关系),其他时间对算法接触也比较少,但是随着开发时间变长对一些底层代码/处理机制有所接触越发觉得算法的重要性,所以决定开始系统的学习(主要是刷力扣上的题目)和整理,也希望还没开始学习的人尽早开始。
系列文章收录《算法》专栏中。
问题描述
给定两个 01 字符串 a 和 b ,请计算它们的和,并以二进制字符串的形式输出。
输入为 非空 字符串且只包含数字 1 和 0。
示例 1:
输入: a = "11", b = "10"
输出: "101"
示例 2:
输入: a = "1010", b = "1011"
输出: "10101"
提示:
- 每个字符串仅由字符 '0' 或 '1' 组成。
- 1 <= a.length, b.length <= 10^4
- 字符串如果不是 "0" ,就都不含前导零。
确定学习目标
对《二进制加法》的算法过程进行剖析。
剖析
- 首先对二进制进行单纯的加法并不难,直接使用十进制去理解,无非是进位不一样,从逢十进一改成逢二进行。
- 拿到字符串进行从后开始取每一位进行相加,以长度较长字符串为基准,长度较短的缺少位按照0进行补位即可。
- 设每位相加的结果为a,进位(没有或者不足就是0)为b,每位相加的结果为c,每位进位为d。那么c=(a+b)%2;d=(a+b)/2。
- 最后判断进位是否大于0,是的话最高位补一位为1。
- 由于是从最后位开始的结果需要倒转。
此算法没有涉及到新的知识点,无非就是看你对事务本质的理解并使用代码去实现它,所以还算比较简单。
注意需要对字符串进行非空和只包含数字 1 和 0的判断和限制。
代码
/**
* 1. 首先对二进制进行单纯的加法并不难,直接使用十进制去理解,无非是进位不一样,从逢十进一改成逢二进行。
* 2. 拿到字符串进行从后开始取每一位进行相加,以长度较长字符串为基准,长度较短的缺少位按照0进行补位即可。
* 3. 设每位相加的结果为a,进位(没有或者不足就是0)为b,每位相加的结果为c,每位进位为d。那么c=(a+b)%2;d=(a+b)/2。
* 4. 最后判断进位是否大于0,是的话最高位补一位为1。
* 5. 由于是从最后位开始的结果需要倒转。
*
* @param a
* @param b
* @return
*/
public static String addBinary2(String a, String b) {
//进行非空判断
if (isEmpty(a) || isEmpty(b)) {
throw new RuntimeException("a或b存在为空");
}
int al = a.length();
int bl = b.length();
//对长度进行判断
if (al > 10000 || bl > 10000) {
throw new RuntimeException("a或b存在长度大于10000");
}
//取al和bl之间较大的,用于以长度较长字符串为基准来遍历
int max = Math.max(al, bl);
//进位默认位0
int carry = 0;
StringBuffer result = new StringBuffer();
for (int i = 0; i < max; i++) {
if (i <= al - 1) {
char aCharAt = a.charAt(i);
//每个字符串仅由字符 '0' 或 '1' 组成
if ((aCharAt != '0' && aCharAt != '1')) {
throw new RuntimeException("a或b包含除0和1之外的字符");
}
}
if (i <= bl - 1) {
char bCharAt = b.charAt(i);
//每个字符串仅由字符 '0' 或 '1' 组成
if ((bCharAt != '0' && bCharAt != '1')) {
throw new RuntimeException("a或b包含除0和1之外的字符");
}
}
//从最后一位开始,位不足补0
carry += i < al ? a.charAt(al - 1 - i) - '0' : 0;
carry += i < bl ? b.charAt(bl - 1 - i) - '0' : 0;
//每位相加的结果为c,c=(a+b)%2。这里需要字符所以需要+'0'对应的ascii码(为48)再强转为char
result.append((char) (carry % 2 + '0'));
//每位进位为d,d=(a+b)/2
carry /= 2;
}
//最后判断进位是否大于0,是的话最高位补一位为1。
if (carry > 0) {
result.append('1');
}
//由于是从最后位开始的结果需要倒转。
return result.reverse().toString();
}