简体   繁体   English

Leetcode 题 '3Sum' 算法超过时限,寻求改进

[英]Leetcode question '3Sum' algorithm exceeds time limit, looking for improvement

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0?给定一个包含 n 个整数的数组 nums,在 nums 中是否存在元素 a、b、c 使得 a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.在数组中找到所有唯一的三元组,其总和为零。

class Solution:
    def threeSum(self, nums):

        data = []
        i = j = k =0
        length = len(nums)
        for i in range(length):
            for j in range(length):
                if j == i:
                    continue
                for k in range(length):
                    if k == j or k == i:
                        continue
                    sorted_num = sorted([nums[i],nums[j],nums[k]])
                    if nums[i]+nums[j]+nums[k] == 0 and sorted_num not in data:
                        data.append(sorted_num)

        return data

My soulution is working well but it appears that it may be too slow.我的解决方案运行良好,但似乎它可能太慢了。 Is there a way to improve my codes without changing it significantly?有没有办法在不显着改变代码的情况下改进我的代码?

This is a O(n^2) solution with some optimization tricks:这是一个具有一些优化技巧的 O(n^2) 解决方案:

import itertools

class Solution:
    def findsum(self, lookup: dict, target: int):
        for u in lookup:
            v = target - u
            # reduce duplication, we may enforce v <= u
            try:
                m = lookup[v]
                if u != v or m > 1:
                    yield u, v
            except KeyError:
                pass

    def threeSum(self, nums: List[int]) -> List[List[int]]:
        lookup = {}
        triplets = set()
        for x in nums:
            for y, z in self.findsum(lookup, -x):
                triplets.add(tuple(sorted([x, y, z])))
            lookup[x] = lookup.get(x, 0) + 1
        return [list(triplet) for triplet in triplets]

First, you need a hash lookup to reduce your O(n^3) algorithm to O(n^2).首先,您需要一个 hash 查找来将您的 O(n^3) 算法减少到 O(n^2)。 This is the whole idea, and the rest are micro-optimizations:这就是整个想法,rest 是微优化:

  • the lookup table is build along with the scan on the array, so it is one-pass查找表是与对数组的扫描一起构建的,因此它是一次性的
  • the lookup table index on the unique items that seen before, so it handles duplicates efficiently, and by using that, we keep the iteration count of the second-level loop to the minimal以前见过的唯一项目的查找表索引,因此它可以有效地处理重复项,并且通过使用它,我们将二级循环的迭代次数保持在最低限度

I'd suggest:我建议:

for j in range(i+1, length):

This will save you len(nums)^2/2 steps and first if statement becomes redundant.这将为您节省 len(nums)^2/2 步骤和第一个 if 语句变得多余。

sorted_num = sorted([nums[i],nums[j],nums[k]])
    if nums[i]+nums[j]+nums[k] == 0 and sorted_num not in data:
        sorted_num = sorted([nums[i],nums[j],nums[k]])
        data.append(sorted_num)

To avoid unneeded calls to sorted in the innermost loop.避免在最内层循环中对sorted进行不必要的调用。

This is an optimized version, will pass through:这是一个优化版本,将通过:

from typing import List

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        unique_triplets = []
        nums.sort()
        for i in range(len(nums) - 2):
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            lo = i + 1
            hi = len(nums) - 1
            while lo < hi:
                target_sum = nums[i] + nums[lo] + nums[hi]
                if target_sum < 0:
                    lo += 1
                if target_sum > 0:
                    hi -= 1
                if target_sum == 0:
                    unique_triplets.append((nums[i], nums[lo], nums[hi]))
                    while lo < hi and nums[lo] == nums[lo + 1]:
                        lo += 1
                    while lo < hi and nums[hi] == nums[hi - 1]:
                        hi -= 1
                    lo += 1
                    hi -= 1
        return unique_triplets

The TLE is most likely for those instances that fall into these two whiles: TLE 最有可能适用于属于这两种情况的那些实例:

  • while lo < hi and nums[lo] == nums[lo + 1]:

  • while lo < hi and nums[lo] == nums[lo + 1]:


References参考

  • For additional details, please see the Discussion Board where you can find plenty of well-explained accepted solutions with a variety of languages including low-complexity algorithms and asymptotic runtime / memory analysis 1 , 2 .有关更多详细信息,请参阅讨论板,您可以在其中找到大量解释清楚且公认的解决方案,这些解决方案具有多种语言,包括低复杂度算法和渐近运行时/ memory分析12

Your solution is the brute force one, and the slowest one.您的解决方案是蛮力解决方案,也是最慢的解决方案。 Better solutions can be:更好的解决方案可以是:

Assume you start from an element from array.假设您从数组中的一个元素开始。 Consider using a Set for finding next two numbers from remaining array.考虑使用 Set 从剩余数组中查找接下来的两个数字。

There is a 3rd better solution as well.还有第三个更好的解决方案。 See https://www.gyanblog.com/gyan/coding-interview/leetcode-three-sum/https://www.gyanblog.com/gyan/coding-interview/leetcode-three-sum/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM