求数组内所有和为一个数的情况,第一眼觉得这题应该挺简单的吧,然后慢慢的做,后来发现这题有点东西,现在就把做出来的写一下。个人想法,而且代码可能不是很简洁,大佬们看到请指点!第一次写这种博客,格式搞好久,哭了!
这题是这样的,假设数组里面有[1, 2, 3, 4, 5, 6],然后求所有和为6的情况,情况为[6],[5,1],[4,2],[3,2,1],这个数比较少,看着没啥难度,但是数一旦多起来,情况就会比较复杂了。为了解释方便,我就用和为20,数组为[1,2,...,20]来举例子讲述代码吧,话不多说,先看主要代码吧。
def FNN(n): #首次遍历嵌套
for i in range(len(num)-1, -1, -1): #后序遍历
number = [] #这个数组是用来存储一次和为n的,比如[n],[n-1,1]
plus = 0 #这个就是和了,判断和20的关系
for j in range(i, -1, -1): #二层循环,
if plus + num[j] < n: #累计求和,判断和n的关系
number.append(num[j]) #如果小于n,就加入数组num
plus = plus + num[j] #这个时候才把和加到plus里面
elif plus + num[j] == n: #等于n的情况
number.append(num[j])
number = queue(number) #将得到的数组排序成从大到小,作用后面会讲到
if number not in ReNumber: #避免重复
ReNumber.append(number) #将得到的一种情况存储起来
#print("主要:%s" % number) #可以不用,但是可以让人很清楚的看结果
if len(number) > 1: #防止[20]这个情况也会进入循环
for k in range(0, len(number)): #开始调用另一个函数
t = number[k] #把number[k]先转给t,不然下面的remove就把这个数给删了
number.remove(t) #把number[k]先去了
GNN(number, t) #此时传进去的就是没有number[k]的数组,因为我们要求t的和的情况
number.append(t) #把删除的加回去
number = queue(number) #排序是为了下次循环能正确遍历下一个数
break #得到一次结果为20的就终止这次循环,不用再往下遍历了,进行下一次
说一下上面代码的思路吧,直接举例子,所得的n为20,循环就是先取20,对了,这里循环用到的数组需要是排序好的,然后从大到小取。回到循环,取20,这个时候判断结果为20,就将结果保存。只有一个数,就不用调用GNN()(下一个函数,等会讲)了;下次循环为先取19,19<20,将19保存下来,然后一直遍历,直到取1的时候结果为20为止。先把[19,1]保存,然后调用GNN(),传入的参数为数组[19]和1。这是主要思路,语句的注释代码里写了。FNN()函数主要目的就是为了找出类似[20],[19,1],[18,2],[17,3],[16,4]这种大的情况,并且不要管大的19,18这些数的拆分,没有嵌套调用函数,拆分的工作就交给GNN()。
def GNN(number, n_small): #二次遍历嵌套,传进来的是没有n_small的数组和要求的n_small
for i in range(len(num)-1, -1, -1): #后序遍历
plus = 0
number_small = [] #用来求n的和的数组
for j in range(i, -1, -1): #前面几句和FNN一样
# 下面的大判断,第一个判断不用说,第二个是为了防止重复number中的值,比如[6,5,4,3,2],而5能分成3,2,但是传进来的
#number[6,4,3,2]已经有了,此时就不能再分了第三个条件是避免FNN传进来的n_small和循环的num[j]一样而耽误时间
if plus + num[j] < n_small and num[j] not in number and num[j] != n_small:
number_small.append(num[j])
plus = plus + num[j]
elif plus + num[j] == n_small and num[j] not in number and num[j] != n_small: #同上
number_small.append(num[j])
NumberPlus = queue(number + number_small) #这个就是没有n_small的数组加上n_small求和的数组
if NumberPlus not in ReNumber: #避免重复
#print("副要:%s" % NumberPlus)
ReNumber.append(NumberPlus)
###下面的类似FNN###
if len(number_small) > 1:
for k in range(0, len(number_small)): #这个是从0开始
temp = number_small[k]
number_small.remove(temp)
GNN(queue(number + number_small), temp) #里面的排序可以不用,下次嵌套会排序,这里用是为了保险
number_small.append(temp)
number_small = queue(number_small)
break
GNN是进行拆分的,接着上文讲,传进来的参数是[19]和1,1就是要进行拆分的,但是因为1没有能拆的情况,就退出了。举一个多点的例子,比如[9,8,3]这是FNN()最开始找到的,然后FNN()向GNN()传入[9,3]和8,之后GNN()对3进行拆分,同样的循环,之后分成了[7,1]存到number_small,当然分的时候也要判断7和1在刚刚的[9,3]里面有没有,没有才能分。之后将[9,3]+[7,1]存到ReNumber,程序里面的副要就是为了观察这个输出的,然后再判断[7,1]的情况,7能再分成[5,2],然后出循环。然后再找8的拆分情况[6, 2],类推下去,重复的就会省去。循环结束。再回到FNN(),刚刚的8用完了,轮到3了,分成[2,1],输出[9,8,2,1]。这样一直下去,整个结果就出来了。
def QuickSort(str1): #从小到大,并把负数调到列表最后
for i in range(0, len(str1)):
for j in range(0, i):
if str1[j] > str1[i]:
t = str1[j]
str1[j] = str1[i]
str1[i] = t
for i in range(len(str1)-1, -1, -1):
if str1[i] < 0:
t = str1[i]
str1.remove(t)
str1.append(t)
return str1
这个函数说下后面的把负数调到最后是为什么吧,比如输入[1,-1,-2,2,-3,3,4],正常排序后结果是[-3,-2,-1,1,2,3,4],但是我这个程序是后续遍历的,那这样永远也轮不到负数兄弟出场了,所以得将他们弄到最后面,让他们一开始就进入计算,相当于把要求的n变大了。其他的代码比较简单我就不说啦!完整代码如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Inori
def WriteFile(file1): #写文件
f = open("plus.txt", "a") #这里写文件要用a,因为每次循环输出到文件不能清空文件
f.write(str(file1))
f.write('
')
f.close()
def QuickSort(str1): #从小到大,并把负数调到列表最后
for i in range(0, len(str1)):
for j in range(0, i):
if str1[j] > str1[i]:
t = str1[j]
str1[j] = str1[i]
str1[i] = t
for i in range(len(str1)-1, -1, -1):
if str1[i] < 0:
t = str1[i]
str1.remove(t)
str1.append(t)
return str1
def queue(str1): #将列表数据从大到小排序
for i in range(0, len(str1)):
for j in range(0, i):
if str1[j] < str1[i]:
t = str1[j]
str1[j] = str1[i]
str1[i] = t
return str1
def GNN(number, n_small): #二次遍历嵌套,传进来的是没有n_small的数组和要求的n_small
for i in range(len(num)-1, -1, -1): #后序遍历
plus = 0
number_small = [] #用来求n的和的数组
for j in range(i, -1, -1): #前面几句和FNN一样
# 下面的大判断,第一个判断不用说,第二个是为了防止重复number中的值,比如number中有1,而4能分成3,1,此时就不能这样分
#第三个条件是避免FNN传进来的某个不能分的数而耽误时间,[19,1]传进来的n_small=1,就不用再分了
if plus + num[j] < n_small and num[j] not in number and num[j] != n_small:
number_small.append(num[j])
plus = plus + num[j]
elif plus + num[j] == n_small and num[j] not in number and num[j] != n_small: #同上
number_small.append(num[j])
NumberPlus = queue(number + number_small) #这个就是没有n_small的数组加上n_small求和的数组
if NumberPlus not in ReNumber: #避免重复
#print("副要:%s" % NumberPlus)
ReNumber.append(NumberPlus)
###下面的类似FNN###
if len(number_small) > 1:
for k in range(0, len(number_small)):
temp = number_small[k]
number_small.remove(temp)
GNN(queue(number + number_small), temp) #里面的排序可以不用,下次嵌套会排序,这里保险
number_small.append(temp)
number_small = queue(number_small)
break
def FNN(n): #首次遍历嵌套
for i in range(len(num)-1, -1, -1): #后序遍历
number = [] #这个数组是用来存储一次和为n的,比如[n],[n-1,1]
plus = 0 #这个就是和了,判断和20的关系
for j in range(i, -1, -1): #二层循环,
if plus + num[j] < n: #累计求和,判断和n的关系
number.append(num[j]) #如果小于n,就加入数组num
plus = plus + num[j] #这个时候才把和加到plus里面
elif plus + num[j] == n: #等于n的情况
number.append(num[j])
number = queue(number) #将得到的数组排序成从大到小,作用后面会讲到
if number not in ReNumber: #避免重复
ReNumber.append(number) #将得到的一种情况存储起来
#print("主要:%s" % number) #可以不用,但是可以让人很清楚的看结果
if len(number) > 1: #防止[20]这个情况也会进入循环
for k in range(1, len(number)): #开始调用另一个函数,这里不能取第一个数,所以从1开始
t = number[k] #把number[k]先转给t,不然下面的remove就把这个数给删了
number.remove(t) #把number[k]先去了
GNN(number, t) #此时传进去的就是没有number[k]的数组,因为我们要求t的和的情况
number.append(t) #把删除的加回去
number = queue(number) #排序是为了下次循环能正确遍历下一个数
break #得到一次结果为20的就终止这次循环,不用再往下遍历了,进行下一次
if __name__ == '__main__':
num = []
###下面两句是用于自己输入数组的,用空格隔开
print("请输入数组:")
# 下面一步是利用map将输入的[1 2 3 4]分成[1,2,3,4],但是出来的是map类型,
# 所以要转成list型,float是把里面的数按那种类型分,可以是int,这里是由于可以输入浮点型
num = list(map(float, input().split()))
n = float(input('请输入:'))
ReNumber = [] #存储已经求和的数组
f = open("plus.txt", "w") #清空文本,前面函数用的a,这次w,作用就是第二次运行代码清空文件夹
f.close()
QuickSort(num) #排序
FNN(n)
queue(ReNumber)
for i in ReNumber: #最后将结果写文件
WriteFile(i)
print(i)
转载请标明出处,谢谢!