最长无重复字符串[from leetCode]
题目要求:
给定一个字符串,请找出其中无重复字符的最长子字符串。
样例
例如,在"abcabcbb"
中,其无重复字符的最长子字符串是"abc"
,其长度为 3
。
对于,"bbbbb"
,其无重复字符的最长子字符串为"b"
,长度为1
。
O(n) 时间
原题地址:
LeetCode:https://leetcode.com/problems/longest-substring-without-repeating-characters/#/description
LintCode:http://www.lintcode.com/zh-cn/problem/longest-substring-without-repeating-characters/#
分析:
我第一次做这题的时候,是用一种最普通的做法——遍历两次,穷举所有的字符串,找出不重复字符串,存其长度。最后返回长度的最大值。
但是这样做的问题是时间复杂度为O(n^2),和题目要求不符。然后改进了做法,使用了HashMap。
做法一(时间复杂度O(n^2)):
public int lengthOfLongestSubstring(String s) { String res = ""; int temp = 0; ArrayList<Integer> list = new ArrayList<Integer>(); if (s == null || s.length() == 0) { } else if (s.length() == 1) { temp = 1; } else { int i = 0; while (i < s.length() - 1) { int j = 1; while (j <= s.length() - i) { if (isRepetitive(s.substring(i, i + j))) { res = s.substring(i, i + j); temp = Math.max(temp, res.length()); }else{ break; } j++; } i++; } } return temp; }
// 判断字符串是否有重复字符 public static boolean isRepetitive(String s) { boolean b = true; if (s.length() > 1) { for (int i = 1; i < s.length(); i++) { if (s.substring(0, i).contains(s.substring(i, i + 1))) { b = false; break; } } } return b; }
做法二(时间复杂度为O(n)):
public int lengthOfLongestSubstring(String s) { int temp = 0; if (s == null || s.length() == 0) { } else { Map<Character, Integer> myMap = new HashMap<Character, Integer>(); // 用以保存不重复字符串的长度 int[] strlength = new int[s.length() + 1]; // 用字符数组表示字符串 char[] str = s.toCharArray(); for (int i = 0; i < str.length; i++) { Integer lastPosOfChar = myMap.get(str[i]); if (lastPosOfChar == null) { // 更新最长无重复子串的长度 strlength[i] = i == 0 ? 1 : strlength[i - 1] + 1; // 果map添加该字符和位置 myMap.put(str[i], i); } else { int aPos = lastPosOfChar + 1; int unRepeatLen = strlength[i - 1]; int bPos = i - unRepeatLen; if (aPos >= bPos) { // 当前位置的最长无重复子串长度 strlength[i] = i - aPos + 1; } else { // 当前位置的最长无重复子串长度 strlength[i] = i - bPos + 1; } // 跟新当前字符出现的位置 myMap.put(str[i], i); } } for (int i : strlength) { temp = Math.max(temp, i); } } return temp; }
总结:Map大法好,应当努力学习一个。