首页 > 试题广场 >

最长不含重复字符的子字符串

[编程题]最长不含重复字符的子字符串
  • 热度指数:47554 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
数据范围:

示例1

输入

"abcabcbb"

输出

3

说明

因为无重复字符的最长子串是"abc",所以其长度为 3。    
示例2

输入

"bbbbb"

输出

1

说明

因为无重复字符的最长子串是"b",所以其长度为 1。    
示例3

输入

"pwwkew"

输出

3

说明

因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是子串的长度,"pwke" 是一个子序列,不是子串。    
from queue import deque
class Solution:
    def lengthOfLongestSubstring(self , s: str) -> int:
        if not s:
            return 0
        q = deque()
        # 初始无重复最长子串长度
        max_substr = 0
        for i in s:
            if i not in q:
                q.append(i)
                # 更新max_substr
                if len(q) > max_substr:
                    max_substr = len(q)
            else:
                # 从队列中弹出重复元素i以及i之前的所有元素
                while i in q:
                    q.popleft()
                # 弹出之后将i入队
                q.append(i)
        return max_substr

发表于 2022-07-26 00:32:22 回复(0)
import java.util.*;



//https://zhuanlan.zhihu.com/p/80538556
//看这上的题解看了半天没有看懂,最后看了上面这个文章的讲解,稍微懂了
//dp
//dp【i】 代表以i为最后一个元素的最长子字符串的大小
//如果该元素没有出现过,那么当前大小就应该为上一个元素的大小+1,即currentlen+1
//如果该元素出现过,那么就计算当前元素距离上一次最近一次出现该元素的位置的距离d
//如果d大于currentlen,证明它的最近的相同元素不在它上一个元素为最后一个元素的子序列中,所以currentlen++,即把该元素和以上一个元素为最后元素的子字符串连接
//如果d小于等于currentlen,就证明它最近的相同元素在以它上一个元素为最后元素的子字符串
//中,所以以当前元素为最后元素的子字符串的起始位置应该是它上一个相同元素的后面一个元素
//以这个元素为起始点,该元素为终点,算出来的长度就等于之前算出来的d,所以currentlen=d

//当把所有情况的结果计算出来之后,比较currentlen和maxlen的值,如果比maxlen的值大,就更新maxlen,否则继续遍历

//为什么这个解答没有dp数组呢,因为如果有dp数组的话,最后需要遍历一遍dp数组元素找到dp数组的
//最大值,而该解答中,currentlen代表当前dp数组对应的位置的值,用Maxlen不断比较,在遍历
//过程得到了maxlen,所以没有dp数组(算是一种优化吧)

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param s string字符串 
     * @return int整型
     */
    public int lengthOfLongestSubstring (String s) {
        // write code here
        if (s.length() == 0 && s.equals(" ")) return 0;
        int currentLen = 0;
        int maxLen = 0;
        char[] chars = s.toCharArray();
        HashMap<Character, Integer> map = new HashMap<>();
        for (int i = 0; i < chars.length; i++) {
            if (map.containsKey(chars[i])){
                int d=i-map.get(chars[i]);
                if (d>currentLen)
                    currentLen++;
                else
                    currentLen=d;
            }else {
                currentLen++;
            }
            if (currentLen>maxLen)
                maxLen=currentLen;
            map.put(chars[i],i);
        }
        return maxLen;
    }
}






发表于 2022-03-18 23:13:09 回复(0)
import java.util.*;
public class Solution {
    public int lengthOfLongestSubstring (String s) {
        // 定义最大长度
        int max=0;
        // 定义start指针,初始值为-1是考虑到length=1的输入
        int start=-1;
        // 定义hashmap,key为字符,value为最后一次出现的位置
        HashMap<Character,Integer> map = new HashMap<>();
        // 遍历字符串
        for(int i=0;i<s.length();i++){
            char cur = s.charAt(i);
            // 只有当重复元素出现在start后方时,才更新start(避免start向前更新)
            if(map.containsKey(cur) && map.get(cur) > start){
                start = map.get(cur);
            }
            // 实时更新map
            map.put(cur,i);
            // 更新最大长度
            max = Math.max(max, i-start);
        }
        // 返回最大长度
        return max;
    }
}

发表于 2022-01-04 23:58:16 回复(1)
双指针解法,耗时短,供参考
class Solution:
    def lengthOfLongestSubstring(self , s: str) -> int:
        cnt = 1
        i = 0
        k = 1
        
        while i < len(s)-1 and k < len(s):
            if s[k] not in s[i: k]:
                cnt = max(cnt, len(s[i: k+1]))
                k += 1
            elif s[k] in s[i: k]:
                i += 1
                k = i+1
        
        return cnt


发表于 2022-03-28 11:02:43 回复(0)
public int lengthOfLongestSubstring(String s) {
        int b = 0;
        int key = 0;
        List<Character> res = new ArrayList<>();
        while (b != s.length()) {
            if (res.contains(s.charAt(b))){
                List<Character> code = new ArrayList<>();
                for (Character re : res) {
                    if (re == s.charAt(b)) {
                        code.add(re);
                        break;
                    } else code.add(re);
                }
                res.removeAll(code);
                res.add(s.charAt(b));
                b++;
            }else {
                res.add(s.charAt(b));
                b++;
            }
            key = Math.max(key,res.size());
        }
        return key;
    }

发表于 2021-11-10 16:19:51 回复(0)
正常思维的小白解法:双指针
  public int lengthOfLongestSubstring(String s) {
        // write code here
        // 典型的额双指针问题
        int len = s.length();
        if(len <= 1)
            return s.length();
        int maxLen = 0;
        ArrayList<Character> charList = new ArrayList<>();
        for (int i = 0; i < len; i++) {
            for (int j = i; j < len; j++) {
                char c = s.charAt(j);
                if(!charList.contains(c))
                    charList.add(c);
                else {
                    maxLen = Math.max(maxLen, charList.size());
                    charList.clear();
                    break;
                }
            }
        }
        return maxLen;
    }

大神解法,滑动窗口 + HASH 编码(ASCII码表),时间复杂度直接降低至 O(n)
 public int lengthOfLongestSubstring(String s) {
        // write code here
        int len = 0;
        int[] hash = new int[256];
        int j = 0;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            hash[c]++; // 初始化时,每个元素对应 ASCII 的数字的值为 1
            while (hash[c] > 1) { // 发现有重复的字符串
                // 寻找重复元素的下一个下标,退出就是为 j
                hash[s.charAt(j)] --;
                j++;
            }
            // 当前的最大值
            len = Math.max(i - j + 1, len);
            // 继续往下寻找...
        }
        return len;
    }


发表于 2024-04-26 16:36:44 回复(0)
package main

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 *
 * @param s string字符串
 * @return int整型
 */
func lengthOfLongestSubstring(s string) int {
	// write code here
	var char2Index = make(map[int32]int, len(s))
	var maxSub = 0
	var currentSubLen = 0

	var getMax = func(a, b int) int {
		if a > b {
			return a
		}
		return b
	}
	var left int
	for index, char := range s {
		if charIdx, exist := char2Index[char]; exist {
			if charIdx < left {
				currentSubLen += 1
			} else {
				maxSub = getMax(currentSubLen, maxSub)
				currentSubLen = index - charIdx
				left = charIdx + 1
			}
		} else {
			currentSubLen += 1
		}
		char2Index[char] = index
	}
	maxSub = getMax(currentSubLen, maxSub)
	return maxSub
}



编辑于 2024-04-21 16:46:53 回复(0)
function lengthOfLongestSubstring(s) {
    // write code here
    if (!s) return 0;
    let dic = new Map();
    let dp = [1];
    let m = 1;
    dic.set(s[0], 0);
    for (i = 1; i < s.length; i++) {
        let j = dic.get(s[i]);
        dp[i] = j === undefined || dp[i - 1] < i - j ? dp[i - 1] + 1 : i - j;
        dic.set(s[i], i);
        m = Math.max(m, dp[i]);
    }
    return m;
}

发表于 2023-03-14 22:30:53 回复(0)
C语言做法 简单移动 用数组代替哈希表 不过思想是类似的
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param s string字符串 
 * @return int整型
 */
#include <string.h>
#define max(x,y)((x)>(y)?(x):(y))

int lengthOfLongestSubstring(char* s ) {
    // write code here
    int len = strlen(s);
    //appear数组类似于哈希表 appear[s[i]]存放每个字符出现过的次数
    //s[i]是字符 如abcab s[0]==s[3]=='a'
    //不难发现 appear[s[0]]==appear[s[3]]==appear['a']
    int appear[10000] = {0};
    //ans保存最大长度
    int ans = 0;
    //i和j是不含重复字符的子字符串的首尾指针
    for (int i=0, j=0; j<len; j++) {
        //尾指针j开始扫描 字符出现就次数+1
        appear[s[j]]++;
        //存在重复出现的字符
        //如abcab appear[s[0]]==appear[s[3]]==appear[a]
        while (i<j && appear[s[j]]>1) {
            //重复出现的字符 出现次数-1
            appear[s[i]]--;
            //首指针i向后移动一位
            i++;
        }
        //ans取ans和每次子串长度的最大值
        ans = max(ans, j-i+1);
    }
    return ans;
}


发表于 2023-03-04 09:37:03 回复(0)
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param s string字符串 
     * @return int整型
     */
    int lengthOfLongestSubstring(string s) {
        // 时间复杂度O(N),空间复杂度O(N)
        unordered_set<char> hash;
        int left = 0, right = 0, res = 0;
        while (right < s.size()) {
            while (hash.find(s[right]) != hash.end()) {
                hash.erase(s[left]);
                ++left;
            }
            hash.insert(s[right]);
            ++right;
            res = max(res, right - left);
        }
        return res;
    }
};

发表于 2022-11-11 14:39:31 回复(0)
public int lengthOfLongestSubstring(String s) {
        // 记录字符上一次出现的位置
        int[] last = new int[128];
        for (int i = 0; i < 128; i++) last[i] = -1;

        int start = 0;
        int res = 0;
        for (int i = 0; i < s.length(); 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;
    }
发表于 2022-08-17 18:04:05 回复(0)
function lengthOfLongestSubstring( s ) {
    if(s.length===0)return 0;
    if(s.length===1)return 1;
    let max=0;
    let left=0;
    let right=1;
    let str=s[0];
    for(let i=1;i<s.length;i++){
        let index=str.indexOf(s[i])
        if(index!==-1)left=left+index+1;
        right=i+1;
        str=s.slice(left,right);
        max=Math.max(max,str.length);
    }
    return max;
}
发表于 2022-07-24 17:17:52 回复(0)
 public int lengthOfLongestSubstring (String s) {
        // write code here
        HashMap<Character, Integer> map = new HashMap<>();
        int res = 0;
        int l = 0;
        for (int i = 0; i < s.length(); i++) {
            if (map.containsKey(s.charAt(i))) {
                map.put(s.charAt(i), map.get(s.charAt(i)) + 1);
            } else {
                map.put(s.charAt(i), 1);
            }
            //重复了就一直移动左边界 直到不重复
            while (map.get(s.charAt(i)) > 1) {
                map.put(s.charAt(l), map.get(s.charAt(l)) - 1);
                l++;
            }
            res = Math.max(res, i - l + 1);
        }
        return res;
    }
}

发表于 2022-06-14 15:16:32 回复(0)
 public int lengthOfLongestSubstring (String s) {
     int max=0;
        int start=0;
        char[] chars = s.toCharArray();
        Set<Character> set = new HashSet<>();
        for (int end = 0; end < chars.length; end++) {
            while (set.contains(chars[end])){
                set.remove(chars[start]);
                start++;
            }
            set.add(chars[end]);
            max=Math.max(max,end-start+1);
        }
        return max;
    }

发表于 2022-02-19 10:33:40 回复(0)
使用双指针指不包含重复字符的区间。
如果当前这个字符在双指针区间中出现过,移动左指针,直到将这个字符移除为止。
使用max来记录最大长度。
public int lengthOfLongestSubstring (String s) {
    // write code here
    int max = 0;
    boolean[] sign = new boolean[256];
    int left = 0, right = 0;
    while (right < s.length()) {
        char ch = s.charAt(right);
        if (sign[ch]) {
            while (s.charAt(left) != ch) {
                sign[s.charAt(left ++)] = false;
            }
            sign[s.charAt(left ++)] = false;
        }
        sign[ch] = true;
        right ++;
        max = Math.max(max, right - left);
    }
    return max;
}


发表于 2022-01-06 00:31:29 回复(0)
public int lengthOfLongestSubstring (String s) {
        // dp[i]表示以i-1处字符结尾的最大len
        int[] dp = new int[s.length() + 1];
        // HashMap存储字符出现的位置,char - idx
        Map<Character, Integer> map = new HashMap();
        int maxLen = 0;
        for(int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (!map.containsKey(ch)) {
                dp[i + 1] = dp[i] + 1;
            } else { // abaa
                dp[i + 1] = Math.min(i - map.get(ch), dp[i] + 1);
            }
            map.put(ch, i);
            maxLen = Math.max(maxLen, dp[i + 1]);
        }
        
        return maxLen;
    }
发表于 2021-11-07 14:48:54 回复(1)
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 *
 * @param s string字符串
 * @return int整型
 */
#include <string.h>
int lengthOfLongestSubstring(char* s ) {
    // write code here
    int sample[129] = {0}, maxlen = 0, templen = 0, k = 1;
    for (int i = 0; i <= strlen(s); i++) {
        if (sample[s[i]] == 0 && i != strlen(s)) {
            sample[s[i]] = k++;
        } else {
            if (maxlen < k - 1)maxlen = k - 1;
            k -= sample[s[i]];
            templen = sample[s[i]];
            for (int j = 0; j < 129; j++) {
                if (sample[j] > 0)sample[j] -= templen;
                if (sample[j] < 0)sample[j] = 0;
            }
            sample[s[i]] = k++;
        }
    }

    return maxlen;
}
发表于 2024-04-28 09:43:48 回复(0)
    public int lengthOfLongestSubstring (String s) {
        // write code here
        HashMap<Character, Integer> mp = new HashMap<>();
        int res = 0;
        if(s.length() <= 1){
            return s.length();
        }
        int left = 0, right = 0;
        while(right < s.length()){
            if(mp.containsKey(s.charAt(right))){
                mp.put(s.charAt(right), mp.get(s.charAt(right)) + 1);
            } else {
                mp.put(s.charAt(right), 1);
            }
            if(mp.get(s.charAt(right)) > 1){
                // 因为每次subring提取出来的字符串索引值都是从0开始,
                // 所以需要加上左边界left,才能表示s.charAT(right)字符在s中的索引位置
                int index = s.substring(left, right).indexOf(s.charAt(right)) + left;
                mp.put(s.charAt(right), mp.get(s.charAt(right))-1);  // 保证字符left,right区间的字符只出现一次。如果不做这一步,假设abcac,此时a重复了,在区间[0,4]之间,a出现两次,移动left到1时,a在[1,4]之间只出现一次,如果不-1,则还是两次,就会判定错误。
                res = Math.max(res, right - left);
                left = index + 1;
            }
            right++;
        }
        // 会出现一种情况,right一直到结束,都没有重复,此时就无法进入if条件判断长度
        // 需要在循环结束时,判断最后一个是否重复? 重复,说明已经进入循环内的if判断过
        // 不重复,说明还需要再进行判断一次,判断res 与 当前right - left 长度
        return mp.get(s.charAt(right-1)) == 1 ? res = Math.max(res, right - left) : res;

发表于 2024-04-25 20:02:36 回复(0)
无语得要死,字符输入范围又不给,示例全是字母,还以为全是字母。
编辑于 2024-04-15 10:19:18 回复(0)
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # write code here
        dp = [1]
        hashmap = {s[0]: 0}

        for i in range(1, len(s)):
            if s[i] not in hashmap:  # 最长子串+1
                dp.append(dp[i - 1] + 1)
                hashmap[s[i]] = i
            else:
                index = hashmap[s[i]]
                hashmap[s[i]] = i
                dp.append(min(i - index, dp[i - 1] + 1))
        return max(dp)

编辑于 2024-04-08 11:27:03 回复(1)