刷力扣

序言

蓝桥杯的题目没有题解,力扣不仅有的题有官方题解而且还有大量用户的题解,所以就转战力扣。虽说力扣有题解,但毕竟不是我自己写的,我会把自己写的代码贴到这里,留作以后复习。为了适应蓝桥杯,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)

未完待续

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值