1. 问题描述:
给出基数为 -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 组成的数组。
示例:
输入:arr1 = [1,1,1,1,1], arr2 = [1,0,1]
输出:[1,0,0,0,0]
解释:arr1 表示 11,arr2 表示 5,输出表示 16 。
提示:
1 <= arr1.length <= 1000
1 <= arr2.length <= 1000
arr1 和 arr2 都不含前导零
arr1[i] 为 0 或 1
arr2[i] 为 0 或 1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/adding-two-negabinary-numbers
2. 思路分析:
① 一开始的时候想到的是先计算出两个数组对应的基数为-2的十进制数字,然后将他们的结果相加起来,判断相加的结果为正数还是负数,然后使用递归递归两个平行状态:当前位置是取0还是取1来不断接近我们需要求解的数字,在递归方法的出口判断出累加的结果是否等于了目标值假如等于了目标值那么返回结果即可,但是提交上去超时了
② 后面想到模拟两个数组对应位置相加的过程来得到对应的数字,与之前不同的是之前的基数都是正数的,所以进位的情况是比较好想出来的,因为这里是以-2为基底的所以处理进位会有所不同,我们可以对两个数字进行翻转然后对长度较短的一个数组进行补零,这样就可以先对低位进行相加了,一开始的时候进位carry设置为0,然后对两个数组对应位置相加,判断这个结果是否大于了1,假如大于了1说明是有进位的,因为是-2为基底的,所以所以相邻位置得到的数字是正负数交替的,所以当当前位置存在进位的时候,相当于是抵消了高位中的一个1,也就是进位为-1,当结果为负数的时候那么我们我们需要向高位借一个1,而这个时候进位是1的,结果为0的时候进位为0,最后将将这个结果添加到结果集中即可,并且我们需要判断最后的进位是否是0假如不是0那么需要添加两个1到结果集中,最后需要消除掉结果集中的前导0并且返回逆序的列表即可,终点是理解当相加的结果是大于0的时候进位应该是-1的,所以0的时候进位为1,因为相邻位置对应权重的值是正负数交替出现的,所以相当于是抵消了高位上的一个1
3. 代码如下:
模拟相加过程:
from typing import List
class Solution:
def addNegabinary(self, arr1: List[int], arr2: List[int]) -> List[int]:
len1, len2 = len(arr1), len(arr2)
arr1 = arr1[::-1]
arr2 = arr2[::-1]
# 判断哪一个的长度更长
if len1 < len2:
arr1 = arr1 + [0] * (len2 - len1)
len1 = len2
elif len1 > len2:
arr2 = arr2 + [0] * (len1 - len2)
carry = 0
res = list()
for i in range(len1):
t = arr1[i] + arr2[i] + carry
# 说明当前有进位
if t > 1:
# 这样往高位进位的时候应该是抵消高位中的一个1
carry = -1
t -= 2
elif t < 0:
carry = 1
t += 2
else:
carry = 0
res.append(t)
if carry != 0:
res += [1, 1]
while len(res) >= 2 and res[-1] == 0:
res.pop()
return res[::-1]
超时的递归:
from typing import List
class Solution:
def recursion(self, res: List[int], p: int, l: int, t: int, sum: int):
if t == sum: return True
if p > l: return False
# 存在两个平行状态
res.insert(0, 1)
if self.recursion(res, p + 1, l, t + (-2) ** p, sum): return True
# 回溯
res.pop(0)
res.insert(0, 0)
if self.recursion(res, p + 1, l, t, sum): return True
res.pop(0)
return False
def addNegabinary(self, arr1: List[int], arr2: List[int]) -> List[int]:
sum1, sum2 = 0, 0
# enumerate用于规定索引从那个值开始
for i, n in enumerate(arr1, 1):
if arr1[i - 1] != 0:
sum1 += (-2) ** (len(arr1) - i)
for i, n in enumerate(arr2, 1):
if arr2[i - 1] != 0:
sum2 += (-2) ** (len(arr2) - i)
sum = sum1 + sum2
if sum == 0: return [0]
if sum1 == 0 and sum2:
return arr2
elif sum2 == 0 and sum1:
return arr1
# 接下来最核心的是使用-2的基底来表示res
# 一开始的时候感觉可以使用递归来解决: 尝试所有的可能性
if sum > 0:
l = len(bin(sum)) + 1
else:
l = len(bin(sum)) + 1
res = list()
self.recursion(res, 0, l, 0, sum)
return res