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源代码如下,感觉写的棒棒哒~
这个题目的意思是给你一个字符串,让你找出一个字符不重复的子串,并且这个子串的长度要尽可能的长,输出满足条件的子串最大长度。
乍一听还挺复杂,但是静下来再读一遍,起码首先能够得到一个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; } }
相关文章推荐
- 3.求数组最大值[分治递归]
- js中的caller和callee
- 寒假笔记——java
- Qml文件的两种加载方式|启动Qt quick app的两种方法
- XZ_iOS中清除缓存的实现
- Example_java_测试
- tcp短连接TIME_WAIT问题解决方法大全(2)——SO_LINGER
- 给一个控制器的view设置背景图片
- android 的jpush极光推送
- 面试1-HTTP状态码
- .NET中的异步编程
- hdu2255奔小康赚大钱 KM算法
- Java——FileInputStream&FileOutputStream字节流实现文件复制
- Indivisibility(最大公约数+排列组合)
- HTML学习笔记(一)
- codeforces--651B Beautiful Paintings
- a:link,a:visited,a:hover,a:active 区别
- 分布式Web应用----Java动态代理技术实现原理分析
- dxRibbonRadialMenu控件使用
- 对微信的评价