最长无重复子串

一、题目描述

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

示例 1:

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

示例 2:

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

示例 3:

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

二、解法

​ 可以有两种思路:

​ 1、暴力法:使用一个嵌套循环挨个匹配,时间复杂度是 O(n * n),空间复杂度是 O(n)

​ 2、滑动窗口法:当出现一个重复的时候,那么就不能使用前面已经记录的那个重复的字符了,要把它移动到它的后一位[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SldKCMXl-1584791396069)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200319230634286.png)]

​ 如果是字符 c 出现了重复,我们把指针移到 a 的下一位,那么这个子串一定还会有重复,一直到第一个 c 的下一位才可能消除重复。

提醒自己:滑动窗口不一定要一次就把指针移动到指定的位置,可以一下一下挪动!!!

2.1 暴力法

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int[] char_num;	//保存字符出现的次数
        int max = 0, temp = 0;

        for(int i = 0; i < s.length(); i++) {
            temp = 0;
            char_num = new int[128];	//ASCLL 的字符集有 128 种
            for(int j = i; j < s.length(); j++) {
                int index = s.charAt(j);
                if(char_num[index] == 0){
                    char_num[index]++;
                    temp++;
                    max = (temp > max) ? temp : max;
                } else break;
                
            }
        }

        return max;
    }
}

//官方已经说明暴力解法会超时,但他们是使用 hashset 来求解的,我用数组并没有超时

2.2滑动窗口

Ⅰ、使用 set

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int max = 0, temp = 0, i = 0, j = 0;
        int length = s.length();
        Set<Character> set = new HashSet<>();	//滑动窗口的 set 解法


        //用窗口来进行优化
        while(i < length && j < length) {
        	//窗口是一个 [start, end],则 j 是 end,i 是start
            if(!set.contains(s.charAt(j))) {
                set.add(s.charAt(j));
                j++;
                max = (j - i > max) ? j - i : max;
            } else {	//移动 start,是一步一步移动的!
                set.remove(s.charAt(i));
                i++;
            }

        }

        return max;
    }
}

Ⅱ、使用数组(桶)

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int[] char_num = new int[128];
        int length = s.length();
        int i =0, j = 0, max = 0;
        
        while(i < length && j < length) {
            if(char_num[s.charAt(j)] == 0) {	//j 指针指向的字符在数组中如果表示为 0
                char_num[s.charAt(j)]++;
                j++;
                max = (j - i > max) ? j - i : max;
                
            } else {
                char_num[s.charAt(i)] = 0;	//把 i 指针指向的字符在数组中清除掉
                i++;
            }
        }
        
        return max;
    }
}
求解最长无重复子串是一个经典的算法问题,通常可以利用滑动窗口的思想结合哈希集合(HashSet)来高效解决。以下是详细步骤及思路: ### 核心思想: 1. 使用两个指针 `left` 和 `right` 构成动态变化的窗口 `[left, right]` 来表示当前检查的字符串片段。 2. 借助一个哈希表存储字符及其最后一次出现的位置。 3. 遍历整个字符串时更新窗口大小,并记录最大长度。 #### 具体实现步骤: ```c #include <stdio.h> #include <string.h> int lengthOfLongestSubstring(char *s) { int charIndex[128]; // ASCII 字符集大小 memset(charIndex, -1, sizeof(charIndex)); // 初始化为-1 int left = 0; // 左边界初始化 int maxLength = 0; for (int right = 0; s[right] != '\0'; ++right) { // 右边从头到尾遍历字符串 if (charIndex[s[right]] >= left) { // 如果发现有重复字符并且该字符位置大于等于左边界,则调整左边界 left = charIndex[s[right]] + 1; } charIndex[s[right]] = right; // 更新或插入新字符的最新索引 int currentLength = right - left + 1; // 当前窗口长度 if (currentLength > maxLength) maxLength = currentLength; // 记录最大值 } return maxLength; } // 测试函数 void test() { char str[] = "abcabcbb"; printf("The longest substring without repeating characters is %d\n", lengthOfLongestSubstring(str)); } ``` 此段程序通过维护左右两端不断移动寻找最优结果的方式解决问题,在时间复杂度上达到了 O(n),其中 n 表示输入字符串长度。它保证每个元素最多只会被访问两次——一次由右端点触发、另一次可能因为新的非重复条件改变左端点引起。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值