IOS 算法(基础篇) ----- 公平的糖果棒交换

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 算法合集地址

你可能感兴趣的:(IOS 算法(基础篇) ----- 公平的糖果棒交换)