剑指 Offer 48. 最长不含重复字符的子字符串(3. 无重复字符的最长子串)
题目:
思路:
【1】这道题不难,暴力破解也是可以的,但是双循环带来的开销无疑很大的。所以以空间换时间借助辅助空间,那么就要思考辅助空间怎么知道该字符已经被收录了,如数据结构中的contains函数,判断是否在数据结构里面。但是换个角度想想,每个字符其实都是有对应的ASCII码,也就是有表可看,那么其实可以构建一个固定的数组,用于标记这些,boolean也可,int也行,但是int消耗更小,比较一个8字节,一个4字节,消耗更小的内存做一样的事。
代码展示:
遍历加队列的处理方法
class Solution { public int lengthOfLongestSubstring(String s) { //创建队列 Queue<Character> queue = new LinkedList<>(); int max = 0; for (char c : s.toCharArray()) { while (queue.contains(c)) { //如果有重复的,队头出队,直到没有重复的为止 queue.poll(); } //添加到队尾 queue.add(c); //更新max max = Math.max(max, queue.size()); } return max; } }
双指针加辅助空间:
//时间2 ms击败96.65% //内存41.4 MB击败68.60% //时间复杂度为O(N),因为最优情况下是右指针走一遍,最差的情况是左右指针都走一遍,其实也就是遍历个数最多为2N //空间复杂度为O(1),因为开辟的是固定常量的辅助空间 //思路采用双指针+int数组辅助空间 //双指针是为了拉长之后计算距离 //int数组用于记录你是否扫描过该字符,因为在英文中字符是有ASCII表参考的 class Solution { public int lengthOfLongestSubstring(String s) { int[] tag = new int[256]; int left = 0, right = 0, count = 0; while (right < s.length()){ if (tag[s.charAt(right)] == 0){ tag[s.charAt(right++)] = 1; count = Math.max(count,(right - left)); }else { tag[s.charAt(left++)] = 0; } } return count; } }