[1]两数之和

题目

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

解题

方法一:暴力枚举

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i + 1, n):
                if nums[i] + nums[j] == target:
                    return [i, j]
        
        return []
问题一:self怎么用?

self指向对象,谁创建的对象,就指向谁

问题二:nums: List[int] target: int) -> List[int] 这种定义方法

这是python中用于类型检查的静态类型。它允许您定义输入参数和返回的类型,以便预先处理某些不兼容性。它们只是注释,而不是实际的静态类型。

方法二:哈希表(降低时间复杂度)

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hashtable = dict()
        for i, num in enumerate(nums):
            if target - num in hashtable:
                return [hashtable[target - num], i]
            hashtable[num] = i
        return []

问题一:dict()怎么用?

dict() 函数用于创建一个字典。

一般用法:

>>>dict()                        # 创建空字典
{}
>>> dict(a='a', b='b', t='t')     # 传入关键字
{'a': 'a', 'b': 'b', 't': 't'}
>>> dict(zip(['one', 'two', 'three'], [1, 2, 3]))   # 映射函数方式来构造字典
{'three': 3, 'two': 2, 'one': 1} 
>>> dict([('one', 1), ('two', 2), ('three', 3)])    # 可迭代对象方式来构造字典
{'three': 3, 'two': 2, 'one': 1}

前面是键(key),后面是值(value),组成键值对。: ,}

访问:

d = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
print "dict['Name']: ", dict['Name']
>>>d['Name']:  Zara
dict['Age'] = 8 # 更新
dict['School'] = "RUNOOB" # 添加

del dict['Name']  # 删除键是'Name'的条目
dict.clear()      # 清空字典所有条目
del dict          # 删除字典

注意

  • 字典值可以没有限制地取任何python对象
  • 不允许同一个键出现两次🤗😎,会被覆盖成一个
  • 键必须不可变,所以可以用数字,字符串或元组充当,所以用列表就不行

其他用法:

cmp(dict1, dict2) #比较两个字典元素。
len(dict)#计算字典元素个数,即键的总数。
str(dict)#输出字典可打印的字符串表示。
type(variable)#返回输入的变量类型,如果变量是字典就返回字典类型。
    >>>type(dict)
	<class 'dict'>

dict.clear()#删除字典内所有元素
dict.copy()#返回一个字典的浅复制
dict.fromkeys(seq[, val])#创建一个新字典,以序列 seq 中元素做字典的键,val 为字典所有键对应的初始值
dict.get(key, default=None)#返回指定键的值,如果值不在字典中返回default值
dict.items()#以列表返回可遍历的(键, 值) 元组数组
dict.keys()#以列表返回一个字典所有的键
dict.setdefault(key, default=None)#和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default
dict.update(dict2)#把字典dict2的键/值对更新到dict里
dict.values()#以列表返回字典中的所有值
pop(key[,default])#删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。
popitem()#返回并删除字典中的最后一对键和值。

参考

问题二:enumerate()怎么用?

enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

以下是 enumerate() 方法的语法:

enumerate(sequence, [start=0])
  • sequence – 一个序列、迭代器或其他支持迭代对象。
  • start – 下标起始位置。

用法:

>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]#所有东西
>>> list(enumerate(seasons, start=1))       # 小标从 1 开始
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

它其实实现的是一个for循环

i = 0
seq = ['one', 'two', 'three']
for element in seq:
    print(i, seq[i])
    i += 1
seq = ['one', 'two', 'three']
for i, element in enumerate(seq):
    print(i, element)

表达更简洁,速度有没有变快就不知道了,内存肯定是变大了

测试速度:

step = 10000
T1 = time.perf_counter()
for k in range(step):
    i = 0
    seq = ['one', 'two', 'three']
    for element in seq:
        pass
    # print(i, seq[i])
    i += 1
T2 = time.perf_counter()

T11 = time.perf_counter()
for j in range(step):
    seq = ['one', 'two', 'three']
    for i, element in enumerate(seq):
        pass
    # print(i, element)
T21 = time.perf_counter()
print('1程序运行时间:%s毫秒' % ((T2 - T1) * 1000))
print('2程序运行时间:%s毫秒\n' % ((T21 - T11) * 1000))
1程序运行时间:2.10769999999999毫秒
2程序运行时间:2.3905000000000176毫秒

一万次0.1ms等于没差距,但是当加上print函数就不一样了

1程序运行时间:211.4754毫秒
2程序运行时间:429.7692毫秒

相差一倍,帅哥疑惑

python 计算相邻两个数的差值_Python

开始我以为跟print(i,seq[i])print(i,element)中i无关

把i去掉只print(element)print(seq[i])

1程序运行时间:135.3671毫秒
2程序运行时间:108.89389999999999毫秒

这里就讲到为什么enumerate方法占用内存大了,enumerate方法需要给每个i分配地址,每次内部i+1结束分配新的地址,而for方法只需要分配一个地址给i,然后+1地址不变,所以enumerate方法的print多了个找地址的过程。

参考