Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 和小于或等于k的最长子数组的长度_Python_Algorithm_Dynamic Programming - Fatal编程技术网

Python 和小于或等于k的最长子数组的长度

Python 和小于或等于k的最长子数组的长度,python,algorithm,dynamic-programming,Python,Algorithm,Dynamic Programming,在一次采访中,我被问到这样一个问题:给定一些正整数数组s,求最长子数组的长度,使其所有值之和小于或等于某个正整数k。每个输入将始终至少有一个解决方案。数组不是圆形的 我开始编写一个动态规划解决方案,通过在从0到k的越来越大的值中找到最大长度来工作 这是我用python编写的代码,其中有一个错误我似乎找不到,我的答案总是相差几位数: def maxLength(s, k): lengths = [0 for x in range(k)] for i in range(1,k+1):

在一次采访中,我被问到这样一个问题:给定一些正整数数组s,求最长子数组的长度,使其所有值之和小于或等于某个正整数k。每个输入将始终至少有一个解决方案。数组不是圆形的

我开始编写一个动态规划解决方案,通过在从0到k的越来越大的值中找到最大长度来工作

这是我用python编写的代码,其中有一个错误我似乎找不到,我的答案总是相差几位数:

def maxLength(s, k):
    lengths = [0 for x in range(k)]
    for i in range(1,k+1):
        for j in range(len(s)):
            if s[j] <= i and lengths[i - s[j]] + 1 > lengths[i]:
                lengths[i] = lengths[i - s[j]] + 1
        if i + 1 == len(s):
            break
    return lengths[-1]
def最大长度(s,k):
长度=[0表示范围(k)内的x]
对于范围(1,k+1)内的i:
对于范围内的j(len(s)):
如果s[j]长度[i]:
长度[i]=长度[i-s[j]]+1
如果i+1==len(s):
打破
返回长度[-1]
输入1:
s=[1,2,3],k=4

输出1:
2

输入2:
s=[3,1,2,1],k=4

输出2:
3

我认为这是可行的。。。(递归地从问题中取出连续的需求,因为这似乎与问题中提供的样本输出不匹配),OP提到问题是:

给定某个正整数数组s,求最长子数组的长度,使所有值之和等于某个正整数k

产出:

3
# BorrajaX's note: 2 + 1 + 3
2
# BorrajaX's note: 3 + 1
3
# BorrajaX's note: 1 + 2 + 1
3
# BorrajaX's note: 1 + 2 + 7
0
# BorrajaX's note: No possible sum
6
# BorrajaX's note: 1 + 1 + 1 + 1 + 1 + 1
编辑01:

如果您想获取给您的总和最长的列表,您可以这样做:

import copy


def longest_sum(input_list, used_list, target_number):
    if target_number == 0:
        return used_list

    if not input_list:
        return []

    # Taken
    used_list_taken = copy.copy(used_list)
    used_list_taken.append(input_list[0])
    used_1 = longest_sum(input_list[1:], used_list_taken, target_number - input_list[0])

    # Not taken
    used_list_not_taken = copy.copy(used_list)
    used_2 = longest_sum(input_list[1:], used_list_not_taken, target_number)
    if len(used_1) > len(used_2):
        return used_1
    else:
        return used_2


if __name__ == "__main__":
    print(longest_sum([2, 1, 8, 3, 4], [], 6))
    print(longest_sum([1, 2, 3], [], 4))
    print(longest_sum([3, 1, 2, 1], [], 4))
    print(longest_sum([1, 2, 7, 8, 11, 12, 14, 15], [], 10))
    print(longest_sum([1, 2, 3], [], 999))
    print(longest_sum([1, 1, 1, 1, 1, 1, 4], [], 6))
def get_longes(a_list, k):
    longest = 0
    length = len(a_list)
    for i in xrange(length):
        s = 0
        for j in xrange(i,length):
            s+=a_list[j]
            if s < k:
                pass
            elif s==k:
                longest = j+1-i
            else:
                break
    return longest
你会看到:

[2, 1, 3]
[1, 3]
[1, 2, 1]
[1, 2, 7]
[]
[1, 1, 1, 1, 1, 1]
ps1:如果没有递归提供的快速回溯功能,我真的不知道如何做到这一点。。。抱歉:-(


PS 2:如果这不是您想要的(我提到我从需求中删除了连续需求),请告诉我,我将删除此答案。

稍微短一点,并假设为非圆形s:在s上滑动大小减小的窗口

def maxlen(s, k):
    for win in range(k, 0, -1):
        for i in range(0, len(s) - win):
            if sum(s[i:i+win]) == k:
                return win
    return None

s = [3,1,2,3]
k = 4
print(maxlen(s, k))
可以在线性(O(n))时间内执行此操作:

这段代码可能看起来像是O(n),如果它是用Go编写的,那么它就是。请参见
current=current[1:][/code>?根据,从列表中获取一个片段需要O(n)

我找不到从开始删除元素的列表操作,直到我突然意识到我不必这样做。
current
始终是
s
的一个连续子数组,那么为什么不只标记它的开始和结束呢

这是我的最终解决方案:

def max_length(s, k):
    # These two mark the start and end of the subarray that `current` used to be.
    subarray_start = 0
    subarray_end = 0

    subarray_sum = 0
    max_len = -1 # returns -1 if there is no subsequence that adds up to k.
    for i in s:
        subarray_sum += i
        subarray_end += 1
        while subarray_sum > k: # Shrink the array from the left, until the sum is <= k.
            subarray_sum -= s[subarray_start]
            subarray_start += 1
        if subarray_sum == k:
            max_len = max(max_len, subarray_end - subarray_start)

    return max_len
def最大长度(s,k):
#这两个标记了“current”以前的子数组的开始和结束。
子阵列_开始=0
子数组_end=0
子数组_和=0
max_len=-1#如果没有累加到k的子序列,则返回-1。
对于s中的i:
子阵_和+=i
子阵列_end+=1
当子数组_sum>k:#从左侧收缩数组,直到和为k:#从左侧收缩数组,直到和为原始答案
最初的问题是找到最长的子数组的长度,该子数组的总和为k

您可以遍历列表索引,将每个索引作为求和窗口的起点。然后将索引从起点索引遍历到终点,以标记窗口的终点。在每个步骤中,您都可以获取和,甚至更好,将其添加到一个和项中。如果和超过目标,您将打破内部循环,继续前进。

它将如下所示:

import copy


def longest_sum(input_list, used_list, target_number):
    if target_number == 0:
        return used_list

    if not input_list:
        return []

    # Taken
    used_list_taken = copy.copy(used_list)
    used_list_taken.append(input_list[0])
    used_1 = longest_sum(input_list[1:], used_list_taken, target_number - input_list[0])

    # Not taken
    used_list_not_taken = copy.copy(used_list)
    used_2 = longest_sum(input_list[1:], used_list_not_taken, target_number)
    if len(used_1) > len(used_2):
        return used_1
    else:
        return used_2


if __name__ == "__main__":
    print(longest_sum([2, 1, 8, 3, 4], [], 6))
    print(longest_sum([1, 2, 3], [], 4))
    print(longest_sum([3, 1, 2, 1], [], 4))
    print(longest_sum([1, 2, 7, 8, 11, 12, 14, 15], [], 10))
    print(longest_sum([1, 2, 3], [], 999))
    print(longest_sum([1, 1, 1, 1, 1, 1, 4], [], 6))
def get_longes(a_list, k):
    longest = 0
    length = len(a_list)
    for i in xrange(length):
        s = 0
        for j in xrange(i,length):
            s+=a_list[j]
            if s < k:
                pass
            elif s==k:
                longest = j+1-i
            else:
                break
    return longest
def-get-longes(列表,k):
最长=0
长度=长度(a_列表)
对于X范围内的i(长度):
s=0
对于X范围内的j(i,长度):
s+=a_列表[j]
如果s
这可以进一步加快速度,因为在外循环中移动一步时,不需要重置窗口大小。事实上,只要跟踪窗口大小,并在外循环继续移动时将其减小1。这样,您甚至可以摆脱内循环,在O(n)中写入内容:

def get_longest(a_list,k):
    length=len(a_list)
    l_length = 0
    longest = 0
    s = 0
    for i in xrange(length):
        while s<k:  # while the sum is smaller, we increase the window size
            if i+l_length==length: # this could also be handled with a try, except IndexError on the s+=a_list[... line
                return longest
            s+=a_list[i+l_length]
            l_length+=1
        if s == k:  # if the sum is right, keep its length if it is bigger than the last match.
            longest = max(l_length, longest)
        l_length-=1  # keep the window end at the same position (as we will move forward one step)
        s-=a_list[i]  # and subtract the element that will leave the window
    return longest
def get_longest(a_列表,k):
长度=长度(a_列表)
l_长度=0
最长=0
s=0
对于X范围内的i(长度):

虽然s这里有一个解决方案适用于任何可迭代的
s
(甚至是迭代器)。它本质上与相同的算法,但如果
k
相对于
s
中的值较大(因此相关子序列的长度较长),则效率会更高:

因为我们在迭代时不保留包含我们正在检查的子序列的列表,所以这种基于迭代器的方法只有在您只需要最长子序列的长度,而不需要其实际内容时才有用

如果您想获得最长子序列的副本,可以在bigblind的答案上使用不同的变体,使用
collections.dequeue
而不是列表(这样从左侧弹出很快),并像我的代码一样跟踪运行的总和(这样您就不需要反复调用
sum
):

如果您的问题标题具有误导性,并且您实际上并不关心子序列是否连续,那么我认为您当前的动态规划方法可以满足您的要求。我只是不完全确定我是否理解循环的工作原理。我认为最自然的做法是在输入项上使用外循环,在p上使用第二个循环包含该值的势和(是
长度
列表中的索引)。我还建议使用
作为除
0
以外的所有长度的初始值,因为如果没有特殊情况,很难使条件正常工作

def max_length(s, k):
    lengths = [None for _ in range(k+1)]
    lengths[0] = 0

    for x in s:
        for i in range(k, x-1, -1): # count down to avoid duplication
            if lengths[i-x] is not None and (lengths[i] is None or
                                             lengths[i-x] >= lengths[i]):
                lengths[i] = lengths[i-x] + 1

    return lengths[k]

这篇文章对你很有帮助

可以使用求和数组+二进制搜索来解决此问题。

你得到的第一个观察结果是如果我们
def get_longes(a_list, k):
    longest = 0
    length = len(a_list)
    for i in xrange(length):
        s = 0
        for j in xrange(i,length):
            s+=a_list[j]
            if s < k:
                pass
            elif s==k:
                longest = j+1-i
            else:
                break
    return longest
def get_longest(a_list,k):
    length=len(a_list)
    l_length = 0
    longest = 0
    s = 0
    for i in xrange(length):
        while s<k:  # while the sum is smaller, we increase the window size
            if i+l_length==length: # this could also be handled with a try, except IndexError on the s+=a_list[... line
                return longest
            s+=a_list[i+l_length]
            l_length+=1
        if s == k:  # if the sum is right, keep its length if it is bigger than the last match.
            longest = max(l_length, longest)
        l_length-=1  # keep the window end at the same position (as we will move forward one step)
        s-=a_list[i]  # and subtract the element that will leave the window
    return longest
def get_longest_smaller_or_equal(a_list,k):
    length=len(a_list)
    l_length = 0
    longest = 0
    s = 0
    for i in xrange(length):
        while s<=k:  # while the sum is smaller, we increase the window size
            longest = max(l_length, longest)
            if i+l_length==length: # this could also be handled with a try, except IndexError on the s+=a_list[... line
                return longest
            s+=a_list[i+l_length]
            l_length+=1
        l_length-=1  # keep the window end at the same position (as we will move forward one step)
        s-=a_list[i]  # and subtract the element that will leave the window
    return longest
import itertools

def max_length(s, k):
    head, tail = itertools.tee(s)
    current_length = current_sum = 0
    max_len = -1 # returns -1 if there is no subsequence that adds up to k.

    for i in head:
        current_length += 1
        current_sum += i

        while current_sum > k:
           current_length -= 1
           current_sum -= next(tail)

        if current_sum == k:
            max_len = max(max_len, current_sum)

    return max_len
import collections

def max_subsequence(s, k):
    current = collections.dequeue()
    current_sum = 0
    max_len = -1
    max_seq = None # returns None if there is no valid subsequence.

    for i in s:
        current.append(i)
        current_sum += i

        while current_sum > k: # Shrink from the left efficiently!
           current_sum -= current.popleft()

        if current_sum == k:
            if len(current) > max_len:
                max_len = len_current
                max_seq = list(current) # save a copy of the subsequence

    return max_seq
def max_length(s, k):
    lengths = [None for _ in range(k+1)]
    lengths[0] = 0

    for x in s:
        for i in range(k, x-1, -1): # count down to avoid duplication
            if lengths[i-x] is not None and (lengths[i] is None or
                                             lengths[i-x] >= lengths[i]):
                lengths[i] = lengths[i-x] + 1

    return lengths[k]
sum[i] = sum[i−1] + array[i]
sum[i]=array[i]
sum[j]−sum[i], j>i