无重复字符的最长字串

题目

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

示例

示例 1:

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

示例 2:

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

示例 3:

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

思想(滑动窗口)

滑动窗口是一种在数组或字符串上进行迭代的算法,通过维护一个子数组或子串,该子数组或子串的大小在迭代过程中可以变化。该子数组或子串的起始位置通过"滑动"进行调整,从而找到符合特定条件的解。

滑动窗口的窗口大小是动态变化的,当发现重复字符时,通过调整窗口的起始位置来实现。这样,你能够在遍历字符串的过程中找到不包含重复字符的最长子串,同时利用 `max` 变量来记录最大长度。

滑动窗口是解决一类子串或子数组问题的常见思想,通常用于解决找到不重复元素的最长子串或子数组的问题。这种方法的优势在于它可以在线性时间内解决问题,而不需要嵌套循环。

算法分析

  1. 初始化变量:`max` 用于存储最长子串的长度,`index` 用于跟踪重复字符的索引,空字符串 `str` 用于存储当前子串。

  2. 使用 for 循环遍历输入字符串 `s` 中的每个字符。

  3. 在循环内部,通过使用 `indexOf` 方法检查当前字符 `ch` 是否已经存在于当前子串 `str` 中。如果存在(`index != -1`),则表示找到了重复的字符。

  4. 如果找到重复的字符,通过比较当前子串 `str` 的长度和当前最大长度 `max` 来更新 `max` 长度。然后,通过删除从子串开头到重复字符(包括重复字符)的字符来更新子串 `str`,并将当前字符 `ch` 连接到子串中。

  5. 继续循环。

  6. 如果未找到重复字符,简单地将当前字符 `ch` 连接到子串 `str` 中。

  7. 循环结束后,比较最终子串 `str` 的长度和当前最大长度 `max`,以确保最后一个子串也被考虑在内。

  8. 返回最大长度。

java 复制代码
class Solution {
    public int lengthOfLongestSubstring(String s) {
        int max=0;
        int index=-1;
        String str="";
   
        for(int i=0;i<s.length();i++){
            char ch=s.charAt(i);
            index=str.indexOf(ch);
           if(index!=-1){
              
              max=Math.max(str.length(),max);
              str=s.substring(i-(str.length()-1-index),i+1);
            
                continue;
           }
             str=str+ch;
        }
          max=Math.max(str.length(),max);
        return max;
    }
}

运行结果

总的时间复杂度为 O(n)

击败百分之5%的对手。。。emmm被我击败南坪

算法调优

这时官方的解法,思想也是滑动窗口,来看看有什么区别:

时间复杂度是O(n^2)

它采用一个Set集合,然后左指针指向i ,右指针指向rk

rk从一个开始逐个遍历,增加不同的值加入集合,

一旦有相同的值,就说明此i指向的值的最长长度已经到了,让左指针i++,指向下一个值。

rk不用更新回去,因为从i到rk是不重复的,那从i+1到rk也肯定是不重复的,所以rk不用更新回去,set集合也不用清空。

每次左指针移动前,要更新最长的长度

Set<Character> occ = new HashSet<Character>();: 创建一个哈希集合 occ,用于记录当前窗口中字符的出现情况。

int rk = -1, ans = 0;: 定义右指针 rk 初始值为 -1,用于表示当前窗口的右边界。ans 用于记录最长子串的长度。

occ.remove(s.charAt(i - 1));: 在每次移动左指针时,从哈希集合中移除左指针所指向的字符,表示该字符不再属于当前窗口。

while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) { ... }: 在每次移动右指针时,不断地向右移动,直到遇到重复字符或者到达字符串的末尾。在移动的过程中,将新的字符加入哈希集合。

ans = Math.max(ans, rk - i + 1);: 在每一步迭代中,更新最长子串的长度。

java 复制代码
class Solution {
    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;

    }
}

时间耗时:6ms确实比我块的多,但是时间复杂度很大。懂得都懂

相关推荐
掘金安东尼1 小时前
Amazon Lambda + API Gateway 实战,无服务器架构入门
算法·架构
码流之上2 小时前
【一看就会一写就废 指间算法】设计电子表格 —— 哈希表、字符串处理
javascript·算法
快手技术4 小时前
快手提出端到端生成式搜索框架 OneSearch,让搜索“一步到位”!
算法
CoovallyAIHub1 天前
中科大DSAI Lab团队多篇论文入选ICCV 2025,推动三维视觉与泛化感知技术突破
深度学习·算法·计算机视觉
NAGNIP1 天前
Serverless 架构下的大模型框架落地实践
算法·架构
moonlifesudo1 天前
半开区间和开区间的两个二分模版
算法
moonlifesudo1 天前
300:最长递增子序列
算法
CoovallyAIHub1 天前
港大&字节重磅发布DanceGRPO:突破视觉生成RLHF瓶颈,多项任务性能提升超180%!
深度学习·算法·计算机视觉
CoovallyAIHub1 天前
英伟达ViPE重磅发布!解决3D感知难题,SLAM+深度学习完美融合(附带数据集下载地址)
深度学习·算法·计算机视觉
聚客AI2 天前
🙋‍♀️Transformer训练与推理全流程:从输入处理到输出生成
人工智能·算法·llm