• 无重复字符的最长子串 - 力扣(LeetCode)


    3. 无重复字符的最长子串 - 力扣(LeetCode)

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

    示例 1:

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

    示例 2:

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

    示例 3:

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

    1、将字符串分为两个集合,第一个集合是目前最长串,第二个集合是需要加入最长串的字符

    每次从第二个集合拿一个字符串,判读是否第一个集合存在该字符串

    开始     NULL      S{abcabcbb}    

                 {a}   {bcabcbb}    //加入第一个结合

                {ab}   {cabcbb}   

               {abc}  {abcbb}

               {bca}   {bcbb}     //重复了,需要调整第一个字符串

    ..... 直到第二个字符串为空

    1. public int lengthOfLongestSubstring(String s) {
    2. if(s==null || s.length()==0) return 0;
    3. int len = s.length();
    4. int left=0,right=0,max=1;
    5. for(int i=1;i
    6. boolean find = false;
    7. for(int j=left;j<=right;j++){
    8. if(s.charAt(j)==s.charAt(i)){
    9. left=j+1;
    10. right=i;
    11. find=true;
    12. if(right-left+1>max)
    13. max=right-left+1;
    14. break;
    15. }
    16. }
    17. if(find == false){
    18. right=i;
    19. if(right-left+1>max)
    20. max=right-left+1;
    21. }
    22. }
    23. return max;
    24. }

    将for 循环替换为java 字符串函数

    1. public static int lengthOfLongestSubstring(String s) {
    2. if(s==null || s.length()==0) return 0;
    3. int len = s.length();
    4. int left=0,right=0,max=1;
    5. for(int i=1;i
    6. String src=s.subSequence(left,right+1).toString();
    7. int offset = src.indexOf(s.charAt(i));
    8. if(offset != -1){
    9. left+=offset+1;
    10. right=i;
    11. if(right-left+1>max)
    12. max=right-left+1;
    13. continue;
    14. }
    15. right = i;
    16. if (right - left + 1 > max)
    17. max = right - left + 1;
    18. }
    19. return max;
    20. }

    方法一:滑动窗口
    思路和算法

    我们先用一个例子考虑如何在较优的时间复杂度内通过本题。

    我们不妨以示例一中的字符串 abcabcbb\texttt{abcabcbb}abcabcbb 为例,找出从每一个字符开始的,不包含重复字符的最长子串,那么其中最长的那个字符串即为答案。对于示例一中的字符串,我们列举出这些结果,其中括号中表示选中的字符以及最长的字符串:

    以 (a)bcabcbb\texttt{(a)bcabcbb}(a)bcabcbb 开始的最长字符串为 (abc)abcbb\texttt{(abc)abcbb}(abc)abcbb;
    以 a(b)cabcbb\texttt{a(b)cabcbb}a(b)cabcbb 开始的最长字符串为 a(bca)bcbb\texttt{a(bca)bcbb}a(bca)bcbb;
    以 ab(c)abcbb\texttt{ab(c)abcbb}ab(c)abcbb 开始的最长字符串为 ab(cab)cbb\texttt{ab(cab)cbb}ab(cab)cbb;
    以 abc(a)bcbb\texttt{abc(a)bcbb}abc(a)bcbb 开始的最长字符串为 abc(abc)bb\texttt{abc(abc)bb}abc(abc)bb;
    以 abca(b)cbb\texttt{abca(b)cbb}abca(b)cbb 开始的最长字符串为 abca(bc)bb\texttt{abca(bc)bb}abca(bc)bb;
    以 abcab(c)bb\texttt{abcab(c)bb}abcab(c)bb 开始的最长字符串为 abcab(cb)b\texttt{abcab(cb)b}abcab(cb)b;
    以 abcabc(b)b\texttt{abcabc(b)b}abcabc(b)b 开始的最长字符串为 abcabc(b)b\texttt{abcabc(b)b}abcabc(b)b;
    以 abcabcb(b)\texttt{abcabcb(b)}abcabcb(b) 开始的最长字符串为 abcabcb(b)\texttt{abcabcb(b)}abcabcb(b)。
    发现了什么?如果我们依次递增地枚举子串的起始位置,那么子串的结束位置也是递增的!这里的原因在于,假设我们选择字符串中的第 kkk 个字符作为起始位置,并且得到了不包含重复字符的最长子串的结束位置为 rkr_kr 
    k

     。那么当我们选择第 k+1k+1k+1 个字符作为起始位置时,首先从 k+1k+1k+1 到 rkr_kr 
    k

      的字符显然是不重复的,并且由于少了原本的第 kkk 个字符,我们可以尝试继续增大 rkr_kr 
    k

     ,直到右侧出现了重复字符为止。

    这样一来,我们就可以使用「滑动窗口」来解决这个问题了:

    我们使用两个指针表示字符串中的某个子串(或窗口)的左右边界,其中左指针代表着上文中「枚举子串的起始位置」,而右指针即为上文中的 rkr_kr 
    k

     ;

    在每一步的操作中,我们会将左指针向右移动一格,表示 我们开始枚举下一个字符作为起始位置,然后我们可以不断地向右移动右指针,但需要保证这两个指针对应的子串中没有重复的字符。在移动结束后,这个子串就对应着 以左指针开始的,不包含重复字符的最长子串。我们记录下这个子串的长度;

    在枚举结束后,我们找到的最长的子串的长度即为答案。

    判断重复字符

    在上面的流程中,我们还需要使用一种数据结构来判断 是否有重复的字符,常用的数据结构为哈希集合(即 C++ 中的 std::unordered_set,Java 中的 HashSet,Python 中的 set, JavaScript 中的 Set)。在左指针向右移动的时候,我们从哈希集合中移除一个字符,在右指针向右移动的时候,我们往哈希集合中添加一个字符。

    至此,我们就完美解决了本题。

    作者:力扣官方题解
    链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    1. class Solution {
    2. public int lengthOfLongestSubstring(String s) {
    3. // 哈希集合,记录每个字符是否出现过
    4. Set occ = new HashSet();
    5. int n = s.length();
    6. // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
    7. int rk = -1, ans = 0;
    8. for (int i = 0; i < n; ++i) {
    9. if (i != 0) {
    10. // 左指针向右移动一格,移除一个字符
    11. occ.remove(s.charAt(i - 1));
    12. }
    13. while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
    14. // 不断地移动右指针
    15. occ.add(s.charAt(rk + 1));
    16. ++rk;
    17. }
    18. // 第 i 到 rk 个字符是一个极长的无重复字符子串
    19. ans = Math.max(ans, rk - i + 1);
    20. }
    21. return ans;
    22. }
    23. }
    24. 作者:力扣官方题解
    25. 链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/
    26. 来源:力扣(LeetCode)
    27. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    1024程序员节:庆祝编程的魅力
    BI国产化,必须要弄懂的2个关键
    解决VSCode中Debug和运行路径不一致的
    中国第一口粮大国科技领域的超级阵营 国稻种芯百团计划行动
    期望+拆贡献+充斥:CF1349D
    基于HFSS的线阵综合分析
    企业应用架构研究系列一:业务拆分
    基于Java毕业设计二手手机回收平台系统源码+系统+mysql+lw文档+部署软件
    Spring的三种依赖注入的方式
    【Redis】SortedSet类型
  • 原文地址:https://blog.csdn.net/lei7143/article/details/133186909