力扣练习——两数之和(python语言)

恍然间才发现把笔记记录在网上比记在本子上更方便,所以记录一次小小的尝试。

问题描述

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

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum

思路和提示

个人思路

从给定列表中依次不放回的取出一个数字,取一个新列表(mirror)存放这个数字,用target减去该数字,看差值是否在所给列表中。若在,将差值也存放在mirror中,然后找出这两个值在给定列表中的位置并输出;若不在,将mirror中的数字弹出(我用的remove),继续下一个数字。相当于遍历的方法。

官方提示

1.A really brute force way would be to search for all possible pairs of numbers but that would be too slow. Again, it’s best to try out brute force solutions for just for completeness. It is from these brute force solutions that you can come up with optimizations.

2.So, if we fix one of the numbers, say x, we have to scan the entire array to find the next number y, which is value - x, where value is the input parameter. Can we change our array somehow so that this search becomes faster?

3.The second train of thought is, without changing the array, can we use additional space somehow? Like maybe a hash map to speed up the search?

总结:前两条是解决办法,大概和我个人的思路相一致。第三条中的 hash map目前还不知道是什么意思…

代码及描述

代码

class Solution(object):
    def twoSum(self, nums, target):
        twopos=[]
        mirror=nums[:]
        for i in nums:
            mirror.remove(i)
            twopos.append(i)
            x=target-i
            if x in mirror :
                twopos.append(x)
                if len(set(nums)) != len(nums):
                    one=nums.index(twopos[0])
                    nums[nums.index(twopos[0])]=''
                    two=nums.index(twopos[1])
                    return [one,two]
                else:
                    return[nums.index(twopos[0]), nums.index(twopos[1]) ]
            else:
                twopos.pop(0)

编写过程(这里是学习过程)

刚看完题感觉比较简单,很快就写好了代码,之道反复修改了几次之后才发现,事情并没有那么简单…
列两个比较典型的问题:

第一次出现的问题:

mirror=nums
'''这种方法中mirror和nums用的相同的存储空间'''

相当于mirror和nums共用了一个列表,所以对mirror的操作对nums也有相同的影响,最后return的时候从nums里找不到数值了…

第二次出现的问题:
少了一次判断,当nums=[3,3],target=6时,应该输出[0,1],所以加上一次判断

if len(set(nums)) != len(nums):
                    one=nums.index(twopos[0])
                    nums[nums.index(twopos[0])]=''
                    two=nums.index(twopos[1])
                    return [one,two]
'''这种方法直接改变了给定列表,但是最后能解决问题了就没有改(´▽`) '''

修改好之后,代码终于能成功运行了

结果:

执行用时 :560 ms, 在所有 python 提交中击败了 49.83% 的用户
内存消耗 :13.1 MB, 在所有 python 提交中击败了 15.65% 的用户

自己用的也就是暴力破解法,时间复杂度应该是O(n2),但是看有人用暴力破解法耗时 1636ms,所以不太确定,此处存疑。
关于算法复杂度:算法的时间复杂度和空间复杂度-总结

1636ms的代码:

def twoSum(nums, target):
    lens = len(nums)
    j=-1
    for i in range(lens):
        if (target - nums[i]) in nums:
            if (nums.count(target - nums[i]) == 1)&(target - nums[i] == nums[i]):
            #如果num2=num1,且nums中只出现了一次,说明找到是num1本身。
                continue
            else:
                j = nums.index(target - nums[i],i+1) 
                #index(x,i+1)是从num1后的序列后找num2                
                break
    if j>0:
        return [i,j]
    else:
        return []

#作者:lao-la-rou-yue-jiao-yue-xiang
#链接:https://leetcode-cn.com/problems/two-sum/solution/xiao-bai-pythonji-chong-#jie-fa-by-lao-la-rou-yue-j/
#来源:力扣(LeetCode)
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

总结

可以看出用的都是简单的语句(再难一些自己都看不懂了),变量的命名和语句很糙,写的也很慢,经验太少了。

代码优化

1.命名变量时缺少经验,比如两数之和的两数,可以用num1, num2表示。
2.如果存在相同的两数,最后判定时,直接修改了给定列表中的值,这种做法很不好…

参考代码

找了一个简洁,自己又看得懂的代码:
用到了提示3中的 hash map。

class Solution(object):
    def twoSum(self, nums, target):
        hashmap = {}
        for index, num in enumerate(nums):
            another_num = target - num
            if another_num in hashmap:
                return [hashmap[another_num], index]
            hashmap[num] = index
        return None

#作者:lao-la-rou-yue-jiao-yue-xiang
#链接:https://leetcode-cn.com/problems/two-sum/solution/xiao-bai-pythonji-chong-#jie-fa-by-lao-la-rou-yue-j/
#来源:力扣(LeetCode)
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

结果:

执行用时 :40ms, 在所有 python 提交中击败了 87.30% 的用户
内存消耗 :13.1 MB, 在所有 python 提交中击败了 15.26% 的用户

时间复杂度是O(n)。

学到的语句

1.enumerate 函数

python 自带的 enumerate 语句:

enumerate英文翻译为枚举的意思。 可以将一个可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

如:

 >>> product = [ "Mac pro","iPhone","iWatch"]
 >>> for index,item in enumerate(product):
          print(index,item)

 '''得到结果如下:'''
 0    Mac pro
 1    iPhone
 2    iWatch

具体请参考Python中的enumerate函数介绍

2.permutations 函数

该函数从python自带的库 itertools 中引入:

>>> import itertools
>>> s = [1, 2, 3]
>>> print(itertools.permutations(s,2))
<itertools.permutations object at 0x000002C49B0283A8>
>>> n=itertools.permutations(s,2)
>>> for i in n:
	print(i)

'''得到结果如下:'''	
(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
(3, 2)

3.combinations 函数

该函数同样从python自带的库 itertools 中引入:

>>> import itertools
>>> s = [1, 2, 3]
>>> t=list(itertools.combinations(s, 2))
>>> print(t)
[(1, 2), (1, 3), (2, 3)]

>>> t=list(itertools.combinations(s, 3))
>>> print(t)
[(1, 2, 3)]

即:
permutations和combinations都是得到一个迭代器。
combinations方法重点在组合,permutations方法重在排列。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值