序言
蓝桥杯的题目没有题解,力扣不仅有的题有官方题解而且还有大量用户的题解,所以就转战力扣。虽说力扣有题解,但毕竟不是我自己写的,我会把自己写的代码贴到这里,留作以后复习。为了适应蓝桥杯,Python环境是3.6.5,没有安装任何第三方库。
350. 两个数组的交集 II
给定两个数组,编写一个函数来计算它们的交集。
示例 1: 输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]示例 2: 输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]说明: 输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致。我们可以不考虑输出结果的顺序。
进阶: 如果给定的数组已经排好序呢?你将如何优化你的算法? 如果 nums1 的大小比 nums2 小很多,哪种方法更优? 如果 nums2
的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-of-two-arrays-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
一开始我对题目的理解有偏差,认为交集必须是连续的,看了题解之后发现并不是,只要是两个列表中均出现的即可算是交集。这题我一开始想的是遍历长度较小的列表,找到第一个在较长的列表中出现的数字,在使用另一个指针依次遍历较小列表,直到静止指针和遍历指针之间的几个数不在较长的列表中为止,后来发现我还是太菜了,这种想法简直愚钝。更正想法后,使用字典存储较小列表出现的数字和出现的次数,然后遍历较大列表,较大列表中的元素在字典中并且该元素对应的值大于0的话就将该元素加入到列表中,同时将字典中该元素的值减1。以下是Python实现的代码
class Solution:
def intersect(self, nums1, nums2):
if len(nums2) < len(nums1):
return self.intersect(nums2, nums1)
dic = {}
lis = []
for item in nums1:
if item not in dic.keys():
dic[item] = 1
else:
dic[item] += 1
for item in nums2:
if item in dic.keys() and dic[item] > 0:
lis.append(item)
dic[item] -= 1
return lis
so = Solution()
print(so.intersect([2, 2, 3], [1, 2, 2, 1, 3]))
写的可能不是很好,有愿意指导的大神感激不尽。
后来发现力扣评论区有使用Counter()函数的,简单的查了一下这个函数,官方文档是这样子介绍它的:
一个 Counter 是一个 dict的子类,用于计数可哈希对象。它是一个集合,元素像字典键(key)一样存储,它们的计数存储为值。计数可以是任何整数值,包括0和负数。Counter 类有点像其他语言中的 bags或multisets。
在这道题中,传入一个列表参数,会返回一个 ‘collections.Counter’ 类型的值,它在形式上类似于字典,字典的键是列表中的元素,字典的值是该元素在列表中出现的次数,按照字典的值由大到小排序,如下
from collections import Counter
n = Counter((1, 2, 3, 1, 2, 5, 9, 0, 2, 3))
print(n) # Counter({2: 3, 1: 2, 3: 2, 5: 1, 9: 1, 0: 1})
print(dict(n)) # {1: 2, 2: 3, 3: 2, 5: 1, 9: 1, 0: 1}
转为字典输出后,会按照元素在原列表中的顺序排序,不止是列表,字符串、元组也是一样的。
使用Counter()函数后代码如下,可以看到简化了一些
from collections import Counter
class Solution:
def intersect(self, nums1, nums2):
lis = []
if len(nums2) < len(nums1):
return self.intersect(nums2, nums1)
dic = dict(Counter(nums1))
for item in nums2:
if item in dic.keys() and dic[item] > 0:
lis.append(item)
dic[item] -= 1
return lis
so = Solution()
print(so.intersect([2, 2, 3], [1, 2, 2, 1, 3]))
1. 两数之和
这题比较简单,但我通过这道题认识了index()方法,之前学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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
就不说啥了,直接上代码吧
class Solution:
def twoSum(self, nums, target):
'''for i in range(0, len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target and i != j:
return i, j'''
i = 0
j = 0
for i in range(1, len(nums)):
temp = nums[:i]
if (target - nums[i]) in temp:
j = temp.index(target - nums[i])
return j, i
so = Solution()
nums = [3, 3]
target = 6
m, n = so.twoSum(nums, target)
print(m, n)
被注释掉的是暴力解法,可以通过,顺便一提将第四行的for j in range(i + 1, len(nums)):
变为for j in range(0, len(nums)):
就会超时。
11. 盛最多水的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i
的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组
[1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。示例: 输入:[1,8,6,2,5,4,8,3,7] 输出:49>
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这道题我一开始想到的就是暴力法,管他什么时间复杂度空间复杂度的,老夫从来就是几个for循环一把梭,暴力解决就完事了,简单直观可读性高。然鹅 理智 现实 告诉我不能这么干,不出所料的超时了。
然后就是想着如何优化一下时间复杂度,想到了双指针,也是两个for循环,一开始一个在最左端,一个在最右端,计算一下面积值并保存下来,然后左端指针不动,如果右端指针的下一位比当前值小的话就直接移动而不计算,否则的话既计算又移动,但结果是错的,我目前还在想为什么会错。
看了力扣的题解,也是双指针,不过是一个while循环,复杂度一下子就降低了,整个列表只遍历一次就行了,大体意思是一开始左右指针分别在最左边和最右边,计算面积并记录下来,双指针比较大小,谁小谁移动,左边指针向右移动,右边指针向左移动,总是移动小指针是有道理的,因为每次移动后两指针距离一定会变短,而面积取决于指针间的距离和较小指针的高度,移动大指针的话如果移动后的值比另一个指针小,则面积比之前更小(指针间距离减小,高度也减小),如果移动后的值比另一个指针大,则面积依旧是减小的(指针间距离减小,高度不变)。而如果移动小指针的话就有可能遇到比大指针还大的指针,这样即使指针间距离减小了,但双指针的最小高度变大了,面积有可能会变大。以下是代码。
height = map(int, input().split(','))
height = list(height)
m = 0
left = 0
right = len(height) - 1
while left < right:
if (abs(left - right)) * (height[right] if height[left] > height[right] else height[left]) > m:
m = (abs(left - right)) * (height[right] if height[left] > height[right] else height[left])
if height[left] <= height[right]:
left += 1
elif height[left] > height[right]:
right -= 1
print(m)