题目描述:
农夫约翰出门沿着马路散步,但是他现在发现自己可能迷路了!
沿路有一排共 N 个农场。
不幸的是农场并没有编号,这使得约翰难以分辨他在这条路上所处的位置。
然而,每个农场都沿路设有一个彩色的邮箱,所以约翰希望能够通过查看最近的几个邮箱的颜色来唯一确定他所在的位置。
每个邮箱的颜色用 A..Z 之间的一个字母来指定,所以沿着道路的 N 个邮箱的序列可以用一个长为 N 的由字母 A..Z 组成的字符串来表示。
某些邮箱可能会有相同的颜色。
约翰想要知道最小的 K 的值,使得他查看任意连续 K 个邮箱序列,他都可以唯一确定这一序列在道路上的位置。
例如,假设沿路的邮箱序列为 ABCDABC 。
约翰不能令 K=3,因为如果他看到了 ABC,则沿路有两个这一连续颜色序列可能所在的位置。
最小可行的 K 的值为 K=4,因为如果他查看任意连续 4 个邮箱,那么可得到的连续颜色序列可以唯一确定他在道路上的位置。
看了下题目,好像是求字符串连续重复的最大字串的长度maxlen
本题答案为maxlen+1;
这道题应该是问:字符串中任意查看连续k个字符
首先凭借这k个连续的字符能够确定该序列的位置,
其次其他地方没有出现过
最后k最小
直接做就是hhhhhh🙂
是不是很简单呢?直接上代码😂
时间复杂度 O(nlogn) sort 排序
参考文献
C++ 代码
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int n;
string str;
int getlength(string str1,string str2)
{
int i=0;
for(;i<str1.size(); i++)
if(str1[i] != str2[i])
break;
return i ;
}
int main()
{
cin>>n>>str;
vector<string> v;
for(int i=0 ; i< n ; i++)
{
string s = str.substr(i);
v.push_back(s);
}
sort(v.begin(),v.end());
int maxlen = 0;
for(int j=0 ; j<v.size()-1 ; j++)
{
int len = getlength(v[j],v[j+1]);
maxlen = max(maxlen,len);
}
return cout << maxlen+1 ,0;
}
java代码
import java.io.*;
import java.util.*;
public class Main {
static int n;
static String str;
public static int num(String str1,String str2)
{
int i=0;
for(;i<str1.length(); i++)
if(str1.charAt(i)!= str2.charAt(i))
break;
return i ;
}
public static void main(String args[]) {
Scanner cin = new Scanner(System.in);
n=cin.nextInt();
str=cin.next();
String v[]=new String [n];
for(int i=0;i<n;i++)
{
String s=str.substring(i);
v[i]=s;
}
Arrays.sort(v);
int maxlen=0;
for(int j=0;j<v.length-1;j++)
{
int len=num(v[j],v[j+1]);
maxlen=Math.max(maxlen,len);
}
System.out.println(maxlen+1);
return ;
}
}
方法二:哈希+枚举 O(nlogn)
#include <iostream>
#include <cstring>
#include <unordered_set>
using namespace std;
int main()
{
int n;
string s;
cin>>n>>s;
for(int i=1;i<=n;i++)
{ //枚举K
bool f=true;
unordered_set<string> q;
for(int j=0;j<=n-i;j++)
{ //枚举子串
auto c=s.substr(j,i);
if(q.count(c))
{ //该子串出现过 count:如果找不到c子串则返回0
f=false;
break;
}
q.insert(c); //加入该子串
}
if(f)
{
cout<<i<<endl;
break;
}
}
return 0;
}
其他人的解法
方法三:二分 O(nlogn)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int N = 110;
int n;
string a;
bool check(int x)
{
map<string ,int> cnt; // 记录某个子串出现次数
for (int i = 0; i < n; i ++ )
{
string temp = a.substr(i, x);
cnt[temp] ++ ;
if (cnt[temp] > 1) return false;
}
return true;
}
int main()
{
cin >> n;
cin >> a;
int l = 0, r = n - 1;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << r << endl;
return 0;
}
方法四:字符串哈希+二分 O(nlogn)
#include<cstdio>
#include<unordered_set>
using namespace std;
typedef unsigned long long ULL;
const int N=110,P=1331;
ULL h[N],p[N];
int n;
char s[N];
ULL getv(int l,int r){
return h[r]-h[l-1]*p[r-l+1];
}
bool isok(int x){
unordered_set<ULL>se;
for(int i=x;i<=n;i++){
ULL tmp=getv(i-x+1,i);
if(se.count(tmp))return false;
se.insert(tmp);
}
return true;
}
int main(){
p[0]=1;
scanf("%d%s",&n,s+1);
for(int i=1;i<=n;i++){
h[i]=h[i-1]*P+s[i];
p[i]=p[i-1]*P;
}
int l=1,r=n+1;
while(l<r){
int mid=l+r>>1;
if(isok(mid)){
r=mid;
}else{
l=mid+1;
}
}
printf("%d\n",l);
return 0;
}
Python代码(暴力) 太nb了,虽然我不懂hhhhhh
def main():
n = int(input())
s = input()
visited = set()
for k in range(1, n + 1):
visited.clear()
ok = True
for l in range(n - k + 1):
cur = s[l : l+k]
if cur in visited:
ok = False
break
visited.add(cur)
if ok == True:
print(k)
return
if __name__ == "__main__":
main()
方法五:和方法二类似 O(nlogn)
#include <iostream>
#include <string.h>
#include <algorithm>
#include <unordered_set>
using namespace std;
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n; cin >> n;
string s; cin >> s;
unordered_set<string> visited;
for (int k = 1; k < n + 1; k ++)
{
visited.clear();
bool ok = true;
for (int l = 0; l < n - k + 1; l ++)
{
string cur = s.substr(l, k);
if (visited.find(cur) != visited.end())
{
ok = false;
break;
}
visited.insert(cur);
}
if (ok == true)
{
cout << k << endl;
return 0;
}
}
return 0;
}
欢迎留言点赞
嗷嗷嗷