zoukankan      html  css  js  c++  java
  • 编程练习(一)201301 JAVA题目0-1级

    编写一个函数,传入一个int型数组,返回该数组能否分成两组,使得两组中各元素加起来的和相等,并且,所有5的倍数必须在其中一个组中,所有3的倍数在另一个组中(不包括5的倍数),能满足以上条件,返回true;不满足时返回false。

    方法一:暴力求解

    while 1:
        try:
            n = input()
            l = input().split() # 列表
            sum1 = sum2 = 0
            ll = [] # 保存 3,5 之外的数
            for i in l:
                if int(i) % 5 == 0:
                    sum1 += int(i)
                elif int(i) % 3 == 0:
                    sum2 += int(i)
                else:
                    ll.append(int(i))
            d_value = abs(sum1 - sum2) # 2*x + d_value = sum(ll) ===> d_value = sum(ll) - 2 * x
            if not ll and d_value == 0:
                print ('true')
            elif not ll and d_value != 0:
                print ('false')
            else: # 存在差值,并且有剩余数字
                s = set()
                for x in ll:
                    tmp = list(s)
                    for y in tmp:
                        s.add(x + y)
                    s.add(x)
                for may_value in s:
                    if d_value == abs((sum(ll) - may_value) - may_value):
                        print ('true')
                        break
                else:
                    print ('false')
        except:
            break
    

    解析:首先得到 sum1, sum2,剩下的数字组成的列表ll, 以及二者的差值。如果成立,则存在x使得: 2*x + d_value = sum(ll)。即
    d_value = sum(ll) - 2 * x。最朴素的方法,找到列表ll中所有数字和所有可能的值,然后代入比较。
    所以问题转换为如何求一个数组中所有数字求和得到的值。

    list_ = [1,2,3,4,5,6,7,5,3,2,1,5,99]
    s = set()
    for x in list_:
        tmp = list(s)
        for y in tmp:
            s.add(x +y)
        s.add(x)
    print(s)
    

    s 的值 {x1,x1+x2,x2,x1+x3,x1+x2+x3,x2+x3,x3......}
    方法二:递归

    def search(ll, target):
        if target == 0:
            return True
        if not ll:
            return False
        return search(ll[1:],target) or search(ll[1:],target - ll[0])
     
     
    while True:
        try:
            m,ls = int(input()),list(map(int, input().split()))
      
            ls1 = []
            ls2 = []
            ls3 = []
     
     
            for i in ls:
                if i%5 == 0:
                    ls1.append(i)
                elif i%3 ==0:
                    ls2.append(i)
                else:
                    ls3.append(i)
            t = abs(sum(ls1)-sum(ls2))
            d = sum(ls3) - t
            if d%2 != 0:
                print('false')
            else:
                if search(ls3,d/2):
                    print('true')
                else:
                    print('false')
        except:
            break
    

    解题思路:先按提干要求构建ls1和ls2,计算ls1和ls2总和之差的绝对值t,用ls3抹平两者差距;
    问题变成了:ls3的总和减去t之后的值d,d能否被ls3中元素平分。如果d是奇数,那么一定不能平分。
    如果d是偶数,那么变了成能不能从ls3中挑选出若干元素,他们的和为d/2,与打靶问题有类似之处;
    但是本题比打靶问题简单,打靶问题每次射击的结果从0到10有11种情况,本地只有两种情况
    分解子问题:
    使用递归开始查找,对ls3中的每个元素遍历,每个元素都分两种情况:参与构建d/2和不参与构建d/2;
    形成一个二叉树,记录查找结果;
    边界条件:
    1.如果target为0了,那么说明找到了一个构建d/2的方法
    2.如果ls3都查找完了还没有找到,说明没有办法构建d/2

    另一种思考方式:
    5的倍数一组,和为s5,3的倍数一组,和为s3,剩余的元素为一组,s5和s3相差s,
    剩余的一组分成的两组之间也应该相差s才能使得最后s3组和s5组和结果相同.
    假设剩余的一组和为s0,分成两组s1和s2,且s1和s2相差s,那么有s1+s2=s0且s1-s2=s;
    则有s2=(s0-s)/2,s1=(s0+s)/2,因此可以转化为从剩余的一组中看是否能够找到几个数的和为s1或s2*/
    用二叉树遍历所有结果(中间能找到s1或者s2就停止),二叉树的建立就是把所有结果列出来,第一个数有取和不取两种可能,取第一个数,那么第二个数又有取和不取两种可能,不取第一个数的话,第二个数也是有取和不取两种可能.这样一直遍历查找下去,找不到就输出false.

  • 相关阅读:
    Python3.8 爬取豆瓣电影TOP250 练手爬虫
    作为一名phper,php的运行模式,你真的了解吗??
    前端自动生成条码码插件JsBarcode.all.min.js
    js判断是否在微信内打开页面
    学习Swoole之如何避免成为被坑哭的程序员
    上下界网络流
    网络流建模经验
    HttpClient和Gson跨域访问
    CentOS7+mysql5.6配置主从
    Atlas安装配置
  • 原文地址:https://www.cnblogs.com/leimu/p/13432135.html
Copyright © 2011-2022 走看看