翻转和镜像编号

时间:2018-10-23 16:11:14

标签: swift algorithm data-structures

我刚刚从互联网上获得了一个面试问题,并与Swift一起练习。

问题如下:

给出一个字符串数组的输入,验证是否将其旋转180度是否为“相同”。

例如:

[1, 6, 0, 9, 1] => return true 
[1, 7, 1] => return false

我想出了以下方法,将镜像数字放在字典中,然后检查给定数组中是否有任何数字与字典数字不匹配。

似乎可以在基本测试用例中使用,但是我想知道是否遗漏了什么吗?

func checkRotation (nums : [Int]) -> Bool
{
    var dict = [Int : Int]()
    dict  = [0:0, 1:1, 2:5, 5:2, 6:9, 8:8, 9:6]

    for n in nums
    {
        guard let exist = dict[n] else
        {
            return false
        }
    }
    return true
}

5 个答案:

答案 0 :(得分:4)

extension Collection where Element == Int {
    func isFlipMirrored() -> Bool {
        let mirrors = [0:0, 1:1, 6:9, 8:8, 9:6]
        return zip(self, self.reversed()) // Create tuples of each element and its opposite
            .allSatisfy {                 // Return whether all of them match the rule:
                mirrors[$0] == $1         // That the element matches its opposite's mirror
        }
    }
}

这虽然没有达到应有的效率,但它非常简单而且很关键。它只是以相反的顺序验证了序列中的每个元素都与镜像的元素相同。

仅检查元素的前半部分会更有效,但是这是一个相当小的优化,需要额外的条件,因此我不确定对于较小的N来说是否真的会更快。在使代码过于复杂之前进行概要分析。

当然,仅仅是因为它实际上并没有变慢(即我没有分析过要知道的事实),这并不意味着采访者不会因为这段代码会进行多余的检查而感到困惑。关于绩效的误解很多,而且似乎都出现在面试问题中。因此,让我们让面试官高兴,只检查清单的后半部分与后半部分。

extension Collection where Element == Int {
    func isFlipMirrored() -> Bool {
        let mirrors = [0:0, 1:1, 6:9, 8:8, 9:6]

        // May test one more thing than we technically have to, but fewer conditionals
        let midpoint = count / 2 + 1

        return zip(self.prefix(midpoint),             // Create tuples of the left-half of the list,
                   self.reversed().prefix(midpoint))  //    and the right half
            .allSatisfy {                 // Return whether all of them match the rule:
                mirrors[$0] == $1         //     that the element matches its opposite's mirror
        }
    }
}

答案 1 :(得分:2)

要知道数组是否可转换,您需要

  • 遍历项直到索引N/2(包括奇数长度数组的中间项)

  • 检查所有项目是否都属于字典

  • 检查dict[nums[i]] == nums[N-i-1]

我不了解Swift,但是Python示例应该看起来非常接近:

def isconv(lst):
    dict = {0:0, 1:1, 2:5, 5:2, 6:9, 8:8, 9:6}
    N = len(lst)
    for i in range((N + 1) // 2):
        if (lst[i] not in dict) or (dict[lst[i]] != lst[N - 1 - i]):
            return False
    return True

print(isconv([1,6,0,9,1]))
print(isconv([5,5,2,2]))
print(isconv([1,6,0,6,1]))
print(isconv([1,4,1]))
>>True
>>True
>>False
>>False

答案 2 :(得分:2)

我的方法是使用prefix来限制数据集,并使用enumerated来同时枚举索引和值。放入lazy中,这样就不会产生大量的数组副本,而只处理相关的内容。

extension Array where Element == Int {
    func isMirrored() -> Bool {
        let flipped = [0:0, 1:1, 2:5, 5:2, 6:9, 8:8, 9:6]

        return lazy                         // means we won't make 3 copies of arrays
            .prefix((count + 1) / 2)        // stops the enumeration at the midway point
            .enumerated()                   // enumerates over (index, value)
            .allSatisfy { (index, value) in // verify all elements meet the criteria below

            // make sure each reversed element matches it's flipped value
            // Note you don't have to explicitly check for nil, since
            // '==' works on Optional<Int>
                return flipped[value] == self[count - index - 1]
            }
    }
}

[1, 6, 0, 9, 1].isMirrored()
[1, 7, 1].isMirrored()

答案 3 :(得分:1)

您可以尝试

func checkRotation (nums : [Int]) -> Bool
{
    var dict = [0:0, 1:1, 2:5, 5:2, 6:9, 8:8, 9:6]
    return nums.filter{ dict[$0] != nil }.count == nums.count

}

func checkRotation (nums : [Int]) -> Bool
{
    var dict = [0:0, 1:1, 2:5, 5:2, 6:9, 8:8, 9:6]
    return nums.compactMap{ dict[$0]}.count == nums.count

}

答案 4 :(得分:1)

我的代码存在一些问题,在下面对此进行了注释:

func checkRotation /* Why the space here? */ (nums /* Why the space here? */ : [Int]) -> Bool
{ // Brackets like this aren't Swift's code style
    // Dict is a horrible name. I can see that it's a dictionary. What is it a dict *of*?!
    var dict = [Int : Int]() // Why is this a `var` variable, that's assigned an empty initial value
    dict  = [0:0, 1:1, 2:5, 5:2, 6:9, 8:8, 9:6] // only to be immediately overwritten?

    for n in nums // This should be a `contains(_:)` call, rather than explicit enumeration
    {
        // If you're not using a `contains(_:)` check, you should at least use a `where` clause on the for loop
        guard let exist = dict[n] else // "exist" is a bad variable name, and it's not even used. Replace this with a `dict[n] != nil` check.
        {
            return false
        }
    }
    return true
}

这是我用类似的方式写它的方式:

func checkRotation(nums: [Int]) -> Bool {
    let mirroredDigits = [0:0, 1:1, 2:5, 5:2, 6:9, 8:8, 9:6]

    for n in nums where mirroredDigits[n] == nil {
        return false
    }
    return true
}