• 渚漪力扣D1


    3. 无重复字符的最长子串

    难度中等4245收藏分享切换为英文关注反馈

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

    示例 1:

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

    示例 2:

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

    示例 3:

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

    滑动窗口
    思路和算法

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

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

    image-20200903090231417
    发现了什么?如果我们依次递增地枚举子串的起始位置,那么子串的结束位置也是递增的!这里的原因在于,假设我们选择字符串中的第 kk 个字符作为起始位置,并且得到了不包含重复字符的最长子串的结束位置为 rk。那么当我们选择第 k+1个字符作为起始位置时,首先从 k+1 到 rk的字符显然是不重复的,并且由于少了原本的第 kk 个字符,我们可以尝试继续增大 rk,直到右侧出现了重复字符为止。

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

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

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

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

      判断重复字符

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

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

    class Solution {
    public:
        int lengthOfLongestSubstring(string s) {
            // 哈希集合,记录每个字符是否出现过
            unordered_set<char> occ;
            int n = s.size();
            // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
            int rk = -1, ans = 0;
            // 枚举左指针的位置,初始值隐性地表示为 -1
            for (int i = 0; i < n; ++i) {
                if (i != 0) {
                    // 左指针向右移动一格,移除一个字符
                    occ.erase(s[i - 1]);
                }
                while (rk + 1 < n && !occ.count(s[rk + 1])) {
                    // 不断地移动右指针
                    occ.insert(s[rk + 1]);
                    ++rk;
                }
                // 第 i 到 rk 个字符是一个极长的无重复字符子串
                ans = max(ans, rk - i + 1);
            }
            return ans;
        }
    };
    

    拙劣代码 ↓

    int lengthOfLongestSubstring(char * s) {
    	int i, j, k = 0, l = 0,cf;
    	char s1[100000] = { 0 };
    	int zc[100000] = { 0 };
    	for (i = 0; s[i] != ''; i++) {
    		cf = 0;
    		for (j = 0; j < k; j++) {
    			if (s1[j] == s[i]) {
    				cf = 1;
    				break;
    			}
    		}
    		if (j == k) {
    			s1[k] = s[i];
    			k++;
    		}
    		if (cf == 1) {
    			zc[l] = k;
    			i = l;
    			l++;
    			k = 0;
    			continue;
    		}
    	 }
    	zc[l] = k;
    	int max=0;
    	for (i = 0; zc[i] != 0; ++i) {
    		if (max <= zc[i])max = zc[i];
    	}
    	return max;
    }
    
  • 相关阅读:
    二线城市的创业人才之战
    小程序的风口到底如何?
    短视频广告一条上百万,揭秘短视频背后的故事
    让我们来看看这些企业的创始人,在互联网金融的十年里的故事
    背靠大树成为创业成功的显学
    草根站长的艰辛创业路
    互联网大佬们的创业重要选择时刻
    80后的罗敏已经在创业路上走了十几年
    CentOS7 通过 YUM 升级 VIM8
    matplotlib 画图中的basemap安装问题
  • 原文地址:https://www.cnblogs.com/ijuysama/p/13605704.html
Copyright © 2020-2023  润新知