LC 1982. 从子集的和还原数组
https://leetcode-cn.com/problems/find-array-given-subset-sums/
这题思路有三个步骤:
- 将整个数组拆分成为两个数组A, B. 每个元素的差x = A - B是相同的。
- 假设这个差x, 那么说明存在x或者是-x. 如果是x那么继续拆分B,如果是-x那么继续拆分A
- 必须保证拆分元素里面存在一个元素0
其中2,3这个我想到了,但是第1点有点卡住了,没有想到特别有效的办法来做数组拆分。
看了题解之后才知道有个非常有效的解法,选择数组中最小和次小的元素A, B. 那么x = A - B. 这个证明非常简单:
- 如果元素都是非负数,那么结果是显而易见的。
- 如果元素里面有负数,那么最小值就是所有负数的和
- 而第二小的数,是从最小值从删除一个最大的负数,或者是加上一个最小的正数。
class Solution: def recoverArray(self, n: int, sums: List[int]) -> List[int]: sums.sort() print(sums) def split(data): delta = data[1] - data[0] from collections import Counter used = Counter() total = Counter(data) left, right = [], [] for i in range(len(data)): x = data[i] if used[x]: used[x] -= 1 continue left.append(x) exp = delta + x total[exp] -= 1 used[exp] += 1 right.append(exp) return left, right, delta def search(data, ans): if len(data) == 1: return data[0] == 0 left, right, exp = split(data) if 0 in left: ans.append(exp) if search(left, ans): return True ans.pop() if 0 in right: ans.append(-exp) if search(right, ans): return True ans.pop() return False ans = [] ok = search(sums, ans) return ans