1. 程式人生 > 實用技巧 >webhooks鉤子自動部署程式碼簡介

webhooks鉤子自動部署程式碼簡介

目錄

模板題

傳送門

很疑惑怎麼就是藍題了,這演算法不難理解呀(比KMP好多了)

概念

給定一個字串s,不斷把s的最後一個元素放到開頭,可以得到n個字串,其中字典序最小的一個稱為s的最小表示.

另外,這n個字串被稱作是迴圈同構的,為了方便敘述,這裡定義b[]儲存s的迴圈同構字串,且b[i]表示以s的第i位開頭的字串

樸素演算法

根據定義,列舉所有的b,逐位匹配找出最小值,複雜度O(n^2)

優化演算法

首先,將s變化為:s=s+s,得b[i]=s.substr(i,s.size())(substr意義同C++string)

s[i+k] > s[j+k]

,顯然,b[i]不是最小表示.此外,b[i+1],b[i+2]...b[i+k]均不是最小表示

原因:

對於p(1<=p<=k),存在一個比b[i+p]更小的迴圈同構串:b[j+p](這裡不太好理解,但是仔細想想,或者搞個字串模擬一下,還是可以理解的)

因此,每次找到s[i+k] > s[j+k]時,i=i+k+1,若得到的i等於j,則++i

時間複雜度

結論:O(n)

證:

若每次比較從前向後掃描了k的長度,則i或j二者之一會向後移動k,而i和j合計一共最多向後移動2n的長度,因此時間複雜度為O(n)

模板題程式碼

#include <iostream>
#include <cstdio>
using namespace std;
int read() {
	int re = 0;
	bool sig = false;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-')sig = true;
		c = getchar();
	}
	while(c >= '0' && c <= '9')
		re = (re << 1) + (re << 3) + c - '0',
		c = getchar();
	return sig ? -re : re;
} 
int n ; 
int a[600010];
int main() {
	n = read();
	for(int i = 1 ; i <= n ; i++)
		a[i] = a[n + i] = read();
	
	int i = 1 , j = 2 , k;
	while(i <= n && j <= n) {
		for(k = 0 ; k < n && a[i + k] == a[j + k] ; k++);
		if(k == n)break;
		if(a[i + k] > a[j + k]) {
			i = i + k + 1;
			if(i == j)++i;
		}
		else {
			j = j + k + 1;
			if(i == j)++j;
		}
	}
	int ans = (i < j ? i : j);
	for(int p = ans ; p < ans + n ; p++)
		printf("%d " , a[p]); 
	return 0;
}