原题如下:
将写有数字的n个纸片放入一个纸箱子中,然后你和你的朋友从纸箱子中抽取4张纸片,每次记下纸片上的数字后放回子箱子中,如果这4个数字的和是m,代表你赢,否则就是你的朋友赢。
请编写一个程序,当纸片上所写的数字是a1,a2,a3,a4,..,an时,是否存在抽取4次和为m的方案,如果存在,输出YES;否则,输出NO。
首先想到最简单的方案是直接4层循环:
func jude(_ m: Int, _ a: [Int]) -> Bool {
for a1 in a {
for a2 in a {
for a3 in a {
for a4 in a {
if a1 + a2 + a3 + a4 == m {
return true
}
}
}
}
}
return false
}
时间复杂度是O(n^4),这个时间复杂度太大了。。。
给定的条件是:
ai + aj + as + at = m
我们可以变换一下等式,使之成为:
(ai + aj) + (as + at) = m
这样就变成了找两个数的和等于定值了:
a + b = sum
a、b可以看成是数组中任意两个数组相加的合值。那么求解过程可以表示为先算出数组中任意两个数两两相加的一个新数组,然后在这个新数组中找两个数,使得他们的和等于定值。
var sumArray = [Int]()
for a1 in a {
for a2 in a {
let sum = a1 + a2
sumArray.append(sum)
}
}
得到数组中任意两数两两相加和的数组sumArray
.
寻找两个数的和为定值:
for s1 in sumArray {
for s2 in sumArray {
if m == s1 + s2 {
return true
}
}
}
完整代码如下:
func jude(_ m: Int, _ a: [Int]) -> Bool {
var sumArray = [Int]()
for a1 in a {
for a2 in a {
let sum = a1 + a2
sumArray.append(sum)
}
}
for s1 in sumArray {
for s2 in sumArray {
if m == s1 + s2 {
return true
}
}
}
return false
}
测试一下:
let ret = jude(10, [1, 3, 5])
print(ret)//true
let ret = jude(9, [1, 3, 5])
print(ret)//false
这种解法的时间复杂度是O(n^2)。