求数组内所有和为某个数的情况

Posted hecong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求数组内所有和为某个数的情况相关的知识,希望对你有一定的参考价值。

??最近遇到一个问题,求数组内所有和为一个数的情况,第一眼觉得这题应该挺简单的吧,然后慢慢的做,后来发现这题有点东西,现在就把做出来的写一下。个人想法,而且代码可能不是很简洁,大佬们看到请指点!第一次写这种博客,格式搞好久,哭了!
??这题是这样的,假设数组里面有[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(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的就终止这次循环,不用再往下遍历了,进行下一次

??说一下上面代码的思路吧,直接举例子,所得的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(‘\n‘)
    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)
    for i in ReNumber: #最后将结果写文件
        WriteFile(i)
        print(i)

转载请标明出处,谢谢!

以上是关于求数组内所有和为某个数的情况的主要内容,如果未能解决你的问题,请参考以下文章

用matlab如何求出一个数组中最接近某个数的两个数的下标??

和为S的两个数字

两个数和为某个数几个连续数等于某个数

java求数组中,某个值连续出现次数最多的数的次数

JAVA中求某个数组的众数?自己写了个,但是不对

数组小和