代码编织梦想

【剑指offer-C++】JZ48:最长不含重复字符的子字符串

题目描述

描述:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

数据范围: s.length≤40000。

输入:"abcabcbb"
返回值:3
说明:因为无重复字符的最长子串是"abc",所以其长度为 3
输入:"bbbbb"
返回值:1
说明:因为无重复字符的最长子串是"b",所以其长度为 1
输入:"pwwkew"
返回值:3
说明:因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是子串的长度,"pwke" 是一个子序列,不是子串。    

解题思路

最长不含重复字符的子字符串:最直观的想法是,使用变量i表示字符串起始位置,使用变量j表示字符串结束位置,i的范围是0~s.size(),j的范围是i~s.size(),每个起始位置轮次,创建一个无序集合unordered_set来存储从该起始位置开始不重复的字符,如果当前字符s[j]在uset中未出现过,那么就加入uset,反之则退出内层循环,同时计算字符串长度更新最长子字符串长度。其中有两点需要注意的地方:一个是当字符串只含有一个空格时,即s=" “,那么应该返回1,这是测试样例中的一个例子;另一个是j的作用域不应该只设置在内层for循环,因为有可能字符串遍历完,即j=s.size(),此时我们仍需要使用j-i来计算字符串长度,比如示例"df”,其应该返回的是2。

int lengthOfLongestSubstring(string s) 
{
    //空字符串
    if(s.size()==0)
       return 0;
    //测试结果样例
    if(s==" ")
       return 1;
    //res表示最长子字符串的长度
    int res=0; 
    //i表示起始位置
    for(int i=0;i<s.size();i++)
    {
       //用于存储不重复的字符
       unordered_set<char> uset;
       int j; 
       //j表示结束位置
       for(j=i;j<s.size();j++)
       {
          //元素第一次出现
          if(uset.count(s[j])==0)
             uset.emplace(s[j]);
          //元素重复出现
          else
             break;
       }
       //放在外面 因为j有可能等于字符串长度 比如df
       res=max(res,j-i);
     }
     return res;
}

优化:我们可以发现,上述方法每次出现重复时都是从下一个新的起始位置重新开始,这样时间复杂度以及空间复杂度都相对较高,我们可以使用滑动窗口来进行优化。滑动窗口是线性结构上的一段,类似于一个窗口,一般使用双指针来实现,左指针维护窗口左边界,右指针维护窗口右边界,两者同方向不同速率来维护窗口。初始左右指针均指向字符串起始位置字符,然后窗口右界向右移动,保证窗口内元素不重复,一旦元素重复,则将窗口左界向右收缩来保证窗口内元素不重复。具体做法如下:首先使用无序映射对unordered_map<char,int>来统计窗口内非重复元素以及对应次数;然后使用left表示左边界right表示右边界,初始两者均为0,边界条件是右边界right小于字符串长度,每次优先右边界右移即right++,接着记录右边界元素出现的次数,如果其次数大于1,那么表示右边界元素与前面元素重复,此时右移左边界,同时处理左边界元素对应出现的次数,直至当前右边界元素出现次数为1为止退出循环,并且更新窗口最大值即可。

int lengthOfLongestSubstring(string s) 
{
    //统计窗口内的字符以及相应次数
    unordered_map<char,int> umap; 
    //子字符串最大值
    int res=0;
    //设置窗口左右边界
    for(int left=0,right=0;right<s.size();right++)
    {
        //右边界元素出现次数加一
        umap[s[right]]++;
        //出现次数大于一则窗口内有重复
        while(umap[s[right]]>1)
        //窗口左移直至当前右边界元素次数为一同时减去左边界次数
           umap[s[left++]]--;
        //维护子串长度最大值 按照窗口左右边界计算
        res=max(res,right-left+1);
    }
    return res;
}

idea:使用unordered_map来记录窗口内的字符以及相应位置,使用dp[i]表示以第i个元素为结尾的字符串的最长非重复子串长度,其下标从1开始,而字符串下标从0开始,故dp[i]对应的是s[i-1],从头开始遍历字符串,如果当前字符没有出现过,那么dp[i]=dp[i-1]+1,即当前最长等于前一个最长加一,反之如果当前字符出现过,那么dp[i]=min(dp[i-1]+1,i-umap[s[i-1]]),其中后者指的是当前最长等于当前位置减去当前元素上一次出现的位置,即表示不重复的长度,同时要防止中间出现重复元素,故要考虑上一个的基础,两者取最小值即可,最后每一次还要将当前元素以及对应位置加入哈希表,并且更新最长子串长度。

int lengthOfLongestSubstring(string s) 
{
    //统计窗口内的字符以及相应位置
    unordered_map<char,int> umap; 
    //子字符串最大值
    int res=0;
    //dp[i]表示以i为结尾的字符串的最长非重复子串
    vector<int> dp(s.size()+1,1);
    //为了方便递推公式设置dp[0]表示空串
    dp[0]=0;
    //dp[i]是第i个从1开始 但是字符串下标从0开始 故对应s[i-1]
    for(int i=1;i<=s.size();i++)
    {
       //如果当前字符没有出现过
       if(umap.find(s[i-1])==umap.end())
          //则以当前为结尾的最长等于前一个为结尾的最长加一
          dp[i]=dp[i-1]+1;
       //如果当前字符出现过
       else
          //则以当前为结尾的最长等于i减去上一次出现的位置
          //同时为了防止中间出现其他重复的字符需要考虑前一个基础
          dp[i]=min(dp[i-1]+1,i-umap[s[i-1]]);
       //将当前字符出现位置加入哈希表
       umap[s[i-1]]=i;
       //更新最长子字符串
       res=max(res,dp[i]);
    }
    return res;
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_43779149/article/details/129823997

剑指offer JZ43 左旋转字符串 Python 多解-爱代码爱编程

一.题目描述 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它! 二.解题思路 1.空间复杂度O(N),时间复杂

剑指offer-JZ54字符流中第一个不重复的字符-爱代码爱编程

时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M 热度指数:256119 本题知识点: 字符串 问题描述 请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字

剑指offer-JZ43左旋转字符串-爱代码爱编程

时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M 热度指数:347344 本题知识点: 字符串 题目描述 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZde

剑指 Offer-JZ49-把字符串转换成整数-爱代码爱编程

题目描述 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0 解题思路 常规 代码实现 class Solution { public: int StrToInt(string str) { if(str.empty()) return 0;

【牛客网编程练习】剑指Offer-JZ2 替换空格(C++)-爱代码爱编程

一、题目描述 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 二、实现思路 根据题目给的函数模型,两个参数,一个是指向字符数组的指针,一个是这个字符数组的长度。然后我们要实现一个字符(空格)替换的函数,看到这里,脑海里有两种解法。一种是直接

剑指offer--JZ5 替换空格-爱代码爱编程

链接 替换空格_牛客题霸_牛客网【牛客题霸】收集各企业高频校招笔面试题目,配有官方题解,在线进行百度阿里腾讯网易等互联网名企笔试面试模拟考试练习,和牛人一起讨论经典试题,全面提升你的技术能力https://www.nowcoder.com/practice/0e26e5551f2b489b9f58bc83aa4b6c68?tpId=265&tqI

刷题笔记 | 剑指offer-JZ38(字符串的排列)-爱代码爱编程

题目描述: 输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。 例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。 数据范围: n < 10n<10 要求: 空间复杂度 O(n!)O(n!),时间复杂度 O(n!)O(n!) 输入

【剑指offer-c++】jz12:矩阵中的路径-爱代码爱编程

【剑指offer】JZ12:矩阵中的路径 题目描述解题思路 题目描述 描述:请设计一个函数,用来判断在一个n乘m的矩阵中是否存在一条包含某长度为len的字符串所有字符的路径。路径可以从矩阵中的任意一个格子

剑指 offer 48. 最长不含重复字符的子字符串-爱代码爱编程

剑指 Offer 48. 最长不含重复字符的子字符串 难度: m

【剑指offer-c++】jz37:序列化二叉树-爱代码爱编程

【剑指offer-C++】JZ37:序列化二叉树 题目描述解题思路 题目描述 描述:请实现两个函数,分别用来序列化和反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造

【剑指offer-c++】jz38:字符串的排列-爱代码爱编程

【剑指offer-C++】JZ38:字符串的排列 题目描述解题思路 题目描述 描述:输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。例如输入字符串ABC,则

【剑指offer-c++】jz46:把数字翻译成字符串-爱代码爱编程

【剑指offer-C++】JZ46:把数字翻译成字符串 题目描述解题思路 题目描述 描述:有一种将字母编码成数字的方式:‘a’->1, ‘b->2’, … , ‘z->26’。 现在给

剑指 offer 48. 最长不含重复字符的子字符串(滑动窗口python)-爱代码爱编程

剑指 Offer 48. 最长不含重复字符的子字符串 每日几道leetcode刷刷题! JZ-Offer48 题目描述 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。 示

刷题笔记 | 剑指offer-爱代码爱编程

题目描述 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。 数据范围:s.length≤40000 方法一:滑动窗口+哈希表 思路: 使用滑动窗口,保证窗口内部元素都是不重复的,然后窗口

【剑指offer-爱代码爱编程

【剑指offer】JZ19: 正则表达式匹配 题目描述解题思路 题目描述 描述:请实现一个函数用来匹配包括’.‘和’*‘的正则表达式。 1.模式中的字符’.‘表示任意一个字符。 2.模式中的字