摘要:你只可以看到在滑動(dòng)窗口內(nèi)的數(shù)字。滑動(dòng)窗口每次只向右移動(dòng)一位。返回滑動(dòng)窗口最大值。算法思路暴力破解法用兩個(gè)指針,分別指向窗口的起始位置和終止位置,然后遍歷窗口中的數(shù)據(jù),求出最大值向前移動(dòng)兩個(gè)指針,然后操作,直到遍歷數(shù)據(jù)完成位置。
Time:2019/4/16
Title: Sliding Window Maximum
Difficulty: Difficulty
Author: 小鹿
Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.
給定一個(gè)數(shù)組 nums,有一個(gè)大小為 k 的滑動(dòng)窗口從數(shù)組的最左側(cè)移動(dòng)到數(shù)組的最右側(cè)。你只可以看到在滑動(dòng)窗口 k 內(nèi)的數(shù)字。滑動(dòng)窗口每次只向右移動(dòng)一位。返回滑動(dòng)窗口最大值。
Example:
Input: nums = [1,3,-1,-3,5,3,6,7], and k = 3 Output: [3,3,5,5,6,7] Explanation: Window position Max --------------- ----- [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7
Note:
You may assume k is always valid, 1 ≤ k ≤ input array"s size for non-empty array.
Follow up:
Could you solve it in linear time?
暴力破解法1)看到這個(gè)題目最容易想到的就是暴力破解法,借助一個(gè) for 循環(huán),兩個(gè)變量,整體移動(dòng)窗口,然后每移動(dòng)一次就在大小為 k 的窗口求出最大值。
2)但是這樣的解決效率非常低,如果數(shù)據(jù)非常大時(shí),共有 n1 個(gè)數(shù)據(jù),窗口大小為 n2(n1 遠(yuǎn)遠(yuǎn)大于 n2),時(shí)間復(fù)雜度為 n2(n1 - n2) 。也就是 n1 * n2,最壞時(shí)間復(fù)雜度為 n^2。
優(yōu)先級(jí)隊(duì)列
1)每次移動(dòng)窗口求最大值,以及在動(dòng)態(tài)數(shù)據(jù)中求最大值,我們想到的就是優(yōu)先級(jí)隊(duì)列,而優(yōu)先級(jí)隊(duì)列的實(shí)現(xiàn)是堆這種數(shù)據(jù)結(jié)構(gòu),這道題用堆解決效率更高。如果對(duì)堆不熟悉,趕緊給自己補(bǔ)補(bǔ)功課吧!底部有我寫的文章鏈接。
2)通過堆的優(yōu)化,向堆中插入數(shù)據(jù)時(shí)間復(fù)雜度為 logn ,所以時(shí)間復(fù)雜度為 nlogn。
暴力破解法:1)用兩個(gè)指針,分別指向窗口的起始位置和終止位置,然后遍歷窗口中的數(shù)據(jù),求出最大值;向前移動(dòng)兩個(gè)指針,然后操作,直到遍歷數(shù)據(jù)完成位置。
優(yōu)先級(jí)隊(duì)列:
1)需要維護(hù)大小為 k 的大頂堆,堆頂就是當(dāng)前窗口最大的數(shù)據(jù),當(dāng)移動(dòng)窗口時(shí),如果插入的數(shù)據(jù)大于堆頂?shù)臄?shù)據(jù),將其加入到結(jié)果集中。同時(shí)要?jiǎng)h除數(shù)據(jù),如果刪除的數(shù)據(jù)為最大數(shù)據(jù)且插入的數(shù)據(jù)小于刪除的數(shù)據(jù)時(shí),向大小為 k 的以 logn 的時(shí)間復(fù)雜度插入,返回堆頂元素。
var maxSlidingWindow = function(nums, k) { if(k > nums.length || k === 0) return []; let res = [], maxIndex = -1; for(let l = 0, r = k-1;r < nums.length;l++, r++){ if(maxIndex < l){ // 遍歷求出最大值 let index = l; for(let i = l;i <= r;i++) { if(nums[i] > nums[index]) index = i; } maxIndex = index; } if(nums[r] > nums[maxIndex]){ maxIndex = r; } res.push(nums[maxIndex]); } return res; };
let count = 0; let heap = []; let n = 0; var maxSlidingWindow = function(nums, k) { let pos = k; n = k; let result = []; let len = nums.length; // 判斷數(shù)組和最大窗口樹是否為空 if(nums.length === 0 || k === 0) return result; // 建大頂堆 let j = 0 for(;j < k; j++){ insert(nums[j]); } result.push(heap[1]); // 移動(dòng)窗口 while(len - pos > 0){ if(nums[k] > heap[1]){ result.push(nums[k]); insert(nums[k]); nums.shift(); pos++; }else{ if(nums.shift() === heap[1]){ removeMax(); } insert(nums[k-1]); result.push(heap[1]); pos++; } } return result; }; // 插入數(shù)據(jù) const insert = (data) =>{ //判斷堆滿 // if(count >= n) return; // >= // 插入到數(shù)組尾部 count++ heap[count] = data; //自下而上堆化 let i = count; while(i / 2 > 0 && heap[i] > heap[parseInt(i/2)]){ swap(heap,i,parseInt(i/2)); i = parseInt(i/2); } } // 兩個(gè)數(shù)組內(nèi)元素交換 swap = (arr,x,y) =>{ let temp = arr[x]; arr[x] = arr[y]; arr[y] = temp; } // 堆的刪除 const removeMax = () =>{ // 判斷堆空 if(count <= 0) return ; // 最大數(shù)據(jù)移到最后刪除 heap[1] = heap[count]; // 長度減一 count--; // 刪除數(shù)據(jù) heap.pop(); // 從上到下堆化 heapify(heap,count,1); } // 從上到下堆化 const heapify = (heap,count,i) =>{ while(true){ // 存儲(chǔ)堆子節(jié)點(diǎn)的最大值下標(biāo) let maxPos = i; // 左子節(jié)點(diǎn)比父節(jié)點(diǎn)大 if(i*2 < n && heap[i*2] > heap[i]) maxPos = i*2; // 右子節(jié)點(diǎn)比父節(jié)點(diǎn)大 if(i*2+1 <= n && heap[i*2+1] > heap[maxPos]) maxPos = i*2+1; // 如果沒有發(fā)生替換,則說明該堆只有一個(gè)結(jié)點(diǎn)(父節(jié)點(diǎn))或子節(jié)點(diǎn)都小于父節(jié)點(diǎn) if(maxPos === i) break; // 交換 swap(heap,maxPos,i); // 繼續(xù)堆化 i = maxPos; } }
暴力破解法
時(shí)間復(fù)雜度:O(n^2).
空間復(fù)雜度:O(1).
優(yōu)先級(jí)隊(duì)列
時(shí)間復(fù)雜度:nlogn.
空間復(fù)雜度:O(1).
堆:1)堆插入、刪除操作
2)如何實(shí)現(xiàn)一個(gè)堆?
3)堆排序
4)堆的應(yīng)用
詳細(xì)查看寫的另一篇關(guān)于堆的文章:數(shù)據(jù)結(jié)構(gòu)與算法之美【堆】
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/103623.html
摘要:題目要求假設(shè)有一個(gè)數(shù)組和一個(gè)長度為的窗口,數(shù)組長度。當(dāng)窗口右滑時(shí),會(huì)刪除下標(biāo)上的值,并加入下標(biāo)上的值。此時(shí)中記錄的值編程了,并返回當(dāng)前的最大值為。一旦最大值失效,就從窗口中重新找一個(gè)最大值就好了。 題目要求 Given an array nums, there is a sliding window of size k which is moving from the very lef...
摘要:這樣,我們可以保證隊(duì)列里的元素是從頭到尾降序的,由于隊(duì)列里只有窗口內(nèi)的數(shù),所以他們其實(shí)就是窗口內(nèi)第一大,第二大,第三大的數(shù)。 Sliding Window Maximum Given an array nums, there is a sliding window of size k which is moving from the very left of the array to...
摘要:丟棄隊(duì)首那些超出窗口長度的元素隊(duì)首的元素都是比后來加入元素大的元素,所以存儲(chǔ)的對(duì)應(yīng)的元素是從小到大 Problem Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only...
摘要:小鹿題目二叉樹的最大深度給定一個(gè)二叉樹,找出其最大深度。二叉樹的深度為根節(jié)點(diǎn)到最遠(yuǎn)葉子節(jié)點(diǎn)的最長路徑上的節(jié)點(diǎn)數(shù)。求二叉樹的深度,必然要用到遞歸來解決。分別遞歸左右子樹。 Time:2019/4/22Title: Maximum Depth of Binary TreeDifficulty: MediumAuthor:小鹿 題目:Maximum Depth of Binary Tre...
摘要:小鹿題目驗(yàn)證二叉搜索樹給定一個(gè)二叉樹,判斷其是否是一個(gè)有效的二叉搜索樹。假設(shè)一個(gè)二叉搜索樹具有如下特征節(jié)點(diǎn)的左子樹只包含小于當(dāng)前節(jié)點(diǎn)的數(shù)。所有左子樹和右子樹自身必須也是二叉搜索樹。算法思路定義全局的變量,用來返回是否為二叉搜索樹。 Time:2019/4/24Title: Vaildata Binary Search TreeDifficulty: MediumAuthor: 小鹿 ...
閱讀 3436·2023-04-25 22:44
閱讀 952·2021-11-15 11:37
閱讀 1646·2019-08-30 15:55
閱讀 2660·2019-08-30 15:54
閱讀 1098·2019-08-30 13:45
閱讀 1444·2019-08-29 17:14
閱讀 1867·2019-08-29 13:50
閱讀 3426·2019-08-26 11:39