赞
踩
题目描述:
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
---------------------------------------------------------------------------------------------------------------
day1:耗时半小时,通过率超过18%,慢慢找寻自己数据结构方面不足,提升思维
我的代码:
- public static int lengthOfLongestSubstring(String s) {
- String longStr = "", tempStr = "";
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- int num = tempStr.indexOf(c);
- if (num == -1){
- tempStr += c;
- }else {
- tempStr = tempStr.substring(num+1)+c;
- }
- if (tempStr.length() > longStr.length()){
- longStr = tempStr;
- }
- }
- return longStr.length();
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
思路:通过longStr记录当前最长子串,tempStr用来存放当前子串,for循环获取字符串中每个字符,通过indexOf方法比较当前字符是否存在于tempStr中,不在当前字符串中时把当前字符附加到字符串后(这里建议用StringBuilder),在当前字符串中则把tempStr中的当前字符以后的所有字符保存为新字符串,最后通过比较tempStr和longStr的长度得到最长的子串。(ps:笔者知道用哈希会更好算,但是忘了使用哈希的方式了,就采用了最基本的思路来做)
官方思路:(哈希表)
- public int lengthOfLongestSubstring(String s) {
- // 哈希集合,记录每个字符是否出现过
- Set<Character> occ = new HashSet<Character>();
- int n = s.length();
- // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
- int rk = -1, ans = 0;
- for (int i = 0; i < n; ++i) {
- if (i != 0) {
- // 左指针向右移动一格,移除一个字符
- occ.remove(s.charAt(i - 1));
- }
- while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
- // 不断地移动右指针
- occ.add(s.charAt(rk + 1));
- ++rk;
- }
- // 第 i 到 rk 个字符是一个极长的无重复字符子串
- ans = Math.max(ans, rk - i + 1);
- }
- return ans;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
思路解析(个人思路,仅供参考):生成一个空集合,用来记录最长子串,通过for循环遍历字符串,每循环一次,删除集合中的一个字符(因为本题只要求求出最长长度,所以这里删除集合中的字符也无所谓),通过一个while循环,将字符串中的字符添加到集合中去,while判断条件为不超出字符长度,并且下一个字符不存在于集合中,rk用来表示字符串中记录的下标(这里while的判断比较关键,一边记录下标,一边判断下一个字符是否在集合中,当下一个集合已经在集合中时,需等待到上面的occ.remove删除这个字符后,才会再次添加到集合中,并记录下标),ans用来记录最长的子串,通过比较当前ans和下标减去循环数的大小来确定是否更新ans值,最后返回ans值
大佬思路:(狂吹大佬,六批六批)
- public int lengthOfLongestSubstring(String s) {
- // 记录字符上一次出现的位置
- int[] last = new int[128];
- for(int i = 0; i < 128; i++) {
- last[i] = -1;
- }
- int n = s.length();
-
- int res = 0;
- int start = 0; // 窗口开始位置
- for(int i = 0; i < n; i++) {
- int index = s.charAt(i);
- start = Math.max(start, last[index] + 1);
- res = Math.max(res, i - start + 1);
- last[index] = i;
- }
-
- return res;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
思路解析:(个人看法,仅供参考)
通过设置一个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
总结:自己数据结构方面思路比较浅显,常规思路也想不到很高深的,只有定个小目标,每天坚持一个及以上算法,提升思维,提高代码能力。最后,坚持写博客(虽然已经很久没写了)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。