本博客主要內容爲圖書《劍指offer》第二版47 題的解題思路及代碼。方法可能還有不足之處,歡迎大家討論評論。
1. 題目描述
給定一個數組和一個滑動窗口的大小,請找出所有滑動窗口裏的最大值。例如,如果輸入數組 {2,3,4,6,2,5,1} 及滑動窗口的大小 3,那麼一定存在 6 個滑動窗口,它們的最大值分別爲 {4,4,6,6,6,5}。
2. 題目分析
在書上的方法比較好,但是如果不是很理解這個過程的話,不是很好理解書上所講述內容的含義,在這裏我用一種比較容易理解的方式進行描述。爲了輸出每個窗口中的最大值,我們使用了一個數組temp,數組temp中存放着當前窗口的最大值,和按需排列好的次大值,並且這些次大值在數組中的位置只能是位於最大之後的,數組 temp 的最大規模爲 size -1。
以上面的題目爲例,首先在數組temp中存儲 2 爲目前的最大值,之後讀取原始數組中的數字 3 ,由於3 比 2 大,所以將 2 彈出,將 3 壓入;然後讀取原始數組中的數字 4,由於4 比 3 大,所以將 3 彈出,將 4 壓入;讀取原始數組中的數字 6,由於 6 比 4 大,所以將 4 彈出,將 6 壓入;讀取原始數組中的數字 2,由於 6 比 2 大,所以 6 不會被彈出,但是這個時候 temp 的大小小於 size - 1,所以將 2 壓入(因爲他是目前除了6 以外最大的元素);讀取原始數組中的數字 5,由於 5 比 2 大,所以將 2 彈出,先不壓入5,而是將 5 與 6 進行比較,由於 6 比 5 大,所以 6 不會被彈出,但是這個時候 temp 的大小小於 size - 1,所以將 5 壓入;在讀取原始數組中的數字 1 之前我們發現,如果滑動窗口移動到了包含 1 的位置,那麼這個時候 6 已經是在窗口之外了,也就是說 6 是過期的,所以這個時候應該首先將 6 彈出,此時 temp 只剩下 5 ,取原始數組中的數字 1,由於 5 比 1 大,所以 5 不會被彈出,但是這個時候 temp 的大小小於 size - 1,所以將 1 壓入。
經過上面的舉例分析,我們已經得到在滑動窗口滑動的過程中 temp 的取值過程。但是並不是在讀取第一個元素的時候就開始輸出滑動窗口中的最大值,而是當整個滑動窗口都讀取到的時候才輸出
所以找出滑動窗口的最大值的過程,實際上就兩步工作:
(1)判斷當前的最大值是否過期。
(2)將讀入的數字與 temp 中的元素從後向前依次比較大小,將 temp 中小於讀入數字的元素都彈出;如果刪除後 temp 的大小還沒有達到 size - 1,那麼將這個元素壓入(刪除後 temp 的大小有可能達到 size - 1 嘛?有可能的!因爲可能經過比較發現 temp 中沒有元素被彈出)。
3. 代碼實現
# -*- coding:utf-8 -*-
class Solution:
def maxInWindows(self, num, size):
# 如果數組 num 不存在,則返回 []
if not num:
return []
# 如果滑動窗口的大小大於數組的大小,或者 size 小於 0,則返回 []
if size > len(num) or size <1:
return []
# 如果滑動窗口的大小爲 1 ,則直接返回原始數組
if size == 1:
return num
# 存放最大值,次大值的數組,和存放輸出結果數組的初始化
temp = [0]
res = []
# 對於數組中每一個元素進行判斷
for i in range(len(num)):
# 判斷第 i 個元素是否可以加入 temp 中
# 如果比當前最大的元素還要大,清空 temp 並把該元素放入數組
# 首先判斷當前最大的元素是否過期
if i -temp[0] > size-1:
temp.pop(0)
# 將第 i 個元素與 temp 中的值比較,將小於 i 的值都彈出
while (len(temp)>0 and num[i] >= num[temp [-1]]):
temp.pop()
# 如果現在 temp 的長度還沒有達到最大規模,將元素 i 壓入
if len(temp)< size-1:
temp.append(i)
# 只有經過一個完整的窗口才保存當前的最大值
if i >=size-1:
res.append(num[temp [0]])
return res