无重复字符的最长子串第一名代码解释记录

leetcode第三题, 无重复字符的最长子串第一名代码解释记录
 

代码

public int lengthOfLongestSubstring(String s) {
    // 第二次提交,参考执行范例,成功(用时+内存:100%,23%)
    int ans = 0, start = 0, len = s.length();
    int[] arr = new int[128];
    for (int i = 0; i < len; i++) {
        int x = s.charAt(i);
        start = Math.max(start, arr[x]);
        ans = Math.max(ans, i - start + 1);
        arr[x] = i + 1;
    }

    return ans;
}

 

分解

 

第一部分, 去掉判断重复的逻辑

 
字符串"abcdab"
 
public int lengthOfLongestSubstring(String s) {
    // 第二次提交,参考执行范例,成功(用时+内存:100%,23%)
    int ans = 0, start = 0, len = s.length();
    int[] arr = new int[128];
    for (int i = 0; i < len; i++) {
        ans = Math.max(ans, i - start + 1);
    }

    return ans;
}
 
假如逻辑中没有判断重复的, 那么字符串长度每次循环都要计算
那么ans相当于字符串的长度
 
0
 
 

第二部分, 当前字符相关信息假如数组

 
当i=4, 再次来到a的时候, 那么子字符串的长度怎么计算
 
arr[x] = i + 1;
 
现在先把每个字符相关信息放入arr数组
当前字符的ASCII码, 就是arr数组的下标
值是当前字符的下一个字符的下标
 
这样的话, 如果有重复的字符, 那么同一个下标的值会被替换
但是到现在位置, ans还是没有被影响到, 因为新加的代码没有影响到ans和start
 
int[] arr = new int[128];
int数组, 如果不赋值, 默认值为0
 
public int lengthOfLongestSubstring(String s) {
    // 第二次提交,参考执行范例,成功(用时+内存:100%,23%)
    int ans = 0, start = 0, len = s.length();
    int[] arr = new int[128];
    for (int i = 0; i < len; i++) {
        int x = s.charAt(i);
        arr[x] = i + 1;
        
        ans = Math.max(ans, i - start + 1);
    }

    return ans;
}
 
放入arr
0
 
 

第三部分, 重复时, 更新起始位置

 
public int lengthOfLongestSubstring(String s) {
    // 第二次提交,参考执行范例,成功(用时+内存:100%,23%)
    int ans = 0, start = 0, len = s.length();
    int[] arr = new int[128];
    for (int i = 0; i < len; i++) {
        int x = s.charAt(i);
        start = Math.max(start, arr[x]);
        
        ans = Math.max(ans, i - start + 1);
        
        arr[x] = i + 1;
    }

    return ans;
}
 
start = Math.max(start, arr[x]);
如果一遇到重复的字符, 那么, start就从第一个重复的字符的下一个字符的下标开始
见下图, 如果再次遇见a, 那么start就变成b在字符串位置的下标, 1
 
0
 
所以, ans = Math.max(ans, i - start + 1);
计算的是bcda的长度, 而不是abcda的长度
 
然后再把, 字符串中, 当前a的下一个字符的下标, 放入arr数组97的下标对应的值, 覆盖值
 

小结

 
遍历了一次
用数组下标的形式和ASCII码, 存储了字符与下标的关系, 代替了HashSet或者HashMap
相对来说, 存储的内容变小, 查询也更快了一些
 

解释

 

数组通过下标计算长度

 
假如起始下标是0, 当前下标是0, 那么长度是1, 0 - 0 + 1 = 1
假如起始下标是0, 当前下标是1, 那么长度是2, 1 - 0 + 1 = 2
 
当前下标current, 起始下标start, 长度length, length = current - start + 1
 
0
 
0
 
 

ans变量

 
ans, 答案的意思, 最后返回的变量, 变量名叫答案, ans, answer
 
 

String.charAt()

 
char c = s.charAt(i);
int x = s.charAt(i);
 
string.charAt(下标索引)
返回一个char字符, 如果用int接收, 返回字符ASCII码对应的值
比如字符串 String s = "abc", s.charAt(0) 为 'a', int接收为97
 

为什么是128的int数组

 
int[] arr = new int[128];
ASCII码规定了128个字符的编码
所以, 字符的ASCII码就是数组的下标, 值是当前字符的下一个字符的下标
比如字符串, abc, a是97, 那么arr[x] = i + 1 ==> arr[97] = 1
 
0
 
0
 
 

参考文档

 
posted @ 2022-04-27 10:21  loseself  阅读(23)  评论(0编辑  收藏  举报