A, B有不同大小的糖果棒:A[i] 是A拥有的第 i 根糖果棒的大小,B[j] 是B拥有的第 j 根糖果棒的大小。他们想交换一根糖果棒,这样交换后,他们都有相同的糖果总量。(一个人拥有的糖果总量是他们拥有的糖果棒大小的总和。)返回一个整数数组 ans,其中 ans[0] 是A必须交换的糖果棒的大小,ans[1] 是 B必须交换的糖果棒的大小。如果有多个答案,你可以返回其中任何一个。保证答案存在。
例子:
A = [1,1], B = [2,2] 返回:[1,2]
A = [1,2], B = [2,3] 返回:[1,2]
A = [2], B = [1,3] 返回:[2,3]
A = [1,2,5], B = [2,4] 返回:[5,4]
解题思路
1.双指针
首先我们看下
例如: A = [1,1], B = [2,2], sum为数组所有元素相加之和
sumA = 1+1 = 2, sumB = 2+2 = 4, sumA - SumB = -2
两者相差 -2, 则找到A中元素与B中元素相差 -1 ( (sumA-sumB)/2 )互换即可
故返回 [1, 2], 1-2 = -1, 转换后 新A = [1, 2], 新B = [2, 1], 总量相等
同理
例如: A = [1,2], B = [2,3], sumA = 3, sumB = 5, sumA - SumB = -2, (sumA - SumB) / 2 = -1
则返回 [1, 2], 其实返回 [2, 3]也是正确的
例如: A = [1,2,5], B = [2,4], sumA = 8, sumB = 6, sumA - SumB = 2, (sumA - SumB) / 2 = 1
返回 [5, 4]
按照题意我们可以机械翻译
从A, B中 找到 A[i] - B[j] == (sumA - SumB) / 2 即可
求和, 取差比较好处理
重点循环取差 这块我们采用用双指针进行处理 (其实2次for循环也可处理, 不过数据量比较大情况下会超时)
i为A指针(其实理解成数组下标也可以)
j为B指针
A[i] - B[j] = (sumA - SumB) / 2 返回: [A[i], B[j]]
A[i] - B[j] < (sumA - SumB) / 2 i++
A[i] - B[j] > (sumA - SumB) / 2 j++
未翻译版
func fairCandySwap(_ A: [Int], _ B: [Int]) -> [Int] {
let sumA = A.reduce(0, +), sumB = B.reduce(0, +)
let diff = (sumA - sumB) / 2
var tempA = A.sorted(), tempB = B.sorted(), i = 0, j = 0
while i < tempA.count && j < tempB.count {
let diffAB = tempA[i] - tempB[j]
if diffAB > diff { j += 1 }
else if diffAB < diff { i += 1 }
else if diffAB == diff { return [tempA[i], tempB[j]] }
}
return []
}
翻译版
func fairCandySwap(_ A: [Int], _ B: [Int]) -> [Int] {
// reduce 求和方法, 令sumA, sumB为A, B中所有元素相加之和
let sumA = A.reduce(0, +), sumB = B.reduce(0, +)
// 找到A, B之中差值, 例如A = [2,3], B = [1, 2] 总和差值2, 那么交换个相差为1即可达到平衡
let diff = (sumA - sumB) / 2
// sorted, 将A, B正序排序, 防止乱序同时乱序双指针不好处理一些
// i为tempA中指针(理解成数组下标也可以), j为tempB指针
var tempA = A.sorted(), tempB = B.sorted(), i = 0, j = 0
// 循环i, j
while i < tempA.count && j < tempB.count {
// 令diffAB为A, B中对应, i, j下标的差值
let diffAB = tempA[i] - tempB[j]
// 如果大于, 令 j = j + 1, tempB[j]大一点, diffAB小一些, 以求差值接近 diff
if diffAB > diff { j += 1 }
// 如果小于, 令i = i + 1, tempA[j]大一点, diffAB大一些, 以求差值接近 diff
else if diffAB < diff { i += 1 }
// 如果相等 tempA[i], tempA[j] 就是我们想要的, 直接返回[tempA[i], tempB[j]]
else if diffAB == diff { return [tempA[i], tempB[j]] }
}
return []
}
2.哈希法
哈希法我认为是个比较好方法, 代码量也比较少
求和, 差值的解释可以参考双指针一样的
因为我们想找到 A, B中相差为差值diff的两个元素
那么我们循环判断, A中是否包含 "B + 差值" 这样也可以
故我们可以机械翻译
未翻译版
func fairCandySwap(_ A: [Int], _ B: [Int]) -> [Int] {
let sumA = A.reduce(0, +), sumB = B.reduce(0, +)
let diff = (sumA - sumB) / 2, tempA = Set(A);
for i in B {
let cA = i + diff
if tempA.contains(cA) {
return [cA, i]
}
}
return []
}
翻译版
func fairCandySwap(_ A: [Int], _ B: [Int]) -> [Int] {
// reduce 求和方法, 令sumA, sumB为A, B中所有元素相加之和
let sumA = A.reduce(0, +), sumB = B.reduce(0, +)
// 找到A, B之中差值, 例如A = [2,3], B = [1, 2] 总和差值2, 那么交换个相差为1即可达到平衡
// 其实不加Set方法也可以, 不过不加Set方法会超时
let diff = (sumA - sumB) / 2, tempA = Set(A);
// 循环B中元素
for i in B {
// 令cA 为 i + diff
let cA = i + diff
// 如果A中包含cA, 即此时cA与i就是要找的, 返回[cA, i]
if tempA.contains(cA) {
return [cA, i]
}
}
return []
}
题目来源:力扣(LeetCode) 感谢力扣爸爸 :)
IOS 算法合集地址