⭐️前面的话⭐️
本篇文章介绍【1073. 负二进制数相加】题解,算法标签:【数学】,【思维】,【模拟算术】,展示语言c++/java。
📒博客主页:未见花闻的博客主页
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
📌本文由未见花闻原创,CSDN首发!
📆首发时间:🌴2022年5月18日(于19日补发)🌴
✉️坚持和努力一定能换来诗与远方!
💭推荐书籍:📚《算法》,📚《算法导论》
💬参考在线编程网站:🌐牛客网🌐力扣
博主的码云gitee,平常博主写的程序代码都在里面。
博主的github,平常博主写的程序代码都在里面。
🍭作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!
📌导航小助手📌
- ⭐️1073. 负二进制数相加⭐️
- 🔐题目详情
- 💡解题思路
- 🔑源代码
- 🌱总结
⭐️1073. 负二进制数相加⭐️
🔐题目详情
1073. 负二进制数相加
难度中等
给出基数为 -2 的两个数 arr1
和 arr2
,返回两数相加的结果。
数字以 数组形式 给出:数组由若干 0 和 1 组成,按最高有效位到最低有效位的顺序排列。例如,arr = [1,1,0,1]
表示数字 (-2)^3 + (-2)^2 + (-2)^0 = -3
。数组形式 中的数字 arr
也同样不含前导零:即 arr == [0]
或 arr[0] == 1
。
返回相同表示形式的 arr1
和 arr2
相加的结果。两数的表示形式为:不含前导零、由若干 0 和 1 组成的数组。
示例 1:
输入:arr1 = [1,1,1,1,1], arr2 = [1,0,1]
输出:[1,0,0,0,0]
解释:arr1 表示 11,arr2 表示 5,输出表示 16 。
示例 2:
输入:arr1 = [0], arr2 = [0]
输出:[0]
示例 3:
输入:arr1 = [0], arr2 = [1]
输出:[1]
提示:
1 <= arr1.length, arr2.length <= 1000
arr1[i]
和arr2[i]
都是0
或1
arr1
和arr2
都没有前导0
💡解题思路
解题思路
思路1:最简单的方案就是,将数转换为十进制,进行计算后,将得到的结果转换为二级制数组,但是数组长度最大为
1000
1000
1000,必然会爆int
,因此该方案不可取。
思路2:模拟加减计算,我们可以先将两个数组对应相加,得到一个新数组,新数组长度大于原来俩数组中最大长度
10
10
10个大小肯定够了,进位也不可能进10
位。
加减计算后,由于原来数组只有0
或1
,进行加法后,可能取值为0
,1
,-1
,因为是基础权重是负数,由于相邻的俩位,是少乘以一个负数的关系,所以相邻位正负号一定相反,所以当需要进位时,其实就是在前一位减去对应的进位权重即可,如当前位为2
,则可进位,进位本质上就是加上
2
×
(
−
2
)
x
=
−
(
−
2
)
x
+
1
2 \times(-2)^{x}=-(-2)^{x+1}
2×(−2)x=−(−2)x+1,即在前一位需要减去1
,由于“减位”机制的存在,数组取值可能还会出现-1
。
那如果当前位取值为-1
时,如何处理呢?其实我们不难列出如下一个等式:
(
−
1
)
×
(
−
2
)
x
=
(
−
2
)
x
+
(
−
2
)
x
+
1
(-1) \times(-2)^{x}=(-2)^{x}+(-2)^{x+1}
(−1)×(−2)x=(−2)x+(−2)x+1
因此我们只需将该位处理成
1
1
1,前一位加上
1
1
1即可。在这里会将前一位加上
1
1
1,因此数组可能取值又多了3
。
综上所述,数组取值可能为-1
,0
,1
,2
,3
,处理情况如下:
- 数组元素大于
1
,将前一位减去1
,当前位取2
的模。 - 数组元素为
1
或0
,无需处理。 - 数组元素为
-1
,将当前位处理为1
,前一位加1
。
🔑源代码
C++代码:
class Solution
{
public:
vector<int> addNegabinary(vector<int>& arr1, vector<int>& arr2)
{
//第一步,统一调整数组,使得第一个数组长度更加大
int size1 = arr1.size();
int size2 = arr2.size();
if (size2 > size1)
{
vector<int> tmp(arr1);
arr1 = arr2;
arr2 = tmp;
}
size1 = arr1.size();
size2 = arr2.size();
//第二步,进行两个数组的加减法
int cur1 = size1 - 1;
int cur2 = size2 - 1;
vector<int> sum(size1 + 10);
int i = sum.size() - 1;
while (cur2 >= 0) sum[i--] = arr1[cur1--] + arr2[cur2--];
//处理剩余数字
while (cur1 >= 0) sum[i--] = arr1[cur1--];
//第三步,调整非法数字,由于初始数组值为0或1,进行加减法进行借位运算,最大值为3,最小值为-1
i = sum.size() - 1;
while (i >= 0)
{
if (sum[i] >= 2)
{
//情况1,数值大于2,因为前一位符号相反,所以等价前位减去对应借位数
sum[i - 1] -= sum[i] / 2;
sum[i] = sum[i] % 2;
} else if (sum[i] == -1)
{
//情况2,数值为-1,借位造成,可以将当前位设置为1,前位加1等价解决
sum[i - 1] += 1;
sum[i] = 1;
}
i--;
}
// 去除前导0,但是至少保留一位
if (sum[0] != 0) return sum;
else
{
//最终长度
int finalLen = sum.size() - 1;
//与sum数组长度差值(前导0个数)
int k = 1;
//求前导0个数,并求对应结果数组长度
int j = 1;
while (j < sum.size() && sum[j] == 0)
{
j++;
finalLen--;
k++;
}
if (finalLen <= 0) finalLen = 1;
vector<int> ans(finalLen);
//拷贝数组
for (j = 0; j < finalLen && j + k < sum.size(); j++)
{
ans[j] = sum[j + k];
}
return ans;
}
}
};
Java代码:
class Solution {
public int[] addNegabinary(int[] arr1, int[] arr2) {
//使得第一个数组长度更长,如果短,则交换
int len1 = arr1.length;
int len2 = arr2.length;
if (len2 > len1) {
int[] tmp = arr1;
arr1 = arr2;
arr2 = tmp;
}
len1 = arr1.length;
len2 = arr2.length;
//首先进行对应位的加减法
int cur1 = len1 - 1;
int cur2 = len2 - 1;
int[] sum = new int[len1 + 10];
int i = sum.length - 1;
//两个数组的加减法
while (cur2 >= 0) {
sum[i--] = arr1[cur1--] + arr2[cur2--];
}
while (cur1 >= 0) {
sum[i--] = arr1[cur1--];
}
// 处理非0非1的数,最极限情况进2位
i = sum.length - 1;
while (i >= 0) {
if (sum[i] > 1) {
sum[i - 1] -= sum[i] / 2;
sum[i] = sum[i] % 2;
} else if (sum[i] == -1) {
sum[i] = 1;
sum[i - 1] += 1;
}
i--;
}
//处理前导0,最少留一个
if (sum[0] != 0) return sum;
else {
int finalLen = sum.length - 1;
int k = 1;
int j = 1;
//处理后续前导0
while (j < sum.length && sum[j] == 0) {
finalLen--;
k++;
j++;
}
//保证最少有一个前导0
if (finalLen == 0) finalLen = 1;
int[] ans = new int[finalLen];
for (j = 0; j < finalLen && j + k < sum.length; j++) {
ans[j] = sum[j + k];
}
return ans;
}
}
}
🌱总结
进位规律探索,进位模拟。