LeetCode 1.Two Sum 两数之和 Python3 五种解法

LeetCode 1.Two Sum 两数之和 五种解法

Bootstrap重采样实战

  • LeetCode 1.Two Sum 两数之和 五种解法
    • 方法一: 哈希表?,排序/二分法
    • 方法二:矩阵加法
    • 方法三:暴力匹配
    • 方法四:两遍哈希表遍历
    • 方法五:一遍哈希表遍历

https://leetcode-cn.com/problems/two-sum/
一共会提到5种解法,除了官方答案,都是自己fighre out的了。

方法一: 哈希表?,排序/二分法

因为是求索引,肯定会涉及到值和索引的映射。因为Python没有HashTable结构。 dict不允许键值对中键值不唯一,只能用tuple替代,但是用tuple又无法像dict一样直接检查Table.contains(value)的操作。只能用买椟还珠的方法做了个 排序,两分。本来自己有写插入排序的,但是不知道怎么用在tuple上只能偷个懒sorted。这样也能拿个普普通通的分数。

class Solution:
    def twoSum(self, nums, target):
        map_nums = [tuple([k,v]) for k,v in enumerate(nums)]
        ordered_nums = sorted(map_nums, key=lambda x:x[1])

        min = 0
        max = len(nums) -1
        while max > min:
            guss = ordered_nums[min][1] + ordered_nums[max][1]
            if guss > target:
                max -= 1
            elif guss<target:
                min += 1
            else:
                return [ordered_nums[min][0], ordered_nums[max][0]]
            
        return [ordered_nums[min][0], ordered_nums[max][0]]

if __name__ =='__main__':
    
    nums = [3,2,2,5]
    target = 8
    solution = Solution()
    solution = solution.twoSum(nums,target)
    print(solution)

Runtime: 40 ms, faster than 82.86% of Python3 online submissions for Two Sum.
Memory Usage: 15.1 MB, less than 6.37% of Python3 online submissions for Two Sum.

方法二:矩阵加法

矩阵自带下标,可以实现运算复杂度降维打击复杂度的降维打击,计算步骤永远为1。LeetCode要硬编码,暂时先用numpy实现了一个,后面又补了一个自己实现的。内存换执行效率,超级暴力的mask匹配。只需要一次运算哦。但是空间复杂度也相当吓人了。
运算复杂度: O ( 0 ) O(0) O(0)
空间复杂度: O ( n × n ) O(n \times n) O(n×n)

class Solution:
    def twoSum(self, nums, target):
        length = len(nums)
        matrix_a = np.array([[i]* length for i in nums])
        matrix_b = matrix_a.T
        mask = np.array([[target]* length for i in nums])
        matrix_sum = matrix_a + matrix_b
        idex = np.argwhere( mask == matrix_sum)
        return idex[0]

        
if __name__ =='__main__':
    
    nums = [3,2,2,5]
    target = 8
    solution = Solution()
    solution = solution.twoSum(nums,target)
    print(solution)

自己也用嵌列表变实现了一个转置(Transpose)和矩阵加法。空间复杂度太大。Leetcode不让过。

class Solution:
    def twoSum(self, nums, target):
        length = len(nums)
        
        def add(matrix1, matrix2):
            result = []
            for row in range(len(matrix1)): 
                row_result = []
                for column in range(len(matrix1[row])):  
                    row_result.append(matrix1[row][column]+matrix2[row][column]) 
                result.append(row_result) 
            return result
            sum = add(matrix_a, maxtri_b)

       
        matrix_a = ([[i]* length for i in nums])
        maxtri_b = [[y[x] for y in matrix_a ] for x in range(len(matrix_a))]
        matrix_sum = add(matrix_a, maxtri_b)

        for x in range(len(matrix_sum)):
            for y in range(len(matrix_sum[x])):
                if (matrix_sum[x][y] == target) & (x != y):
                    return [x,y]
                    
        return false

方法三:暴力匹配

不用对数据本身做转换,多加一个int也就是List多加一个32bit,但是复杂度由于里面要多次的对两者对和进行比较,比较高。
运算复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)

class Solution:
    # two pass without hash table as Brute Force
    def twoSum(self, nums, target):

        # first pass
        for glb_idx in  range(len(nums)):
            # second pass without hash table
            for lcl_idx in range(glb_idx + 1, len(nums)):
                if nums[glb_idx] == target - nums[lcl_idx]:
                    return [glb_idx, lcl_idx]
        return 0

Runtime: 5472 ms, faster than 11.56% of Python3 online submissions for Two Sum.
Memory Usage: 13.7 MB, less than 86.82% of Python3 online submissions for Two Sum.

方法四:两遍哈希表遍历

方法来自官网 https://leetcode.com/articles/two-sum/。
Java占了大便宜,本身有HashTable,可以生成值不唯一的键值对。但是Hash表因为要对每一个元素生成hash值,空间复杂度就高了。
运算复杂度: O ( 1 ) O(1) O(1)
空间复杂度: O ( n ) O(n ) O(n)

public int[] twoSum(int[] nums, int target) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        map.put(nums[i], i); // python这里遇到重复值就无法生成dict类型的Hashtable
    }
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement) && map.get(complement) != i) {
            return new int[] { i, map.get(complement) };
        }
    }
    throw new IllegalArgumentException("No two sum solution");
}

Runtime: 14 ms, faster than 44.33% of Java online submissions for Two Sum.
Memory Usage: 38.1 MB, less than 96.73% of Java online submissions for Two Sum.

方法五:一遍哈希表遍历

方法来自官网 https://leetcode.com/articles/two-sum/。
一遍哈希表发展了两遍哈希表。代码更为简洁。新建了一个Hash表来回收没有匹配上的数值。由于已知必然有解,也就是就算我们不去进行完整的比对,也无论是匹配值中的两个谁先进入新建的Hash表,最终都会找到匹配的两个值和他们对应的索引。

public int[] twoSum(int[] nums, int target) {

    Map<Integer, Integer> map = new HashMap<>();
    
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement)) {
            return new int[] { map.get(complement), i };
        }
        map.put(nums[i], i);
    }
    throw new IllegalArgumentException("No two sum solution");
}

Runtime: 2 ms, faster than 99.02% of Java online submissions for Two Sum.
Memory Usage: 37.4 MB, less than 99.61% of Java online submissions for Two Sum.

运算复杂度: O ( 1 ) O(1) O(1)
空间复杂度: O ( n ) O(n ) O(n)

这个方法的好处就在于即使是python也可以使用虽然没有标准的Hashtable数据结构。由两种涉及键值的重复的情况一共两种,

  1. 两个值相加刚好为答案。
    如果满足这个条件,那么会直接返回结果不会载入字典。
  2. 如果两个值相加不为答案
    那么,新加入的值会覆盖掉原来的那个值 ,但是因为已经过滤了两个值相加为解的情况所以也无所谓了。有了这个思路后貌似过一轮去重啥的测试,python只有dict也能用两遍哈希表遍历做。
 def twoSum(self, nums, target):
        d = {}
        for i, num in enumerate(nums):
            if target - num in d:
                return [d[target-num], i]
            d[num] = i
        return 0

Runtime: 36 ms, faster than 92.77% of Python3 online submissions for Two Sum.
Memory Usage: 14.1 MB, less than 58.21% of Python3 online submissions for Two Sum.

你可能感兴趣的:(python,Raw,Code,numpy,matrix,algorithm,Java,LeetCode)