翻转和镜像数字



我刚刚从互联网上拿起了一个面试问题,正在用 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
}
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
}
}
}

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

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
}

你可以试试

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
}

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

  • 遍历项目直至索引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

我的方法是使用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()

最新更新