審題:
本題需要我們對于每一組數據都找出最大的包裹大小
思路:
本題解析題目意思后我們可以把雪花的編號當成數組中元素的值,把包裹看成一個區間。
本質上就是讓我們找出一組數據中,所有子段中最長的子段。
方法一:暴力解法
我們利用雙層for循環遍歷每一個子段,然后利用unordered_map來記錄子段區間的對應編號出現次數
不過這樣的話,由于內層的索引每次都要回到和外層索引一樣的位置,內層循環的遍歷次數就會比較多
方法二:滑動窗口(優化暴力解法)
簡單來說就是一種指針不回退的搜索方法
當我們搜索到一個編號的雪花出現了兩次的時候,我們就需要記錄區間長度,然后將區間范圍縮小,也就是left--。
此時我們的left可以移動到兩個區域
第一個是非法區域:也就是仍然有出現了兩次的編號在區間范圍內的區域
第二個是合法區域:也就是出現了兩次的編號已經有一個離開區間了的區域
若是非法區域,就算按照暴力解法將right回退也無法找到比當前更長的區間,所以沒有必要回退
若是合法區域,即使回退了也還是要指回當前right的索引位置,所以也沒有必要回退。
得出結論:無論如何right都不用回退
接下來我們看看滑動過程:
(1)初始狀態
(2)滑動
當區間中仍然存在出現兩次的編號,就不斷left--縮短區間(此時不用記錄長度,因為一定沒有之前沒縮短區間的時候長),直到合法為止,合法后即可記錄區間長度,然后right++繼續往后滑動。
解題:
?#include<iostream> #include<algorithm> #include<unordered_map> using namespace std; const int N = 1e6 + 10; unordered_map<int, int> m; int t, n; int a[N]; int maxsize; int main() {cin >> t;while (t--){//清空上一組殘留數據maxsize = 0;m.clear();//數據錄入cin >> n;for (int i = 1; i <= n; i++){cin >> a[i];}//開始搜索int left = 1;for(int right = 1; right <= n; right++){++m[a[right]];while(m[a[right]] > 1)//繼續縮短區間{m[a[left]]--;left++;}maxsize = max(maxsize, right - left + 1);}cout << maxsize << endl;}return 0; }
1.數組a是不用重置的,因為我們每一組數據都會重新錄入,且只訪問到n,不會訪問到殘留數據
2.unordered_map和unordered_set的清空都是使用clear
3.由于right索引位置也是屬于區間內的(區間左閉右閉),所以我們進行size計算的時候需要再加個1
UVA11572 唯一的雪花 Unique Snowflakes - 洛谷