[Lesson Learn] LeetCode #3 Longest Substring Without Repeating Characters
来源:互联网 发布:golang.org上不去 编辑:程序博客网 时间:2024/04/30 15:05
首先先赞一下LeetCode,这道题暴力解法(会超时)原本的Java版参考答案中有一处错误,反馈后仅仅5分钟就解决了,算上读题理解代码的时间,意味着刚反馈就开始回应了。点赞。
首先想到的就是暴力破解,穷举各种可能性,然后逐一判断是否是不包含重复字母的子串,然后记录其中最长的子串的长度。
LeetCode上提供的修正了错误之后的暴力破解的代码如下:
public class Solution { public int lengthOfLongestSubstring(String s) { int n = s.length(); int ans = 0; for (int i = 0; i < n; ++i) for (int j = i + 1; j <= n; ++j) if (allUnique(s, i, j)) ans = Math.max(ans, j - i); return ans; } public boolean allUnique(String s, int start, int end) { Set<Character> set = new HashSet<>(); for (int i = start; i < end; ++i) { Character ch = s.charAt(i); if (set.contains(ch)) return false; set.add(ch); } return true; }}以上代码是完全遍历了所有的情况,一个不漏。
如果一个子集包含重复字母,则它的超集必然也是。所以可以在内层for循环的if判断后边加一句:
else break;进行剪枝。
然而依旧超时。
每次判断是否是不包含重复字母的子串时,可以不用从头判断该子串的每一个字母,只需判断新加入的这一个字母是否在原子串中存在即可。
如果不在原子串中,则无事继续。如果已经在原来的子串中,则这两个字母之间的内容保留,而这两个重复字母则只能取其一。因为是从一端开始扫描过来的,假设是左端,那左端的所有信息已经全部掌握了,所以需要将左端的重复字母舍弃,保留右端的那个字母,然后继续向右扫描,直至结束。
为了迅速判断是否已经存在,要用到Map<Character, Integer>的containsKey()方法。为什么这里不是使用Set<Character>的contains()方法,而非得用Map的?Set和Map的区别在哪?或者换个类似的问题,集合和数组的区别在哪?一个无序一个有序,有序的数组的下标中可以包含位置信息。通过加一个Integer,来存储字母的位置信息。通过字母的位置信息,来判断一个字母是否符合要求。
假设用(i, j]来表示没有重复字母的子串中的字母的位置区间,j-i即中间所包含的数量,半开半闭区间的好处就在于,右侧减左侧即为差值,不用再考虑加一或者减一的问题。
读取的数据保存在字符串s中,下标从0开始。所以初始值,i为-1,j为0。用Map<Character, Integer>来保存已经扫描过的字母的信息,其中Integer保存的是已扫描部分中,值为Character的字母的最右边的位置。
public class Solution { public int lengthOfLongestSubstring(String s) { int n = s.length(), ans = 0; Map<Character, Integer> map = new HashMap<>(); for (int j = 0, i = -1; j < n; ++j) { char thisChar = s.charAt(j); if (map.containsKey(thisChar)) { i = Math.max(map.get(thisChar), i); } map.put(thisChar, j); ans = Math.max(ans, j - i); } return ans; }}
每一次循环读取一个值,设为thisChar。首先先判断已经扫描过的值中是否包含该值,然后由于map中保存的是该字母最右边的位置,i保存的是当前有效区间的左端点的位置,即可做出判断:如果map.get(thisChar) < i,即表示当前有效区间内并没有该值,i值不更新,将该字母的位置信息添加进map,j-i为当前有效区间的长度;如果map.get(thisChar) > i,即表示当前有效区间内有该值,将i更新为该值,同时将该字母在map中的位置信息进行更新,此时j指向的是该类字母在已扫描部分中最右边的那个字母,i指向的是该类字母在已扫描部分中从右边数第二个字母,(i, j)范围是没有重复字母的且与i和j处的字母不同,i和j位置是相同的字母,则(i, j]范围没有重复字母,且j-i即为长度。
if (map.containsKey(thisChar)) {i = Math.max(map.get(thisChar), i);}map.put(thisChar, j);无论thisChar在map中是否存在,语句都一样。不存在则加入,存在则更新。
更新完当前有效区间之后,j-i即为当前有效区间的长度,将该值与历史最大值ans进行比较,更新ans的值。
ans = Math.max(ans, j - i);如此循环下去,经过一次遍历,即可得到结果。
此题不再贴LeetCode官方提供的“参考答案”,因为并没有上边的代码容易理解。
半开半闭区间相比全开区间或者全闭区间的优势就在于,不用考虑加一或者减一的修正问题,而一旦一个地方进行修正,其他所有相关联的地方都要进行相应的修正不能遗漏,而且该加一还是该减一,稍微思路不清楚,就容易写错。
附:
LeetCode #3 题目
LeetCode #3 官方“参考答案”
- [Lesson Learn] LeetCode #3 Longest Substring Without Repeating Characters
- LeetCode 3 - Longest Substring Without Repeating Characters
- LeetCode 3: Longest Substring Without Repeating Characters
- leetcode-3:Longest Substring Without Repeating Characters
- LeetCode(3) Longest Substring Without Repeating Characters
- leetcode 3LONGEST SUBSTRING WITHOUT REPEATING CHARACTERS
- Leetcode【3】:Longest Substring Without Repeating Characters
- [leetcode 3] Longest Substring Without Repeating Characters
- [Leetcode] 3 - Longest Substring Without Repeating Characters
- LeetCode 3:《Longest Substring Without Repeating Characters》
- [leetcode 3] Longest Substring Without Repeating Characters
- [leetcode] 3 Longest Substring Without Repeating Characters
- [Leetcode]3Longest Substring Without Repeating Characters
- leetcode 3 Longest Substring Without Repeating Characters
- LeetCode #3 Longest Substring Without Repeating Characters
- leetcode-3 Longest Substring Without Repeating Characters
- LeetCode 3 Longest Substring Without Repeating Characters
- leetcode 3: Longest Substring Without Repeating Characters
- iOS三方库:xmpp下的xml数据解析及修改上传
- 一起talk C栗子吧(第一百四十七回:C语言实例--流socket通信过程)
- 如何隐藏APP名字
- http编程
- NSURLConnectionDelegate NSURLConnectionDataDelegate
- [Lesson Learn] LeetCode #3 Longest Substring Without Repeating Characters
- iOS 拨打电话三种方式总结
- PHP内核探索:新垃圾回收机制说明
- android源码settings中显示所有正在运行进程流程分析
- 寻找二维矩阵里的一个数
- protobuf的C简单的代码例子(一)
- The superclass “javax.servlet.http.HttpServlet” was not found on the Java Build Path
- android settings源代码分析(1)
- iOS开发中xcode错误和异常处理