1、解题思路–辅助数组–ASCII
用一个数组存放字符串出现过的位置index。
开始遍历字符串:
若没出现过字符,tmp长度➕1;
若发现出现过该字符串,tmp重计:
若上次出现的位置较远,当前字符位置与上一次出现的位置相减大于当前tmp长度,则不管它,tmp➕1;
若上次出现的位置较近,当前字符位置与上一次出现的位置相减小于当前tmp长度,则tmp长度按照位置差重新计数;
每次都更新位置index。
时间复杂度O(n)
来源:力扣(LeetCode):
思路来源链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/cyu-yan-jian-dan-jie-fa-by-pang-san-jin-3/
package com.company;
public class leetCode {
public static void main(String[] args) {
Solution solution = new Solution();
int i = solution.find1("abcasdc");
System.out.println(i);
}
}
package com.company;
import java.util.HashMap;
import java.util.Map;
public class Solution {
//方法一 hashmap
public int find(String s) {
Map<Character, Integer> reMap = new HashMap();
//最长子串
int max = 0;
//慢指针
int left = 0;
//快指针
int i = 0;
while (i < s.length()) {
//如果存在重复的键时,需要将慢指针向左边移动
//虽然左边的位置有移动 -- 不需要将重复的值进行修改成0
if (reMap.containsKey(s.charAt(i))) {
if (reMap.get(s.charAt(i)) >= left) {
left = reMap.get(s.charAt(i)) + 1;
}
}
//快指针的不存在于哈希表的情况
//如果原来哈希表中已经存在相同的键值时候,将会取代旧的值(如果原来的值存在就取代原来的值)
reMap.put(s.charAt(i), i);
i++;
//统计最大字符子串
if ((i - left) > max) {
max = (i - left);
}
}
return max;
}
//ASCII辅助数组的简单解法
public int find1(String s) {
int i;
int ret = 0;
int tmp = 0;
char[] stoarr = s.toCharArray();
int[] arr = new int[128];
for (i = 0; i < stoarr.length; i++) {
System.out.println(stoarr[i]);
int index = (int) stoarr[i];
//如果没有重复的字符
if (arr[index] == 0) {
++tmp;
// arr[index] =1;
System.out.println("看那些是不重复的部分" + " " + i);
} else {
//如果已经在数组中存在的处理
//需要判断重复的字符是在此时字符串的的开始的位置之前
//字符串的长度更新之后增加了 比 原来保存的最大值的个数时 需要及时的更新
ret = (ret >= tmp) ? ret : tmp;
System.out.println("ret" + ret);
//需要滑动次窗口的左侧同时 更新此时的最长子串
tmp = (tmp >= i + 1 - arr[index]) ? i + 1 - arr[index] : tmp;
System.out.println("+" + (i + 1 - arr[index]) + tmp);
}
//高明之处是记录已经遍历的字符的最后 -- 是第几个遍历的
//此处不能从0开始是因为 等于0 如果第一个元素重复出现 -- 不能识别字符已经存在
// arr[index] = i ;
arr[index] = i + 1;//第一次在这里花费的时间比较多
}
ret = (ret >= tmp) ? ret : tmp;
return ret;
}
}
2、结合简单的例子 – abcasdc–分析算法流程–发现问题
arr[index] = i+k (k !=0) 才行。