93 隱藏口令
作者: 5.5.2時間限制: 1S章節: 字符串
問題描述 :
有時候程序員有很奇怪的方法來隱藏他們的口令。
Billy"Hacker"Geits會選擇一個字符串S(由L個小寫字母組成,5<=L<=100,000),然後他把S順時針繞成一個圈。
如字符串cbadfa,繞成一個圈後,我們認爲字符串首尾相連。
每次取其中一個字母作爲起始字母,並順時針依次取字母而組成一個字符串。這樣將得到一些字符串。
比如字符串cbadfa,按照以上規則取出的字符串有:
cbadfa badfac adfacb dfacba facbad acbadf
我們找到最小的那個字符串,可知爲acbadf,也可知道它的第一個字符’a’在原字符串cbadfa中爲第6個字符(位置從1開始),
將得到的結果6減1得到5,這就是我們需要的口令。
再比如字符串alabala,繞成一個圈後,每次取其中一個字母作爲起始字母,並順時針依次取字母而組成一個字符串。這樣將得到一些字符串:
alabala labalaa abalaal balaala alaalab laalaba aalabal
我們找到最小的那個字符串,可知爲aalabal,它的第一個字母’a’在原字符串中位置爲7,7-1=6,則6爲口令。
注:如果按照規則有兩個字符串都是最小的,則取前面那一個。 輸入說明 :
第一行:一個數L
第二行及之後:字符串S。
注意:字符串S可跨多行,但其中的’\n’不算成S中的字符 輸出說明 :
一行,爲得到的口令。
無多餘空格或空行。 輸入範例 : 6 cbadfa 輸出範例 : 5
代碼:
/*
T93 隱藏口令
*/
#include<stdio.h>
#include<string.h>
#define MAX_SIZE 100005
int main() {
int L = 0;
char ch;
int i = 0, j = 0, k = 0;
int index = 0;// 取的字符下標
char oriStr[MAX_SIZE] = "";// 原始字符串
char str[MAX_SIZE] = "";// 構造後的字符串
char minStr[MAX_SIZE] = "";// 構造後的最小字符串
int minIndex = 0;// 最小字符串在原字符串中的開始下標
minStr[0] = 'z' + 5, minStr[1] = '\0';
scanf("%d", &L);
getchar();// 吸收換行符
while (i < L) {
ch = getchar();
if (ch != '\n')
oriStr[i++] = ch;
}
oriStr[i] = '\0';
for (i = 0; i < L; i++) {
k = 0;
for (j = 0; j < L; j++) {
index = i + j;
if (index >= L)
index = index - L;
str[k++] = oriStr[index];
}
str[k] = '\0';
if (strcmp(str, minStr) == -1) {
strcpy(minStr, str);// 更新最小
minIndex = i;
}
}
printf("%d\n", minIndex);
return 0;
}
我的思想是暴力破解,比較low
看了位大佬寫的,沒想到還能這麼解決,於是修改了下代碼:
/*
T93 隱藏口令
算法概述:假設第i個位置往後取L個能達到最小。
再引入兩個變量j, k,j用於和i取到的相比較,k表示當前已經取了k個字母。
初始時i=0, j=1, k=0;根據比較的大小更新i,j,k的值,當k達到L的時候說明
比較完畢,此時輸出i和j中較小的那個
*/
#include<stdio.h>
#include<string.h>
#define MAX_SIZE 100005
int main() {
int L = 0;
int i = 0, j = 0, k = 0;
char ch;
char oriStr[MAX_SIZE] = "";// 原始字符串
scanf("%d", &L);
getchar();// 吸收換行符
while (i < L) {
ch = getchar();
if (ch != '\n')
oriStr[i++] = ch;
}
oriStr[i] = '\0';
i = 0, j = 1;
while (i < L && j < L && k < L) {
k = 0;// 重新開始比較
while (oriStr[(i + k) % L] == oriStr[(j + k) % L] && k < L)// 相等的情況
k++;
if (k == L)
break;
if (oriStr[(i + k) % L] > oriStr[(j + k) % L]) {// 前者比後者大的情況
i += k + 1;
}
else {
j += k + 1;
}
if (i == j) {// 處理位置重合的情況
j++;
}
}
printf("%d\n", i < j ? i : j);
return 0;
}
參考了大佬
從這個題我學到了:
- 求最小循環子串的一種思想