哈喽大家好,我是鹏哥。
最近一直没想好要写些什么主题,所以只好记录下最近刷到的一道Leetcode题吧 —— 456.132模式。
~~~上课铃~~~
1
写在前面
年后以来 ,我就经常想不好要写些什么东西,一方面自己python能力暂时没有提升,另一方面懒得写文章了(尽管已经是一周一篇,但是久了就怠了,没有初时的激情。)
最近在看徐子沛的《大数据》,书中有提到一位数据统计师(名字忘 了)百年前提出的数据统计方式在经过历史滚轮周而复始才最终得到认可。如果当时所做的事情或坚持的事情,在十年或百年后能值得他人的认可或者自己的敬佩,那也算有做下去的意义吧。
2
LeetCode 456题:132模式
【题目内容】:给定一个整数序列:a1, a2, ..., an,一个132模式的子序列 ai, aj, ak 被定义为:当 i < j < k 时,ai < ak < aj。设计一个算法,当给定有 n 个数字的序列时,验证这个序列中是否含有132模式的子序列。
链接如下:https://leetcode-cn.com/problems/132-pattern/
示例1:
输入: [1, 2, 3, 4]
输出: False
解释: 序列中不存在132模式的子序列。
示例 2:
输入: [3, 1, 4, 2]
输出: True
解释: 序列中有 1 个132模式的子序列:[1, 4, 2].
示例 3:
输入: [-1, 3, 2, 0]
输出: True
解释: 序列中有 3 个132模式的的子序列: [-1, 3, 2], [-1, 3, 0] 和 [-1, 2, 0].
3
解法示例
解法 1:暴力解
感觉平时写各种python小程序都能写得很快,但是一轮到这种考题就瞬间愣逼,只剩下暴力解了。有点像大学时的期末考试感觉。
class Solution(object):
def find132pattern(self, nums):
if len(nums) < 3:
return False
for i in range(len(nums)):
first = nums[i]
for j in range(i + 1, len(nums)):
if nums[j] > first:
mid = nums[j]
for k in range(j+1,len(nums)):
if first < nums[k] < mid:
return True
return False
暴力解根据题意还是能很快地写出来,也能成功解决题目的几个例子,但是LeetCode测试样例中肯定有些变态的异常场景,果然运行超时。
解法 2:调用 itertools库
不得不说,python各类封装库对用户的友好。对于这个问题,直接调用 itertools库,只需要5行代码就能解决。
import itertools
class Solution(object):
def find132pattern(self, nums):
if len(nums) < 3:
return False
res = itertools.combinations(nums, 3)
for i in res:
if i[0] < i[2] < i[1]:
return True
return False
这里我简单解释一下itertools库的两个牛逼函数:combinations和permutations。话说我第一次看到有人用这两个函数进行求题时,我就觉得好牛逼,惊为天人。Python还有这种库!把很复杂的逻辑思考转为现成的几行代码。我觉得要是面试时,有考官出组合求解类型的题时,用这个方法肯定也会让他大吃一惊,然后继续问你有没有其他方法。
combinations:用法是itertools.combinations(mylist,num),对mylist列表取出 任意num个元素进行组合;
permutations:用法是itertools.combinations(mylist),对mylist列表所有元素进行排列
因此上述代码就是将nums列表中所有三元素组合都遍历求解。当然结果也是运行超时。
解法 3:二维单调栈
核心思想是用栈stack[[min,max]]将最小值和最大值放在栈里,遇到比max更大的值,就将max弹出然后将最大值进行入栈;如果遇到比min值还 小的值,就添加[min,min],待后面将min进行替换。
class Solution:
def find132pattern(self, nums: List[int]) -> bool:
stack = []
for num in nums:
if len(stack) == 0 or num < stack[-1][0]:
stack.append([num, num])
else:
top_min = stack[-1][0]
while len(stack) != 0 and num > stack[-1][1]:
stack.pop()
if len(stack) != 0 and num > stack[-1][0] and num < stack[-1][1]:
return True
stack.append([top_min, num])
return False
解法 4:一维单调栈
这个解法是在讨论区里看到的。大神所用的解法,不像二维栈一样,用stack[[min,max]]来存储过程数据,而是用栈保存最大值,将弹出的次大值与输入值比较。只要输入值比次大值小,就说明成功了!
不得不说,大神就是大神,想法新颖,代码精简,减少了计算空间!
class Solution:
def find132pattern(self, nums: List[int]) -> bool:
stack=[]
_Min=float("-inf")
for i in range(len(nums)-1,-1,-1):
if nums[i]<_Min:
return True
while stack and nums[i]>stack[-1]:
_Min=stack.pop()
stack.append(nums[i])
return False
132模式的解法大致就介绍到这里了,其中我最喜欢的是解法2和4,尽管2并不能满足运行时间要求,但是很pythonic。
4
那些惊艳的python代码
下面我把我自己遇到的一些让人惊艳代码记录下,给有需要的同学参考。闻道有先后,请大神们勿喷。
1、带索引、值的遍历(这个应该很常见)
for i,k in enumerate(mylist)
2、求列表排序后,之前的索引值列表
[i for i,k in sorted(enumerate(mylist),reverse=True,key=lambda x:x[1])]
3、求列表某值的索引位置
[i for i,k in enumerate(mylist) if k == num]
4、三元表达式
return True if x>y else False
5、将字符串大小写进行转换
mystr.swapcase()
6、将列表中的字符串按数字进行排序,如 ['b3','a10','c1']
return sorted(mylist,key=lambda x:int(re.search('\d+').group(0)))
7、对两个列表进行元素交接,使两列表的和差值最小
list3 = list2 + list1
list1 = min(itertools.combinations(list3,len(list1)),key=lambda x:abs(sum(x)-sum(list3)/2))
8、求列表各元素的频度
return {i:mylist.count(k) for i,k in enumerate(set(mylist))}
5
总结
路漫漫其修远兮,吾将上下而求所。
~~~下课铃~~~
【往期热门文章】:
【Python成长之路】10行代码教你免费观看无广告版的《庆余年》腾讯视频
【Python成长之路】如何用python开发自己的iphone应用程序,并添加至siri指令
【Python成长之路】从 零做网站开发 -- 基于Flask和JQuery,实现表格管理平台
点击下方诗句,可以留言互动喔
【关注“鹏哥贼优秀”公众号,回复“python学习材料”,将会有python基础学习、机器学习、数据挖掘、高级编程教程等100G视频资料,及100+份python相关电子书免费赠送!】
扫描二维码
与鹏哥一起
学python吧!