求字符串中最长子串
这周开工第一天, 本地环境就出现了bug, 调试了一下午才解决, 今天就跟大家来简单分享一个算法吧.
/*** 求最大字符串的一个子串* @Date 4:04 PM 2019/1/21* "abcabcbb" 最大不重复长度是3* "bbbbb" 最大不重复长度是1* "pwwkew" 最大不重复长度为3**/
方法一: 暴利解法
如果你一下想不出来最优的解法, 我们先来个简单粗暴的解法
如果我们要求出最长的字符串, 那我们就把所有的子字符串列出来, 那如何才能列出出来所有的字符串呢, 那我们就需要从字符串上截取字段, 截取字段,那我们就需要一个开始start和一个结束end, 如果要取到所有的字段, 那我们0<= start < len(s), 那 start < end < len(s), 那这个就需要连个嵌套循环.
为了求出所有子串中不重复的最长字符串, 我们可以使用一个集合来记录元素, 遍历所有的子串, 如果中间有元素重复, 那就返回最长的不重复的长度
pulibc class Solution {public static int lengthOfLongestSubstring(String s) {if (s == null || s.length() == 0) {return 0;}int n = s.length();int result = 0;for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {result = allUnique(s, i, j, result);}}return result;}public static int allUnique(String s, int start, int end, int result) {Setset = new HashSet<>(); int len = 0;for (int i = start; i < end; i++) {Character ch = s.charAt(i);if (set.contains(ch)) {return Math.max(len, end - start);}set.add(ch);}return len;}}
复杂度分析
时间复杂度:O(n^3)O(n3) 。
要验证索引范围在 [i, j)[i,j) 内的字符是否都是唯一的,我们需要检查该范围中的所有字符。因此,它将花费 O(j - i)O(j−i) 的时间。
空间复杂度:O(min(n, m))O(min(n,m)),我们需要 O(k)O(k) 的空间来检查子字符串中是否有重复字符,其中 kk 表示 Set 的大小。而 Set 的大小取决于字符串 nn 的大小以及字符集/字母 mm 的大小。
方法二: 最优解
我们来拿一个字符串举例:
abcdcbcbb在子字符串[i, j]中, 当第二个c出现的时候, (即j = "c"), 我们在循环中, 现在是abcd, j不管怎么加, 其实都是没有意义的, 因为已经重复了, 这个时候, 其实我们应该做i + 1; 但是你发现, i其实加1也是没用的, i其实可以直接移动到第一个d的地方就行了,就是第一重复的c的位置+ 1, 因为bcdc这个是没有必要的, i直接可以调到第一个c对应的下标 + 1开始就好了, 这样的效率是最好的, 下面我们用hashMap来操作, 用hashmap来记录, key记录字符, value记录字符的下标.
// HashMap的做法public static int lengthOfLongesSubstring(String s) {if (s == null || s.length() == 0) {return 0;}HashMapmap = new HashMap<>(); int res = 0;// 只需要移动一个j, i是左边移动的下标, 如果有重复, 直接赋值过去, 如果一直没有重复,就是0for (int j = 0, i = 0; j < s.length(); j ++) {if (map.containsKey(s.charAt(j))) {i = Math.max(i, map.get(s.charAt(j)) + 1);}// 记录字符串, key为字符, value为下标map.put(s.charAt(j), j);// 计算两个子字符传的距离,res = Math.max(res, j - i + 1);}return res;}
