我使用Swift 4以两种不同的方式实现了下面的numJewelsInStones
函数。
我想比较每个实现的时间和空间复杂性。但是,我在一个实现中使用了一些本地方法,例如filtering a string
,然后在另一个实现中使用mapping a string to an array of single characters
。我想知道这些本机函数的时间复杂性。另外,如果我使用字符串范围来获取字符串中每个字符的出现,该怎么办?我想了解Swift中的这些本机函数如何影响整体Big O.
实施1: 过滤一个字符串(如果我忽略过滤函数我会说Big O是O(n),使用for循环,这是正确的吗?)
//J - represents types of stones that are jewels
//S - represents the stones I have
func numJewelsInStones(_ J: String, _ S: String) -> Int {
var sum = 0 //Sum - represents how many of the stones I have are also jewels
for jewel in J {
sum = sum + S.filter {$0 == jewel}.count //add sum of occurrences for each stone that is a jewel
}
return sum
}
print(numJewelsInStones("aA", "aAAbbbb")) //prints 3
print(numJewelsInStones("z", "ZZ")) //prints 0
实施2:
我做的第一件事是将字符串映射到单个字符数组,否则我会得到错误'无法在行counts[stone] = (counts[stone] ?? 0) + 1
<上使用类型为字符的索引子类型字符串[String:Int]的子字符串/ p>
UPDATE
:只是注意到我意识到我甚至不需要将字符串映射到字符数组,如果我只是将计数字典的定义更改为var counts: [Character: Int] = [:]
以避免上面的错误。哎呀。我是为了这个问题而原样离开的。
func numJewelsInStones2(_ J: String, _ S: String) -> Int {
let jewels = J.map { String($0) }
let stones = S.map { String($0) }
var counts: [String: Int] = [:]
var sum = 0
for stone in stones {
counts[stone] = (counts[stone] ?? 0) + 1 //frequency count dict
}
for jewel in jewels { //for every jewel
if let count = counts[jewel] { //if the jewel exists in the frequency count dict
sum = sum + count //add its count to the total sum
}
}
return sum
}
print(numJewelsInStones2("aA", "aAAbbbb")) //prints 3
print(numJewelsInStones2("z", "ZZ")) //prints 0
答案 0 :(得分:4)
Swift标准库中的所有高阶函数,例如map
,flatMap
/ compactMap
,filter
和reduce
都有{{1}一般来说,时间复杂度,因为所有这些都在他们被调用的完整集合上工作,他们只访问每个元素一次,因此它们具有线性时间复杂度。
考虑到这一点,您的第一个实施具有O(n)
时间复杂度,因为O(J*S)
中的每个元素都使用J
遍历S
的所有元素。
另一方面,您的第二个实现具有大致线性的时间复杂度,具体取决于filter
中有String
个Character
,S
或J
,其时间复杂度为O(J)
或O(S)
,因为您没有任何嵌套循环,所以您只能顺序遍历J
和S
。
实施1或2是否更有效取决于J
和S
的大小。
答案 1 :(得分:1)
flatMap / compactMap
取O(m + n)
,其中n
是此序列的长度,而m
是结果的长度。
这是用iOS SDK文档编写的。