longest substring问题
最长子串
滑动窗口
HashMap
1.题目描述
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given "abcabcbb", the answer is "abc", which the length is 3.
Given "bbbbb", the answer is "b", with the length of 1.
Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
题目翻译:
给出一个字符串,找出这个字符串中不重复的最长子串。
2. 解题思路
在看到这道题的时候,第一次出现的想法是外层用一个循环控制起点,内层用一个循环来扫描一个链表,当遇到重复的时候,就把在链表中已经存在的节点删除掉继续,最后得到的链表的长度一定是最长子串的长度。但是这样的方法复杂度太高,因为每一次都要重新扫描链表。
所以问题的重点是怎么减少重复查找的过程,怎样能在最短的时间内找到重复的字符,这里就会想到HashMap,能在O(1)的时间内查找。
同时在计算子串的长度的时候利用滑动窗口的思想。在计算当前字符串最长子串的的时候,划定一个边界,在这个边界内是没有重复字母出现,并且得到的长度是当前范围内最大的不重复子串的长度,当出现重复字符的时候,调整这个滑动窗口的边界,使整个窗口中不包含重复的字符。想来想去,这是动态规划的思想。
重新刷leetcode的感觉不一样,主要是觉得要想清楚每道题为什么这样做,这种方法是怎么包含特殊情况的。
3.代码
- 利用HashMap
class Solution {
public int lengthOfLongestSubstring(String s) {
int len = s.length();//取得s的长度
int max_len = 0;
HashMap<Character,Integer> m = new HashMap<Character,Integer>();//建立一个hashmap,把字符和字符的位置记录下来,字符的位置是从1开始的,这样好计算长度
for(int i = 0,j = 0;j<len;j++){
//判断hashmap中是否已经包含了 这个字母,这也是判断重复的依据,
//如果重复就要重新调整滑动窗口的边界
if(m.containsKey(s.charAt(j)))
i = Math.max(m.get(s.charAt(j)),i);//更新左边界
max_len = Math.max(max_len,j-i+1);//拿当前不重复子串的长度和已知的最大长度对比,更新max_len
m.put(s.charAt(j),j+1);//更新字符出现的位置
}
return max_len;
}
}
- 利用int数组解决
class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
int[] index = new int[128];
// 建立一个包含128个字符的数组,初始化全为0,把每个字符和int对应起来,
//每个对应位置保存的是字符在s中出现的位置。
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {
i = Math.max(index[s.charAt(j)], i);//如果这个字符还没有出现过,那么i的值就不变化,但是出现重复,就要更新i的数值
ans = Math.max(ans, j - i + 1);//更新ans的长度
index[s.charAt(j)] = j + 1;//更新字符出现的位置
}
return ans;
}
}