1.题目
题目描述
农夫约翰出门沿着马路散步,但是他现在发现自己可能迷路了!
沿路有一排共 N 个农场。
不幸的是农场并没有编号,这使得约翰难以分辨他在这条路上所处的位置。
然而,每个农场都沿路设有一个彩色的邮箱,所以约翰希望能够通过查看最近的几个邮箱的颜色来唯一确定他所在的位置。
每个邮箱的颜色用 A..Z 之间的一个字母来指定,所以沿着道路的 N 个邮箱的序列可以用一个长为 N 的由字母 A..Z 组成的字符串来表示。
某些邮箱可能会有相同的颜色。
约翰想要知道最小的 K 的值,使得他查看任意连续 K 个邮箱序列,他都可以唯一确定这一序列在道路上的位置。
例如,假设沿路的邮箱序列为 ABCDABC 。
约翰不能令 K=3,因为如果他看到了 ABC,则沿路有两个这一连续颜色序列可能所在的位置。
最小可行的 K 的值为 K=4,因为如果他查看任意连续 4 个邮箱,那么可得到的连续颜色序列可以唯一确定他在道路上的位置。
样例
输入样例:7ABCDABC输出样例:4
2.思路分析
此题找到最小的不能满足找到与他一样的子串的子串即可
对于k依次遍历,再建立一个set数组,因set的特性不能重复添加相同的值,故可以判断是否为子串,然后依次截取子串并进行判断,如果存在则提前结束,不存在则添加进去
分暴力和二分两种做法,最后比较一下代码优化效率
3.暴力算法
import java.io.*; import java.util.HashSet; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine()); String s = br.readLine(); for(int i=1;i<=n;i++){ HashSet<String> hs=new HashSet<>(); boolean flag=true; for(int j=0;j<=n-i;j++){ String t=s.substring(j,j+i); if(hs.contains(t)){ flag=false; break; } hs.add(t); } if(flag){ System.out.println(i); return; } } } }
4.二分算法
import java.io.*; import java.util.HashSet; public class Main { public static void main(String[] args) throws IOException { BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); int n=Integer.parseInt(br.readLine()); String s=br.readLine(); int l=1,r=n; while (l<r){ int mid=l+r>>1; if(checked(mid,n,s)) r=mid; else l=mid+1; } System.out.println(l); } private static boolean checked(int mid,int n,String s) { HashSet<String> set = new HashSet<>(); for(int i = 0;i + mid <= n;i++) { String ns = s.substring(i,i + mid); if(set.contains(ns)) return false; set.add(ns); } return true; } }
5.结尾
数据范围不大,二分算法也只优化了10Ms
感谢你能看完, 如有错误欢迎评论指正,有好的思路可以交流一波,如果对你有帮助的话,点个赞支持下