zltzlt 发表于 2020-3-23 18:37:34

Python:每日一题 358

今天的题目:

给定一个非负整数数组 nums 和一个整数 s。对于数组中的任意一个整数,都可以从 + 或 - 中选择一个符号添加在前面。

返回可以使最终数组和为 s 的所有添加符号的方法数。

示例 1:

输入:nums = ,s = 3
输出:5
解释:

-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3

一共有 5 种方法让最终和为 3。

{:10_298:}欢迎大家一起答题!{:10_298:}

蒋博文 发表于 2020-3-23 18:37:35

本帖最后由 蒋博文 于 2020-3-24 09:58 编辑

def fun358(nums,s):
    sum_nums = sum(nums)
    if sum_nums < s or (s + sum_nums) % 2 != 0:
      return 0
    result = (s + sum_nums) >> 1
    sa = * (result + 1)
    sa = 1
    for i in nums:
      for j in range(result, i - 1, -1):
            sa += sa
    return sa

kinkon 发表于 2020-3-23 18:59:38

能不能多一些例子?

kinkon 发表于 2020-3-23 19:01:55

本帖最后由 kinkon 于 2020-3-25 19:32 编辑

貌似要用到动态规则或者递归
def p358(nums, s):
    a = sum(nums)
    if a < s: #nums的总和小于s无解
      return 0
    if (a + s) % 2 == 1:#nums 和 s 的总和不是偶数无解
      return 0
    """
    下面是公式:
                                 
                     s + sum(nums)
      sum(b)= -------------------
                           2

    b的位置就是求的答案
    下面很烧脑,有点绕,不好解释
    """               
    b = (a+s)//2
    m = +*b
    for i in nums:
      for j in range(b, i-1, -1):
            m += m

    return m

塔利班 发表于 2020-3-23 19:45:32

本帖最后由 塔利班 于 2020-3-24 18:10 编辑

暴力
from itertools import product as p
def f358(nums,s):
    res=0
    if sum(nums)<abs(s):
      return 0
    for e in p(*(["+-"]*len(nums))):
      if eval(''.join(a+str(a) for a in zip(e,nums)))==s:
            res+=1
    return res

def f358(nums,s):
    def dp(a,b):
      if len(a)==1:
            return (a+b,b-a).count(0)
      else:
            return dp(a,a+b)+dp(a,b-a)
    return dp(nums,s)

March2615 发表于 2020-3-23 20:09:40

本帖最后由 March2615 于 2020-3-25 09:34 编辑

# (sum(P) -sum(N)) + (sum(P) + sum(N)) = target + sum(nums)
#-> sum(P) = (target + sun(nums)) // 2
#-> nums中几个数之和为(target + sun(nums)) // 2 -> 背包问题
def daily358(nums: list, target: int) -> int:
    if (target + sum(nums)) % 2 != 0 or sum(nums) < target:
      return 0
    S = (target + sum(nums)) // 2
    dp = * (S + 1)
    dp = 1
    for num in nums:
      for j in range(S, num-1, -1):
            dp += dp
    return dp


if __name__ == '__main__':
    nums =
    s = 4
    print(daily358(nums, s))

一个账号 发表于 2020-3-23 20:18:22

def func(nums, s) -> int:
    def dfs(cur, i, d = {}):
      if i < len(nums) and (i, cur) not in d:
            d[(i, cur)] = dfs(cur + nums, i + 1) + dfs(cur - nums, i + 1)
      return d.get((i, cur), int(cur == s))
    return dfs(0, 0)

TJBEST 发表于 2020-3-23 20:30:49

本帖最后由 TJBEST 于 2020-3-24 14:17 编辑

两个版本,大同小异,一个是用字典存储中间数据,一个纯递归。希望楼主都测一测,我不知道哪一个更快。

不用字典存储中间结果的版本
def fun358(nums,s):
    def inner(end,num):
      if end==1:
            if num != 0:
                if nums==num or nums==-num:
                  return 1
                else:
                  return 0
            else:
                if nums==0:
                  return 2
                else:
                  return 0
      else:
            return inner(end-1,num - nums)+inner(end-1,num + nums)
    return inner(len(nums),s)
用字典存储结果的版本
def fun358(nums,s):
    def inner(end,num):
      if (end,num) in dic:
            return dic[(end,num)]
      if end==1:
            if num != 0:
                if nums==num or nums==-num:
                  dic[(1,num)]=1
                  return 1
                else:
                  dic[(1,num)]=0
                  return 0
            else:
                if nums==0:
                  dic[(1,num)]=2
                  return 2
                else:
                  dic[(1,num)]=0
                  return 0
      else:
            temp = inner(end-1,num - nums)+inner(end-1,num + nums)
            dic[(end,num)]=temp
            return temp
    dic = dict()
    return inner(len(nums),s)

永恒的蓝色梦想 发表于 2020-3-23 20:37:42

悬赏50,nb

风魔孤行者 发表于 2020-3-23 20:55:36

def f323(nums,s):
    sums = sum(nums)
    if (sums-s)%2 == 1:
      return 0
    else:
      add = (sums-s)/2
      nums.sort()
      def f(list1,n):
            count = 0
            if n < list1:
                return 0
            elif n == list1:
                return 1
            else:
                if f(list1,n-list1):
                  return count+f(list1,n-list1)
      x = 0
      while nums != [] and add >= nums:
            x += f(nums,add)
            nums = nums
      return x

ouyunfu 发表于 2020-3-23 21:02:39

本帖最后由 ouyunfu 于 2020-3-23 21:22 编辑

挑战一行代码from itertools import permutations as p
from itertools import chain as c
def f358(nums:list,s:int)->int:
    return *len(nums),len(nums)))].count(s)
如果是python3.8版本,可以使用海象运算符“:=”,减少一次len函数的调用,代码如下:from itertools import permutations as p
from itertools import chain as c
def f358(nums:list,s:int)->int:
    return *(L := len(nums)),L))].count(s)

流浪的杰 发表于 2020-3-23 21:38:59

我刚第二天,可能是梁静茹给我的勇气让我打开了这篇文章

fan1993423 发表于 2020-3-23 21:49:20

本帖最后由 fan1993423 于 2020-3-25 18:14 编辑

def fun358(nums,s):
    if 0 in nums:
      count0=pow(2,nums.count(0))
      nums=list(filter(lambda x:x,nums))
    else:
      count0=1
    if len(nums)==1:
      if nums==s or nums==-s:
            return count0
      else:
            return 0
    nums.reverse()
    result=0
    def recursion(nums,s):
      nonlocal result,count0
      if len(nums)==1:
            if nums==s or nums==-s:
                result+=1
                return result
            else:
                return result
      s+=nums
      if sum(nums)>s:
            recursion(nums,s)+recursion(nums,s-nums*2)
      elif sum(nums)==s:
            result+=1
            return recursion(nums,s-nums*2)
      else:
            return recursion(nums,s-nums*2)
      return result
    return recursion(nums,s)*count0

sjtuszy 发表于 2020-3-23 22:20:20

献丑一个简单的玩赖思路:
import random as r

def fun358(nums, s):
    a = len(nums)
    x =
    m = n = 0
   
    while m < 10000:
      for each in range(a):
            x = r.choice([-1, 1])
      if sum((nums*x) for i in range(a)) == s:
            n += 1
      m += 1
      
    p = (n/m) * (2 ** a)
   
    return round(p)

阴阳神万物主 发表于 2020-3-24 04:14:50

难度评级:中等
要素分析:算法 效率
感受:问题可以转化为对所有数字的符号做规划的二进制问题。
在时间复杂度上面,2^n明显优于暴力破解的 n! ,而循环优于递归。
我现在在考虑要不要把贮存二进制数据的表作为一个新类去定义,直觉告诉我定义新类的话效率会更高,但是懒癌让我想到:如果已经足够了的话,就不用定义了撒。等会儿再更新作为一个新类的代码。
def solve(nums:'list of int>=0',s:int)->int:
    res = 0
    def bi(n):
      yield n%2
      while n := n // 2:
            yield n%2
    r = len(nums)
    for i in range(2**len(nums)):
      l = list(bi(i))
      su = 0
      for j in range(len(l)):su += nums if l else -nums
      if su < s:continue
      while (j := j+1)<r:
            su -= nums
      if su == s:
            res += 1
    return res
if __name__ == '__main__':
    print('示例 输出:',solve(*5,3))

阴阳神万物主 发表于 2020-3-24 04:48:44

本帖最后由 阴阳神万物主 于 2020-3-24 04:51 编辑

这个的时间复杂度(算上定义的二进制数据自增函数)应当是 (2**n)*n
def solve_2(nums:'list of int>=0',s:int)->int:
    res = 0
    r = len(nums)
    class B(list):
      def __init__(self):
            list.__init__(self,(0,))
      def add(self):
            i = -1
            while 1:
                i += 1
                try:
                  if self:self = 0
                  else:self += 1;return
                except IndexError:
                  self.append(1)
                  return
    def getl():
      l = B()
      while len(l)<=r:
            yield l
            l.add()
    for l in getl():
      su = 0
      for i in range(len(l)):su += nums if l else -nums
      if su < s:continue
      while (i := i+1)<r:
            su -= nums
      if su == s:
            print(l)
            res += 1
    return res
if __name__ == '__main__':
    print('示例 输出:',solve_2(*5,3))

AINIDEREN 发表于 2020-3-24 09:28:48

我飘了 ,我都敢看这样的问题了
{:5_109:}

flamezyy 发表于 2020-3-24 09:29:40

本帖最后由 flamezyy 于 2020-3-24 09:38 编辑

def f358(nums, s):
    if sum(nums) < abs(s):
      return 0
    elif len(nums) == 2:
      if nums + nums == abs(s):
            return 1
      elif abs(nums - nums) == abs(s):
            if s == 0:
                return 2
            else:
                return 1
    else:
      return f358(nums[:-1], s-nums[-1]) + f358(nums[:-1], s+nums[-1])
先来个递归的

mdphd 发表于 2020-3-24 09:45:38

x =
s = 3
n = len(x)
ct = 0
def fh(A, B):
    if A == '1':
      return B
    if A == '0':
      return -B   
for i in range(2 ** n):
    a = bin(i).zfill(n)
    b = 0
    for j in range(n):
      b += fh(a, x)
    if b == s:
      ct += 1
print(ct)
暴力破解
尝试优化算法遇阻,只能暴力{:10_266:}

xiaomei47580 发表于 2020-3-24 13:23:16

看到50鱼币我滚了进来。。。看大佬答题
页: [1] 2 3 4 5
查看完整版本: Python:每日一题 358