哈嘍大家好,我是鵬哥。
最近一直沒想好要寫些什麼主題,所以只好記錄下最近刷到的一道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吧!