题目:求得给定字符串的最长连续子字符串(不能有重复字符)
题意的理解:
1.首先是对于字符串的匹配,我想当然的理解为了由小写字母组成的字符串,因为给的例子都是小写字母啊,而且一般OJ里的不都是这样吗!果然大意失荆州,文化差异还是存在的,实际评测字符串为ascll码所表示的字符串。(交上去第一发就挂了,然后改代码!)
2.题目所要求得的最长不重复子字符串,不就是两个相同的字符之间的最大距离吗?当然,在此距离之内不允许有相同字符。也就是说在扫描的过程中,遇到相同的字符,这次小的扫描就可以告一段落重新开始了。
翻译一下:
1.用head标记子字符串的头,tear标记子字符串的尾,初始的都指向index为0的位置,然后tear向后扫描;用一个position数组来存储在head和tear之间已经出现的某字符的位置(position的index是字符的ascll码,position的值是字符的最新出现位置)
2.如果遇到的是新字符,那就在一个flag数组position[256]中做一标记,表明该字符已经出现了(初始为-1)。
3.若tear扫描到一个已经在(head和tear之间)标记过的字符(eg:A),那么此时就可以算一下(tear和head)二者之间的距离了,看看是否是一个新的最优解。
然后head要把在head和tear之间曾出现过的字符(A)的位置跳过,tear才能继续向后扫描。这个时候要用tear所指示的A的位置更新一下标志数组position中A出现的位置,而当前head和tear之间未出现的字符在position中又要复位为-1。接着tear++,继续向后扫描,程序跳转到步骤2执行。
仔细想想:在步骤3,对于head位置的更新导致的position的重新赋值是不是很麻烦?的确,因为这需要从新的head值开始重新遍历从head到tear之间的部分。那么能不能再这一点上做出点小的改进呢?
当然可以,要不我写博客(重点!!!!!!!!)
看下面这段代码:
while(tear<arraycopy.length){
if(position[arraycopy[tear]]==-1){
/**
* 如果tear指示位置的字符在position中,没出现过(arraycopy是char型数组,就是我们要处理的字符串,char的值作为position的index,刚好每一个字符映射到不同的position中 )
* 那么就把tear指示的位置,加到该字符的position值中
* tear继续向后扫描
*/
position[arraycopy[tear]]=tear;
tear++;
}else{/**
* 重点:如果tear指示的字符(A)在position中出现了,那么直接计算head和tear的距离,看是否是新的最大值
* head更新为 (head,原先出现tear指示字符(A)的位置+1)的较大值
* 更新position数组,但是只跟新(A)的位置
* tear继续向后扫描
*
* 为什么只更新(A)的新位置而不更新整个position数组呢?——————因为没必要
* 例子说明:
* 对于输入"abba"
* 当head向0,而tear扫到2时,发现b重复了,那么新的head要跳到2,因为要避开1号位的b;
* tear++发现,3号位的a和position中存的0号位的a也重复了(其实没重复,因为0号位现在不属于head和tear之间)从而又引起了一次距离计算,但是这次不会得到一个更大的距离,maxlength不变
* 但此时引发了head的更新,head取 (2:head当前值,1:position中当前A的位置)的较大值,此时head的值也不变
* 但是接下来的一行会去自动更新重复的A的位置。
* 然后tear++继续扫描
*/
if(tear-head>maxlength)maxlength=tear-head;
head=Math.max(head, position[arraycopy[tear]]+1);
position[arraycopy[tear]]=tear;
tear++;
}
}
if(tear-head>maxlength)maxlength=tear-head;//在因为tear越界跳出循环后,还是要检查一下是否生成了新的maxlength
最后:上述代码的运行时间击败了91.53%的同语言对手,比以前的数据好看多了!!!哈哈哈
附上题目和完整代码:
3. Longest Substring Without Repeating Characters
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given "abcabcbb"
, the answer is "abc"
, which the length is 3.
Given "bbbbb"
, the answer is "b"
, with the length of 1.
Given "pwwkew"
, the answer is "wke"
, with the length of 3. Note that the answer must be a substring, "pwke"
is a subsequence and not a substring.
Subscribe to see which companies asked this question
import java.util.Arrays;
public class Solution {
public int lengthOfLongestSubstring(String s) {
int maxlength=Integer.MIN_VALUE;
int position[]=new int[255];
Arrays.fill(position, -1);
char array[]=s.toCharArray();
int arraycopy[]=new int[array.length];
for(int i=0;i<array.length;i++){
arraycopy[i]=array[i];
}
int head=0,tear=0;
while(tear<arraycopy.length){
if(position[arraycopy[tear]]==-1){
/**
* 如果tear指示位置的字符在position中,没出现过(arraycopy是char型数组,就是我们要处理的字符串,char的值作为position的index,刚好每一个字符映射到不同的position中 )
* 那么就把tear指示的位置,加到该字符的position值中
* tear继续向后扫描
*/
position[arraycopy[tear]]=tear;
tear++;
}else{/**
* 重点:如果tear指示的字符(A)在position中出现了,那么直接计算head和tear的距离,看是否是新的最大值
* head更新为 (head,原先出现tear指示字符(A)的位置+1)的较大值
* 更新position数组,但是只跟新(A)的位置
* tear继续向后扫描
*
* 为什么只更新(A)的新位置而不更新整个position数组呢?——————因为没必要
* 例子说明:
* 对于输入"abba"
* 当head向0,而tear扫到2时,发现b重复了,那么新的head要跳到2,因为要避开1号位的b;
* tear++发现,3号位的a和position中存的0号位的a也重复了(其实没重复,因为0号位现在不属于head和tear之间)从而又引起了一次距离计算,但是这次不会得到一个更大的距离,maxlength不变
* 但此时引发了head的更新,head取 (2:head当前值,1:position中当前A的位置)的较大值,此时head的值也不变
* 但是接下来的一行会去自动更新重复的A的位置。
* 然后tear++继续扫描
*/
if(tear-head>maxlength)maxlength=tear-head;
head=Math.max(head, position[arraycopy[tear]]+1);
position[arraycopy[tear]]=tear;
tear++;
}
}
if(tear-head>maxlength)maxlength=tear-head;//在因为tear越界跳出循环后,还是要检查一下是否生成了新的maxlength
return maxlength;
}
}