给定一个数组如A=[3, 34, 4, 12, 5, 2],再给定一目标数字S。现要求判断在A中能否找到m个数字,使其和等于S,若可以找到这样的数字,返回True,否则返回false。
分析:
首先不可否认,这是一道可以使用回溯解决的问题,如果使用回溯,这个问题的时间复杂度为2^n,anyway, 我们先使用回溯实现一下练练手:
import numpy as np
A = [3, 34, 4, 12, 5, 2]
int S
flag = np.zeros(len(A))
def dfs(depth):
if depth == len(A):
ansList = [A[i] for i in range len(A) if flag[i] == 1]
ans = 0
for i in range(len(ansList)):
ans += ansList[i]
if ans == S:
print(True)
return
for i in range(2):
flag[depth] = i;
dfs(i + 1)
flag[depth] = 0;
dfs(0)
那么如果使用递归该如何实现呢?
可以定义一个函数f(i, j)表示从右往左扫描到数组A下标为i的位置的时候,剩下的数求和要等于j,那么可以得到这样的状态转移方程:
f(i, j) = f(i - 1, j) or f(i - 1, j - A[i])
接下来处理边界条件:
若j == 0 直接返回True
若i == 0 返回 A[0] == j
(我觉得这个边界条件可以不要)若A[j] > remain 返回 f(i - 1, j)
使用递归的方法编程实现代码如下:
import numpy as np
A = [3, 34, 4, 12, 5, 2, 8]
S = 9
flag = np.zeros(len(A))
def re_dp(i, remain):
if i == 0:
return A[i] == remain
elif remain == 0:
return true
elif A[i] > remain:
return re_dp(i - 1, remain)
else:
return re_dp(i - 1, remain) or re_dp(i - 1, remain - A[i])
re_dp(len(A) - 1, S)
使用递归的效率不是很好,最后使用动态规划的解法如下:
import numpy as np
A = [3, 34, 4, 12, 5, 2, 8]
S = 9
# 设置一个二维数组,宽为S + 1,高为len(A)
flag_arr = np.reshape(np.zeros(len(A)*(S + 1), dtype = bool), (len(A), S + 1))
def dp():
for i in range(len(A)):
for j in range(S + 1):
if j == 0:
flag_arr[i][j] = True
elif i == 0 and A[0] == j:
flag_arr[i][j] = True
elif A[i] > j:
flag_arr[i][j] = flag_arr[i - 1][j]
else:
flag_arr[i][j] = flag_arr[i - 1][j] or flag_arr[i - 1][j - A[i]]
return flag_arr[len(A) - 1][S]
dp()
print(flag_arr)