Sword refers to offer (C++)-JZ48: the longest substring without repeated characters (algorithm - dynamic programming)

Author: Zhai Tianbao Steven
Copyright statement: The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source

Title description:

Please find the longest substring that does not contain repeated characters from the string, and calculate the length of the longest substring.

data range:

 s.length≤40000 s.length≤40000

Example:

enter:

"abcabcbb"

return value:

3

illustrate:

Since the longest substring without repeating characters is "abc", its length is 3.

Problem-solving ideas:

This question is a classic question of dynamic programming. There are two ways to solve the problem.

Idea 1: Sliding window

  1. Design a sliding window, the right boundary of the window goes first, and use the hash table to count the number of occurrences of characters.
  2. When repeated characters appear, the left border starts to shrink the window until the repeated characters disappear.
  3. Just keep refreshing the most value.

Idea 2: Dynamic programming

  1. Use a hash table to store the subscript of the last occurrence of the character; use a vector whose length is 1 larger than the string to store the length of the substring that can be maintained until the i-th character, such as v[0]=0, v [1]=1, v[2] may be 1 or 2.
  2. Perform traversal. Use the hash table to judge whether the current character is a repeated character. If it is not a repeated character, then add 1 to the length of the previous substring; if there is a repeated character, the distance between the character and the repeated character is im[s[i] ], but if there are other repeated characters between the two, you need to consider such a situation. It can be considered that in the substring after the repeated character, the character has not appeared before, then there is v[i]+1; so, Compare v[i]+1 and im[s[i]] whichever is smaller, because the small substring is not disconnected, and can continue to be connected later, while the disconnected substring is large in length, but it cannot continue to increase .
  3. Continuously update the latest character subscript and the maximum substring length.

Test code:

Idea 1: Sliding window

class Solution {
public:
    // 最长子串
    int lengthOfLongestSubstring(string s) {
        // 定义哈希表
        unordered_map<char, int> m;
        // 滑动窗口遍历
        int result = 0;
        for(int left = 0, right = 0; right < s.length(); ++right){
            // 窗口右边界先行,统计字符出现次数
            m[s[right]]++;
            // 当出现重复字符,窗口左边界右移缩小窗口直到重复字符消失
            while(m[s[right]] > 1){
                m[s[left]]--;
                left++;
            }
            // 持续刷新子串最大长度
            result = max(result, right - left + 1);
        }
        return result;
    }
};

Idea 2: Dynamic programming

class Solution {
public:
    // 最长子串
    int lengthOfLongestSubstring(string s) {
        // 定义哈希表,存放的是字符出现的位置下标
        unordered_map<char, int> m;
        int result = 0;
        // v[i]表示截止到i个字符时,能继续维持的子串长度
        // 所以v[0]=0,v[1]=1
        vector<int> v = vector<int>(s.length() + 1, 0);
        // i是字符串中字符下标
        for(int i = 0; i < s.length(); ++i){
            // 当哈希表中没发现重复字符,那就在前面最长子串长度基础上+1
            if(m.find(s[i]) == m.end())
                v[i + 1] = v[i] + 1;
            // 若出现了重复字符,该字符与其重复字符的距离为i-m[s[i]]
            // 但如果两者之间有别的重复字符,那要考虑这类情况
            // 可以认为在其重复字符之后的子串中,该字符未出现过,则有v[i]+1
            // 所以v[i]+1和i-m[s[i]]谁小,取谁,因为小的这个子串没断开
            else
                v[i + 1] = min(v[i] + 1, i - m[s[i]]);
            // 刷新该字符最新下标
            m[s[i]] = i;
            // 刷新最值
            result = max(result, v[i + 1]);
        }
        return result;
    }
};

Guess you like

Origin blog.csdn.net/zhaitianbao/article/details/130686370