当前位置:   article > 正文

《LeetCode刷题》3.无重复字符的最长子串(java篇)_给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

题目描述:

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

---------------------------------------------------------------------------------------------------------------

day1:耗时半小时,通过率超过18%,慢慢找寻自己数据结构方面不足,提升思维

我的代码:

  1. public static int lengthOfLongestSubstring(String s) {
  2. String longStr = "", tempStr = "";
  3. for (int i = 0; i < s.length(); i++) {
  4. char c = s.charAt(i);
  5. int num = tempStr.indexOf(c);
  6. if (num == -1){
  7. tempStr += c;
  8. }else {
  9. tempStr = tempStr.substring(num+1)+c;
  10. }
  11. if (tempStr.length() > longStr.length()){
  12. longStr = tempStr;
  13. }
  14. }
  15. return longStr.length();
  16. }

思路:通过longStr记录当前最长子串,tempStr用来存放当前子串,for循环获取字符串中每个字符,通过indexOf方法比较当前字符是否存在于tempStr中,不在当前字符串中时把当前字符附加到字符串后(这里建议用StringBuilder),在当前字符串中则把tempStr中的当前字符以后的所有字符保存为新字符串,最后通过比较tempStr和longStr的长度得到最长的子串。(ps:笔者知道用哈希会更好算,但是忘了使用哈希的方式了,就采用了最基本的思路来做)


官方思路:(哈希表)

  1. public int lengthOfLongestSubstring(String s) {
  2. // 哈希集合,记录每个字符是否出现过
  3. Set<Character> occ = new HashSet<Character>();
  4. int n = s.length();
  5. // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
  6. int rk = -1, ans = 0;
  7. for (int i = 0; i < n; ++i) {
  8. if (i != 0) {
  9. // 左指针向右移动一格,移除一个字符
  10. occ.remove(s.charAt(i - 1));
  11. }
  12. while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
  13. // 不断地移动右指针
  14. occ.add(s.charAt(rk + 1));
  15. ++rk;
  16. }
  17. // 第 i 到 rk 个字符是一个极长的无重复字符子串
  18. ans = Math.max(ans, rk - i + 1);
  19. }
  20. return ans;
  21. }

思路解析(个人思路,仅供参考):生成一个空集合,用来记录最长子串,通过for循环遍历字符串,每循环一次,删除集合中的一个字符(因为本题只要求求出最长长度,所以这里删除集合中的字符也无所谓),通过一个while循环,将字符串中的字符添加到集合中去,while判断条件为不超出字符长度,并且下一个字符不存在于集合中,rk用来表示字符串中记录的下标(这里while的判断比较关键,一边记录下标,一边判断下一个字符是否在集合中,当下一个集合已经在集合中时,需等待到上面的occ.remove删除这个字符后,才会再次添加到集合中,并记录下标),ans用来记录最长的子串,通过比较当前ans和下标减去循环数的大小来确定是否更新ans值,最后返回ans值


大佬思路:(狂吹大佬,六批六批)

  1. public int lengthOfLongestSubstring(String s) {
  2. // 记录字符上一次出现的位置
  3. int[] last = new int[128];
  4. for(int i = 0; i < 128; i++) {
  5. last[i] = -1;
  6. }
  7. int n = s.length();
  8. int res = 0;
  9. int start = 0; // 窗口开始位置
  10. for(int i = 0; i < n; i++) {
  11. int index = s.charAt(i);
  12. start = Math.max(start, last[index] + 1);
  13. res = Math.max(res, i - start + 1);
  14. last[index] = i;
  15. }
  16. return res;
  17. }

思路解析:(个人看法,仅供参考)

通过设置一个128的数组(因为ascii码只有128位,即所有字符都能存放进去),for循环用来把数组中的所有值初始化为-1(这里不初始化使用默认值0也可以,把后面值域改一下就可以),n用来表示字符串的长度,res用来记录最长子串的长度,start表示当前字符是否存在,如果存在那么下标值则记录为start,for循环字符串长度,用index获取当前字符的ascii码,(start和res这两句很妙)start的值为start和last[index]+1(这里加一是因为默认值为-1)中最大的一个,start默认值为0,last[index]+1的默认值也为0,所以只有当index第二次出现时,last[index]+1必大于0(因为last[index]=i,而i是大于等于0的数),且此时start为第二次出现的下标值(很关键),res的值为res和(i-start+1)的最大值,res默认值为0,i在一直加1,所以当start为0时,每次res会增加1,即表示为这个数没出现过,那么当前下标为几,则当前最长子串的数值就为几,当start不等于0后,因为表示为上一次出现这个字符的下标,则res要等待start轮后才能再继续增长(这里比较绕,可以多读一下理解理解)

举个例子:比如字符串:abdac,第一轮last[a] = 0,start = 0,res = 1;第二轮last[b] = 1,start=0,res=2;第三轮同理,第四轮时下标为a,当前last[a]已经有值了,为0,所以start=max(0,1)=1(这里1表示a在当前存储的字符串中的位置是第一个,也代表只空一轮,则下一轮会继续增长,如果这里是2,则表示会空两轮,则从第六轮才会继续增长),res=max(3,3-1+1)=3,第五轮last[c]=4,start=1,res=4,即最长为4,bdac

总结:自己数据结构方面思路比较浅显,常规思路也想不到很高深的,只有定个小目标,每天坚持一个及以上算法,提升思维,提高代码能力。最后,坚持写博客(虽然已经很久没写了)。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/466034
推荐阅读
相关标签
  

闽ICP备14008679号