在瀏覽網頁的時候,快取技術能夠迅速地顯示頁面。這裡我們對瀏覽器的快取技術進行簡化:我們認為瀏覽器的快取大小為m,表示快取可以儲存m個頁面。
當使用者訪問url時,瀏覽器會先到快取中查詢是否有該頁面的記錄,如果有則直接從快取中提取資料;否則,會傳送網路請求,從internet獲取該頁面,並將該頁面放入快取中。當快取中的頁面數量超過m時,快取技術會替換掉快取中最不頻繁訪問的網頁,即最後訪問時間最早的頁面。
現在,我們希望對於給定的使用者訪問歷史記錄,請判斷出每一次訪問頁面是從快取中讀取的,還是通過網路請求獲得的。(快取最開始資料為空)
本題的實質是模擬快取的工作。
簡單的演算法
我們直接純粹的模擬快取,每當訪問乙個新的頁面時,我們去遍歷現在的m條快取記錄。一是確認當前瀏覽的頁面url是否存在於快取記錄中,二是找出當前快取記錄中最早的一條,並將其替換。
每一次操作的時間複雜度為o(m),由於一共有n條記錄,所以總的時間複雜度為o(nm)。
優化
首先我們可以知道o(nm)中的n是沒有辦法優化的,所以我們只能從每一次快取更新入手。
快取的更新分為兩個部分:
檢查當前頁面是否存在於快取
這乙個部分我們可以簡單的使用map來實現,簡單的用boolean(bool)型別來表示該url是否在快取中即可。
將快取記錄中最早的一條進行替換
之前我們採取的方法是通過o(m)的時間進行遍歷來查詢,如果我們將快取換用另一種資料結構來進行儲存就可以做到o(logn)。
比如二叉樹、小根堆等都可以做到。
在這裡打算講的是一種只使用map來完成快取的更新。
首先我們用a[1..n]來表示瀏覽網頁的記錄,用map< url, int > lastvisit的方式來對url進行記錄。
lastvisit[ a[i] ]表示a[i]這條url最後一次訪問時對應的時間。
我們知道快取的大小為m,而且滿足了快取中一定是m個不相同的url。
假設在我們現在的快取中最早的一條記錄對應的為a[s],最新的一條記錄對應的是a[t]。這樣對於第乙個問題,檢查當前頁面是否存在於快取,我們只需要判定當前i是否在[s,t]這個區間中。
同時可以證明在a[s..t]中至多包含有m條不同的url。
其證明:
假設a[s..t]中包含有m+1條不同的記錄,則我們加入第m+1條記錄時,在快取中是無法找到已經存在的記錄。我們一定會拋棄掉快取中最早的那條記錄a[s],並將其替換為第m+1條記錄。所以a[s..t]中一定至多包含m條不同的url記錄。
對於s,t的維護:
t一定總是等於i的,因為a[i]一定是最新的訪問記錄。
而對於s,我們一定有 lastvisit[ a[s] ] == s。因為若lastvisit[ a[s] ] = k,則一定有k>s,表示該url在[s+1,t]之中仍存在。若lastvisit[ a[s] ] = s,則表示在[s+1,t]這個區間內都沒有a[i]的訪問記錄了,a[s]則一定是[s,t]這個區間中最早的訪問記錄。
並且,若此時將a[s]從區間[s,t]中拋棄則表示將這個url從快取中拋棄。
所以我們總是要維護lastvisit[ a[s] ] == s。
我們舉個例子來說明:
該樣例中n=9, m=3。小寫的abcd表示4個不同的url。左邊表示我們的訪問記錄,右邊表示我們的lastvisit。
當進行到某一步時,s=1,t=5。
此時我們移動t+1,由於第6個網頁為d,並不在[s,t]中且m已經到達上限,所以我們需要將a彈出,s+1。同時更新lastvisit[d],得到中間的一步。
接著我們需要維護s,由於lastvisit[b] = 4, lastvisit[c] = 5,所以2,3位的b和c會被跳過,直到s=4,此時有lastvisit[b] = 4。
這樣得到最下面的一幅圖,[s,t]完成了更新。
偽**
s = 1
for i = 1..n
if (lastvisit[ a[i] ] in [s,i])
print
"cache"
else
cachecnt = cachecnt + 1;
if (cachecnt > m) // 快取已滿
s = s + 1
// 將該a[s]從cache中拋棄
end if
print
"internet"
endlastvisit[ a[i] ] = i // 更新最後一次訪問時間
while (lastvisit[ a[s] ] != s)
s = s + 1
end while
// 更新s找到新的最早的訪問記錄
end for
時間複雜度方面,由於使用了map來維護,所以總的時間複雜度為o(nlogn)
該題目的現場通過率為37.5%。200人提交通過了75名選手。
作為該場比賽的第一題,通過率並不是特別高。而本題實際的難度並不大,如果直接從複雜度分析入手應該也能夠很容易推到出可行的辦法。
#include
#include
#include
#include
using
namespace
std;
int main() }}
return
0;}
hiho一下 第六十周
給定只包含字母的兩個字串a,b,求a,b兩個字串的最長公共子串行,要求構成子串行的子串長度都必須大於等於3。比如 abcdefghijklmn 和 ababceghjklmn 其最長滿足題意要求的子串行為 abcjklmn 其由公共子串 abc 和 jklmn 組成。這裡我們要注意子串和子串行的區別...
hiho一下 第二週
題目名稱 trie樹 小hi和小ho是一對好朋友,出生在資訊化社會的他們對程式設計產生了莫大的興趣,他們約定好互相幫助,在程式設計的學習道路上一同前進。這一天,他們遇到了一本詞典,於是小hi就向小ho提出了那個經典的問題 小ho,你能不能對於每乙個我給出的字串,都在這個詞典裡面找到以這個字串開頭的所...
hiho一下第143周
題目1 hiho密碼 時間限制 10000ms 單點時限 1000ms 記憶體限制 256mb 描述 小ho根據最近在密碼學課上學習到的知識,開發出了一款hiho密碼,這款密碼的秘鑰是這樣生成的 對於一種有n個字母的語言,選擇乙個長度為m的單詞 將組成這個單詞的所有字母按照順序不重複的寫出 即遇到相...