如何减少Python脚本的内存使用?

huangapple go评论65阅读模式
英文:

how can I reduce the memory usage of a python script?

问题

我正在尝试解决一个Python问题,虽然我的代码有效,但超出了内存使用限制。
我尝试减少变量数量,但这还不够。

我想知道如何处理这种类型的问题。

这是我的代码:

class Solution(object):
    def threeSum(self, nums):
        
        duos = {}
        triple = {}
        for num1 in nums:
            del nums[nums.index(num1)]
            for num2 in nums :
                duos[tuple([num1,num2])] = num1 + num2
            nums.insert(0, num1)
       
        for duo in duos:
            del nums [nums.index(duo[0])]
            del nums [nums.index(duo[-1])]
            for num in nums:
                if duo[0] + duo[-1] + num == 0:
                    x = [duo[0],duo[-1],num]
                    x.sort()
                    triple[tuple(x)] = 1

            nums.insert(0,duo[0])
            nums.insert(0,duo[-1])
        return triple

这是我尝试解决的问题链接:
https://leetcode.com/problems/3sum/

英文:

I am trying to solve a Python problem and while my code works it exceeds the memory usage limit.
I tried to reduce the number of variables but It wasn't enough.

I would like to know how to approach a problem of this kind

here's my code

class Solution(object):
    def threeSum(self, nums):
        
        duos = {}
        triple = {}
        for num1 in nums:
            del nums[nums.index(num1)]
            for num2 in nums :
                duos[tuple([num1,num2])] = num1 + num2
            nums.insert(0, num1)
       
        for duo in duos:
            del nums [nums.index(duo[0])]
            del nums [nums.index(duo[-1])]
            for num in nums:
                if duo[0] + duo[-1] + num == 0:
                    x = [duo[0],duo[-1],num]
                    x.sort()
                    triple[tuple(x)] = 1

            nums.insert(0,duo[0])
            nums.insert(0,duo[-1])
        return triple    

and here is a link to the problem I tried solving:
https://leetcode.com/problems/3sum/

答案1

得分: 2

一个简单(天真)的方法是遍历每对不同的项目,并检查它们的和的倒数是否在列表的其余部分中。

你不需要对输入列表做任何更改,可以使用集合来确保你只保留唯一的三元组(你可以将其存储为排序的元组,以确保值的顺序不被视为不同的三元组):

def zeroSumTriplets(nums):
    result = set()
    for i,a in enumerate(nums[:-2],1):
        for j,b in enumerate(nums[i:-1],i+1):
            if -a-b not in nums[j:]: continue
            triplet = tuple(sorted([a,b,-a-b]))
            result.add(triplet)
    return list(result)

nums = [-1,0,1,2,-1,-4]
print(zeroSumTriplets(nums)) # [(-1, -1, 2), (-1, 0, 1)]

工作原理:

  • for i,a in enumerate(nums[:-2],1) 遍历数字收集一个索引(i)和一个数字(a)作为三元组的第一部分。它略过了列表的最后两项(nums[:-2]),因为需要有足够的空间来添加两个数字以形成一个三元组。索引(i)从1开始,表示第二个数字的起始点。因此,随着第一个项目的移动,后续的项目始终从下一个可用位置开始(从不后退)。

  • for j,b in enumerate(nums[i:-1],i+1) 从当前第一个项目后立即开始,并再次遍历列表以形成三元组的第二部分。它略过了最后一个项目(nums[i:-1]),因为我们需要为形成三元组提供一个额外的位置。

对于每对(a,b),我们希望在列表的其余部分(从j开始)找到第三个项目,使得它们的总和等于零。此时我们已经知道这个项目应该有什么值。它必须是0 - a - b,因为如果我们可以用那个确切的第三个数字完成三元组(a,b,...),那么sum(a, b, 0-a-b)将为零。因此,我们实际上不需要进行任何额外的加法,只需检查 -a-b 是否在列表中即可告诉我们是否可以将a,b配对成总和为零的三元组。这就是为什么检查 if -a-b not in nums[j:] 就足以决定三元组(a,b,-a-b)是否存在。

由于问题只需要唯一的三元组,我们需要确保类似的三元组(例如[2,-1,-1]和[-1,2,-1])实际上是相同的3个数字,只输出一次。通过对值进行排序,[2,-1,-1] 和 [-1,2,-1] 都将变为 [-1,-1,2]。然后,我们可以将这个排序后的三元组存储在一个集合中(只保留每个不同值的一个实例)。然而,这种方法的唯一问题是集合不能存储列表。但它可以存储元组,所以在将排序后的值添加到集合之前,我们将其转换为元组。

最终结果就是集合的内容,以列表的形式输出。

请注意,有一些方法可以使这个过程更高效,比如使用集合来检查倒数的存在以及使用二分查找跳过部分总和,但这应该给你一个合理的起点

英文:

One simple (naive) way would be to go through every distinct pair of items and check if the inverse of their sum is in the rest of the list.

You don't need to make any change to the input list and you can use a set to ensure that you only keep unique triplets (which you can store as sorted tuples to ensure that order of values isn't treated as different triplets):

def zeroSumTriplets(nums):
    result = set()
    for i,a in enumerate(nums[:-2],1):
        for j,b in enumerate(nums[i:-1],i+1):
            if -a-b not in nums[j:]: continue
            triplet = tuple(sorted([a,b,-a-b]))
            result.add(triplet)
    return list(result)

nums = [-1,0,1,2,-1,-4]
print(zeroSumTriplets(nums)) # [(-1, -1, 2), (-1, 0, 1)]

How it works:

for i,a in enumerate(nums[:-2],1) goes through the numbers collecting an index (i) and a number (a) for the first part of the triplet. It leaves out the last two items of the list (nums[:-2]) because there needs to be room for two more numbers to form a triplet. The index (i) starts at 1 and represents the starting point for the second numbers. So, as we move the first item forward, the subsequent items will always start at the next available position (never backwards).

for j,b in enumerate(nums[i:-1],i+1) goes through the numbers starting immediately after the current first item and runs down the list again to form the second part of the triplet. It leave out the last item (nums[i:-1]) because we need room for one more to form a triplet.

For each of the (a,b) pairs, we want to find a third item in the rest of the list (starting from j) that will make the sum equal to zero. At this point we know exactly what value this item should have. It must be 0 - a - b because sum(a, b, 0-a-b) will be zero if we can complete the triplet (a,b,...) with that exact third number. So we dont actually need to make any more addition, just checking if -a-b is present in the list will tell us if the a,b pair can be used in a triplet that sums up to zero. This is why checking if -a-b not in nums[j:] is enough to decide if the triplet (a, b, -a-b) exists.

Since the problem only wants distinct triplets, wee need to make sure that similar triplets (e.g. [2,-1,-1] and [-1,2,-1]) which are actually the same 3 numbers are only output once. By sorting the values, both [2,-1,-1] and [-1,2,-1] will become [-1,-1,2]. We can then store this sorted triplet in a set (which only keeps one of each distinct values). The only issue with this is that a set cannot store lists. It can however store tuples so we convert the sorted values to a tuple before adding it to the set.

In the end the result is the content of the set, which is output as a list.

Note that there are ways to make this more efficient, using a set to check the presence of the inverse and binary search to skip over partial sums but this should give you a reasonable starting point

答案2

得分: -2

yield 替换 return,看看内存是否不会溢出,很可能会成功。

英文:

replace return with yield and see if the memory doesn't overflow, it will probably work.

huangapple
  • 本文由 发表于 2023年8月5日 05:32:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76839200.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定