class Solution
{
public:
int lengthOfLongestSubstring(String s)
{
Set<Character> hashSet = new HashSet<>(); //创建一个Set容器,HashSet是一个算法
//Set集合保证元素唯一
//右指针,不断添加
int right = -1;
int ans = 0;
//i可以看作左指针,从左边移除
for (int i = 0; i < s.length(); i++)
{
//i为0时HashSet为空不用移除
if (i != 0)
{
hashSet.remove(s.charAt(i - 1));
}
//字符串的下一位不与HashSet里面元素相同,添加进hashSet,右指针向右移动。
//遇到相同元素,结束本次小循环,进大循环(移除下标i的元素,左指针+1(i+1)。
//即HashSet集合中第一位元素变成下标为i+1的元素
while (right + 1 < s.length() && !hashSet.contains(s.charAt(right + 1)))
{
hashSet.add(s.charAt(right + 1));
right++;
}
//遇到有重复元素,则记录最大长度
ans = Math.max(ans, right - i + 1);
}
return ans;
}
};
上面的代码利用了HashSet中的hashset方法,其大概的意思是就是利用两个指针计算字符串不重复的最大值。
示例:字符串abcabcbb ()里为HashSet集合里面的元素。
(a)bcabcbb (ab)cabcbb (abc)abcbb i=0时,不断添加,当right=2时,charAt(right+1) 为HashSet里重复元素。
a(bc)abcbb a(bca)bcbb i=1时,移除重复元素charAt(i-1),再次不断添加。当right=3时,charAt(right+1) 为HashSet里重复元素。
ab(ca)bcbb ab(cab)cbb i=2时
abc(ab)cbb abc(abc)bb i=3时
abca(bc)bb i=4时,hashSet里元素依旧存在下一位元素charAt(right+1) right为5 相同,结束本次小循环,开始新一轮大循环。
abcab(c)bb abcab(cb)b i=5时
abcabc(b)b i=6时
abcabcb()b abcabcb(b) i=7时
HashSet保证元素唯一性的原理:
1、HashSet原理:
我们使用Set集合都是需要去掉重复元素,如果在存储的时候逐个使用equals方法比较,效率低,哈希算法提高去重的效率,降低使用equals方法的次数。
当HashSet调add方法存储对象时,先调用对象的hashCode方法得到一个hash值,然后在集合中查找是否有相同哈希值的对象:
如果没有hash值相同的对象,就直接存入集合;
如果有hash值相同的对象,就和hash值相同的对象逐个进行equals比较,比较结果是false就存入集合,如果是true就不存。
2、将自定义类型的对象存入HashSet去重:
类中必须重写hashCode和equals方法。
hashCode方法:属性值相同的对象返回值必须相同。
equals方法:属性值相同返回true,属性值不相同返回false。返回false时应该存储。
C++方案
class Solution
{
public:
int lengthOfLongestSubstring(string s)
{
// 哈希集合,记录每个字符是否出现过
//先创建一个unordered_set的容器,存储字符串
unordered_set<char> occ;
int n = s.size();
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
int rk = -1, ans = 0;
// 枚举左指针的位置,初始值隐性地表示为 -1
for (int i = 0; i < n; ++i)
{
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.erase(s[i - 1]);
}
while (rk + 1 < n && !occ.count(s[rk + 1]))
{
// 不断地移动右指针
occ.insert(s[rk + 1]);
++rk;
}
// 第 i 到 rk 个字符是一个极长的无重复字符子串
ans = max(ans, rk - i + 1);
}
return ans;
}
};