Проблема в том, что мне нужно сгенерировать всего N чисел, чтобы я мог получить сумму, например, 0. если N = 4, он должен генерировать [1, 0, −3, 2] или [−2, 1, −4, 5].

Вот мой код, он генерирует случайное int, которое суммируется со значением N, и это случайное общее количество значений в списке.

from random import randint

def solution(N):
    values = []
    while 1 <= N <= 100:
         value = randint(1, N)
         values.append(value)
         N = N - value
    return values

print(solution(3))
-1
EverythingRichardify 24 Июн 2019 в 06:50

3 ответа

Лучший ответ

Это не гарантирует, что окончательное число уникально, но маловероятно, что оно уже будет в списке.

def gen_unique_zero_sum_list(num_members):
    ret = []
    for i in range(int(num_members) - 1):
        candidate = random.randint(-100, 100)
        while candidate in ret:
            candidate = random.randint(-100, 100)
        ret.append(candidate)
    ret.append(-sum(ret))
    return ret

То, что вышеприведенное решение не гарантировало уникальность, меня беспокоило. Вот расширенная версия, которая должна обеспечить уникальность:

def gen_unique_zero_sum_list(num_members, min=-100, max=100):
    if int(num_members) < 1:
        raise ValueError
    ret = []
    # populate as many as we can randomly
    for i in range(0, int(num_members) - 2, 1):
        candidate = random.randint(min, max)
        while candidate in ret:
            candidate = random.randint(min, max)
        ret.append(candidate)
    if int(num_members) > 1:
        while len(ret) < int(num_members):
            # at this point we could get a forced duplicate
            candidate = random.randint(min, max)
            while candidate in ret:
                candidate = random.randint(min, max)
            final = -(sum(ret) + candidate)
            if final in ret or final == candidate:
                # we would have a duplicate, force two new numbers
                continue
            ret.append(candidate)
            ret.append(final)
    else:
        # this will always be zero, by definition
        ret.append(-sum(ret))
    return ret
1
JaminCollins 25 Июн 2019 в 14:18

Одним из вариантов решения этой проблемы является рекурсия. Мы можем сгенерировать наше первое значение нашего списка из диапазона от низкого до высокого, добавить его в список, вернуться через функцию, но теперь с ограниченными возможностями (из-за уникальности), пока мы не доберемся до точки, где есть только одно пятно осталось. На этом этапе либо нам удалось найти список, либо мы потерпели неудачу, и предыдущие уровни рекурсии будут искать другие значения с более ранними индексами, которые могут работать. Другая возможность состоит в том, что нет возможных списков (например, от низкого к высокому положительны, опции заканчиваются до последнего спота), и в этом случае наша функция вернет None.

import random


def foo(n, low, high):
    """Helper function for recursive function"""

    def rbar(arr):
        """Recursive function to create a 'random' list of n integers
        between low and high (exclusive) such that the sum of the list is 0
        and the entries of the list are unique."""

        # if one spot left check if -sum(arr) in arr
        if len(arr) == n-1:
            if -sum(arr) not in arr and -sum(arr) in range(low, high):
                    return arr + [-sum(arr)]

        # if more than one spot then generate the next possible values
        # and try to get to a full list of size n with those
        else:
            # loop through shuffled options (randomness here)
            options = [x for x in range(low, high) if x not in arr]

            for opt in random.sample(options, len(options)):
                # if recursively going through function produces a list then return it
                if rbar(arr + [opt]) is not None:
                    return rbar(arr + [opt])

            # if nothing worked then return None
            return


    if n==0:
        return []
    elif n==1 and 0 in range(low, high):
        return [0]
    elif n==1 and 0 not in range(low, high):
        return None
    else:
        return rbar([])


k = foo(4, -10, 10)

if k is not None:
    print("List: {}, Sum:{}".format(k, sum(k)))
else:
    print(None)
1
benrussell80 24 Июн 2019 в 05:48

Вы можете использовать random.sample, а затем просто получить последнее значение как отрицательное значение суммы первых трех значений:

import random
N=4
l = random.sample(range(-10, 10), k=3)
print(l + [-sum(l)])

Например, он выведет:

[-5, 1, -8, 12]

Который:

print(sum([-5, 1, -8, 12]))

Дает :

0
2
U10-Forward 24 Июн 2019 в 04:15