您的位置:首页 > 其它

LeetCode 3.Longest Substring Without Repeating Characters

2016-03-11 22:02 309 查看
碰到的第一个字符串问题。也是第一次学习String的用法。以前都是用的char数组,突然用起String还有些不习惯。。。。

这个题目的意思是给你一个字符串,让你找出一个字符不重复的子串,并且这个子串的长度要尽可能的长,输出满足条件的子串最大长度。

乍一听还挺复杂,但是静下来再读一遍,起码首先能够得到一个O(n ^ 2)的朴素实现的方法吧。首先一个 i 的循环,每次枚举从第 i 位开始的子串。内层循环就从 i 开始一直往后加,直到出现重复的了就停下。这个子串就是从 i 开始满足条件的最长子串,最后在所有结果中取最优即可。至于怎么判断是否重复,开个布尔数组 uesd[256],这里取256是因为扩展ASCLL码就256个,或者说char类型只占用一个字节。最开始全部初始化为 false,之后发现哪个字符有了,就把对应的位置改为
true,有点HASH表的意思,不过简单实用,经常用于各类算法中。

朴素实现比较容易,这里就不附源代码了(其实就是我懒得写。。。。。)。这里主要要介绍一种 O(n) 的方法。记不记得之前刚说过游标法很重要,这里我们也可以通过游标将朴素实现改为 O(n) 版本。还是需要一个布尔类型的used数组,用法和上面一样。还有两个游标 l 和 r。和上面有点类似,大家可以对比下,看看复杂度是怎么降下去的。

最开始还是一样,在 l 确定的时候,r 不断右移,得到一个从 l 开始满足条件的最长的子串。如果s( l .. r )满足条件,s( l .. r + 1)不满足,这个时候 r 不能再加了,需要 l 加一。注意,朴素的实现中,这个时候 r 会从新的 l 开始重新扫描,但实际上我们发现,因为s( l .. r )满足条件,所以 s( l + 1.. r )必定满足条件满足条件,这个时候 r 完全不需要重新扫描,保持原来不动就好。可能说的不是特别清楚,可以看看代码怎么写。

我一直强调在写代码的过程中,你要知道每个变量所代表的非常明确的意义。不然非常容易出现错误。比如在这里:

l 和 r 确定了s 的一个子串 s(l .. r),并且这个子串一定是一个满足所有字符不重复的一个子串。在我的程序里,不管l 和 r 怎么变,这一个条件一定成立。

used数组记录了对应子串s(l .. r)中的每个字符是否出现过,出现过就是true,没出现过就是false。这就是为什么程序里在 l++ 的时候要把used[s.charAt(l)]赋成false。

因为有一个字符被从s(l .. r)中剔除出来。我始终要维持这个数组的意义不变。

要说明这样写法是O(n)的也很容易,每次要么l++要么r++,所以最多也就操作 2n 次。

JAVA源代码如下,感觉写的棒棒哒~

public class Solution {
public int lengthOfLongestSubstring(String s) {
boolean[] used = new boolean[256];
int ans = 0;
Arrays.fill(used, false);
int len = s.length();
int l = 0, r = -1;    //s(l..r)为s的一个字符不重复的子串。这样的初始化代表一个空串。
for (; l < len; used[s.charAt(l++)] = false) {
while (r < len - 1 && !used[s.charAt(r + 1)])   used[s.charAt(++r)] = true;
ans = (ans > r - l + 1 ? ans : r - l + 1);  //不知道JAVA里的max函数怎么写,好囧o(╯□╰)o
}
return ans;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: