最长不含重复字符的字符串
题目
- 请从字符串中找出一个最长的不包含重复字符的字符串,计算最长子字符串的长度;假设字符串中只包含‘a’~‘z’的字符;
- 例如,在字符串“arabcacfr”中,最长的不包含重复子字符串是“acfr”,长度为4;
分析
- 用动态规划来提高效率;首先定义一个函数f(i)表示以第i个字符为结尾的不包含重复字符的子字符串的最长长度;f(i-1)表示以第i-1个字符为结尾的不包含重复的字符串长度;
- 如果第i个字符没有出现过,那么f(i)=f(i-1)+1;
- 例如,在字符串“arabcacfr”中,显然f(0)等于1,;在计算f(1)时,下标为1的字符‘r‘之前也没有出现过,因此f(1)=2,即f(1) = f(0)+1;,到此为止,最长字符串为“ar”
- 如果第i个字符之前已经出现过,那情况就复杂了;我们先计算第i个字符和他上次出现在字符串中的位置的距离,d;
- 第一种情况:d<=f(i-1) ,此时第i个字符上次出现在f(i-1)对应的最长子字符串中,因此f(i)=d;我们接着上面的算f(2),下标为2的值是a,a之前出现过,上一次出现的位置是0,他们之间的距离是d=(i-preIndex)为2,也就是字符’a‘出现在f(1)对应的最长不含重复字符的子字符串“ar”中,此时f(2)=d,即f(2)=2;
- 第二种情况:d>f(i-1),此时字符串上次出现的位置在f(i-1)对应的最长子字符串的前面,因此仍然有f(i)=f(i-1)+1;现在看最后一个字符’r‘就是,他重复的就不再前一个的最长子字符串里,所以还是f(8)=f(7)+1=4;
分析
- 核心方法findLongestSubstring() curLen=0当前没有重复的字符串长度,也就是f(i-1)
- maxLen=0最大字符串长度
- 定义一个位置数组,表示当前的a~z在str里出现的位置
- 最开始全都设成-1,证明没有在str里出现过
- 从头开始遍历字符串 得到字符
- char t=str.charAt(i);
- 去位置数组里,找到该字符在str字符串里出现的位置,为-1就是没有出现过
- int preIndex=position[t-'a']
- 得到两个重复字符的距离(i-preIndex)用当前位置i,减去之前出现的位子
- 如果preIndex=-1||d》curLen
- preIndex等于-1就是代表没在str字符串里出现过,d》curLen出现的重复的字符不在f(i-1)里,所以没关系 当前长度++
- 前面的就不要了,保留从现在开始
- 就赋值
package No15_优化空间和时间效率;
/**
* 创建人:Jason
* 创建时间:2019/1/18
* 描述你的类:
* //题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子
* //字符串的长度。假设字符串中只包含从'a'到'z'的字符。
动态规划,
定义f(i)表示以第i个字符为结尾的不含重复字符的子字符串长度。
定义f(i -1)表示以第i-1个字符为结尾的不含重复字符的子字符串长度。
如果第i个字符之前没有出现过,则f(i) = f(i -1) +1,比如‘abc',f(0) = 1是必然的,
再字符'b'之前没有出现过, 则f(1) = f(0)+1,
字符’c'之前没有出现过,那么f(2) = f(1) +1,每次计算都会用到上一次计算的结果。
如果第i个字符之前出现过呢?找到该字符上次出现的位置preIndex,当前位置d=i-preIndex就得到这两个重复字符之间的距离, 设为d。
此时有两种情况:
如果d <= f(i-1),说明当前重复字符必然在f(i-1)所对应的字符串中,比如'bdcefgc',当前字符c前面出现过了,preIndex为2,
此时d = 6 -2 = 4 ,小于 f(i -1) = 6 (bdcefg)我们只好丢弃前一次出现的字符c及其前面的所有字符,得到当前最长不含重复字符的子
字符串为’efgc‘,即f(i) = 4, 多举几个例子就知道,应该让f(i) = d;
如果d > f(i-1), 这说明当前重复字符必然出现在f(i-1)所对应的字符串之前,比如erabcdabr当前字符r和索引1处的r重复,
preIndex =1, i = 8,d=(i-preIndex) = 7。而f(i -1) = 4 (取索引4之后不包含重复字符的串cdab),而7>4,
此时直接加1即可, 即f(i) = f(i-1) +1
*/
public class LongestSubstringWithoutDup {
//核心方法
public int findLongestSubstring(String str){
//当前长度
int curLen = 0;
//最大长度
int maxLen = 0;
//定义一个位置数组,用来储存该字符出现在str的位置
int []pos = new int[26];
for(int i = 0;i < 26;i++){
//初始化全是-1
pos[i] = -1;
}
//从头开始遍历字符串
for(int i = 0;i < str.length();i++){
char t = str.charAt(i);
//查看该字符是否出现在str里,如果出现过的话,preIndex就不是-1
int preIndex = pos[t-'a'];
//得到两个重复字符的距离,查看这个距离和f(i-1)的大小,这个重复的是数,是否在f(i-1)里
int d = i - preIndex;
//不重复或者重复在外面,不在f(i-1)里面
if(preIndex == -1 || d > curLen){
curLen++;
}
//如果在里面的话,前面就不要了,从该位置开始
else{
curLen = d;
}
//证明该点出现过
pos[t-'a'] = i;
if(curLen > maxLen){
maxLen = curLen;
}
}
return maxLen;
}
7ff7
// ====================测试代码====================
void testSolution1(String input, int expected){
int output = findLongestSubstring(input);
if(output == expected)
System.out.printf( "passed, with input: "+input+" expected:"+expected+"\n");
else
System.out.printf( "FAILED, with input: " +input+"\n");
}
void test(String input, int expected){
testSolution1(input, expected);
}
void test1(){
String input = "arabcacfr";
int expected = 4;
test(input, expected);
}
void test2()
{
String input = "acfrarabc";
int expected = 4;
test(input, expected);
}
void test3()
{
String input = "arabcacfr";
int expected = 4;
test(input, expected);
}
void test4()
{
String input = "aaaa";
int expected = 1;
test(input, expected);
}
void test5()
{
String input = "abcdefg";
int expected = 7;
test(input, expected);
}
void test6()
{
String input = "aaabbbccc";
int expected = 2;
test(input, expected);
}
void test7()
{
String input= "abcdcba";
int expected = 4;
test(input, expected);
}
void test8()
{
String input = "abcdaef";
int expected = 6;
test(input, expected);
}
void test9()
{
String input= "a";
int expected = 1;
test(input, expected);
}
void test10()
{
String input = "";
int expected = 0;
test(input, expected);
}
public static void main(String args[]){
new LongestSubstringWithoutDup().test1();
new LongestSubstringWithoutDup().test2();
new LongestSubstringWithoutDup().test3();
new LongestSubstringWithoutDup().test4();
new LongestSubstringWithoutDup().test5();
new LongestSubstringWithoutDup().test6();
new LongestSubstringWithoutDup().test7();
new LongestSubstringWithoutDup().test8();
new LongestSubstringWithoutDup().test9();
new LongestSubstringWithoutDup().test10();
}
}
- 从字符串中找出一个最长的不含重复字符的子字符串
- 定义一个栈的数据结构,实现min函数,要求push,pop,min时间复杂度是0(1);找出字符串中的最长子串,要求子串不含重复字符,时间复杂度是O(n);
- C++找出字符串中最长的不含重复字符的子串
- 求字符串中不含重复字符的最长子串
- 【Java】面试题48:最长不含重复字符的子字符串
- 面试题:最长不含重复字符的子字符串
- 定义一个栈的数据结构,实现min函数,要求push,pop,min时间复杂度是0(1);找出字符串中的最长子串,要求子串不含重复字符,时间复杂度是O(n);
- 字符串最长不含重复字符的子串长度
- 求字符串最长不含重复字符的子串长度
- 在英文字符串中找第一个最长不含重复字符的子串高效实现(修改版)
- 百度面试题 求字符串中不含重复字符的最长子串长度
- 求字符串中不含重复字符的最长子串的长度
- 求字符串中不含重复字符的最长子串的长度
- 字符串中不重复字符的最长子串
- 求字符串中最长无重复字符的子串
- 查找字符串中最长重复字符的子串
- 贪心法应用:不含重复字符的最长子串
- Leet Code3 查找字符串中最长不重复的字符
- 3. Longest Substring Without Repeating Characters(计算不含重复字符的最长子串的长度)
- Python查找最长不包含重复字符的子字符串算法示例