雙指標演算法的一個簡單題解

fafatadie發表於2024-10-12

題目是這樣的:
給定一個長度為 n
的整數序列,請找出最長的不包含重複的數的連續區間,輸出它的長度。
輸入格式
第一行包含整數 n

第二行包含 n
個整數(均在 0∼105
範圍內),表示整數序列。
輸出格式
共一行,包含一個整數,表示最長的不包含重複的數的連續區間的長度。
資料範圍
1≤n≤105
輸入樣例:
5
1 2 2 3 5
輸出樣例:
3
這題用雙指標演算法,先介紹一下雙指標演算法,雙指標演算法最大的一個好處便是把時間複雜度從o(n**2)降低到o(n),這道題如果我們使用樸素的暴力列舉是可以做的,最好的列舉結果是
int res = 0

for(int i = 1;i <= n; i ++)

for(int j = 1;j <= i;j ++)
{
if check(i,j)//這裡的函式是判斷i到j之間有無重複元素

  continue;

else

  res = max(res,i - j + 1);

}

這段程式碼的時間複雜度是O(n^2)。

解析:

外層迴圈從1到n,共執行n次。
內層迴圈在最壞情況下(即每次i都滿足check(i, j)條件)會執行i次,因此總的執行次數為1 + 2 + ... + n = n * (n + 1) / 2,這是一個關於n的二次函式。
因此,時間複雜度為O(n^2)。
為什麼雙指標演算法的時間複雜度是o(n)呢?
第一層迴圈列舉n次,但第二層的執行次數最多是n次,屬於o(1)的複雜度,所以總的時間複雜度便是o(n)的複雜度。

附上本題的c++程式碼:

include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n;
int a[N],s[N];//a是原陣列,s是統計從j到i之間每個元素出現的次數

int main()
{
int res = 0;//答案
cin >> n;
for(int i = 0;i < n;i ++) cin >> a[i];

for(int i = 0,j = 0;i < n;i ++)
{
	s[a[i]] ++;
	
	while(s[a[i]] > 1)
	{
		s[a[j]] --;//移動j指標,直到沒有重複的元素
		j ++;
	}//這部分程式碼當這次列舉的i與上一次的重複時會執行
	
	res = max(res , i - j + 1);
}

cout << res << endl;

return 0;

}
若有不足之處還望指出,感謝您的瀏覽!

相關文章