LeetCode解题(C++)-3. 无重复字符的最长子串

题目描述:

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

示例 1:

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

示例 2:

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

示例 3:

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

解题方法:

解法一:建立一个HashMap,建立每个字符和其最后出现位置之间的映射,然后我们需要定义两个变量res和left,其中res用来记录最长无重复子串的长度,left指向该无重复子串左边的起始位置的前一个,由于是前一个,所以初始化就是-1,然后我们遍历整个字符串,对于每一个遍历到的字符,如果该字符已经在HashMap中存在了,并且如果其映射值大于left的话,那么更新left为当前映射值。然后映射值更新为当前坐标i,这样保证了left始终为当前边界的前一个位置,然后计算窗口长度的时候,直接用i-left即可,用来更新结果res,代码如下:

int lengthOfLongestSubstring(string s) {
        int res = 0, left = -1;//方法一
        unordered_map<int, int> map;
        for (int i = 0;i < s.size(); ++i) {
            if (map.count(s[i]) && map[s[i]] > left) {
                left = map[s[i]];
            }
            map[s[i]] = i;
            res = max(res, i - left);
        }
        return res;
    }

if判断的解释:一旦当前字符s[i]在HashMap已经存在映射,说明当前的字符已经出现过了,而若m[s[i]] > left 成立,说明之前出现过的字符在我们的窗口内,那么如果要加上当前这个重复的字符,就要移除之前的那个,所以我们让left赋值为m[s[i]],由于left是窗口左边界的前一个位置,所以相当于已经移除出滑动窗口了。

运行效率:36ms

解法二:

扫描二维码关注公众号,回复: 5063454 查看本文章

建立一个256位大小的整型数组来代替HashMap,这样做的原因是ASCII表共能表示256个字符,但是由于键盘只能表示128个字符,所以用128也行,然后我们全部初始化为-1,这样的好处是我们就不用像之前的HashMap一样要查找当前字符是否存在映射对了,对于每一个遍历到的字符,我们直接用其在数组中的值来更新left,因为默认是-1,而left初始化也是-1,所以并不会产生错误,这样就省了if判断的步骤,其余思路都一样:

int lengthOfLongestSubstring( string s) {
        vector < int > m( 128 , - 1 );//方法二
         int res = 0 , left = - 1 ;
         for ( int i = 0 ; i < s.size(); ++ i) {
            left = max(left, m[s[i]]);
            m[s[i]] = i;
            res = max(res, i - left);
        }
        return res;
    }

运行效率:20ms

解法三:在提交记录中发现有一种方法效率8ms,下面简单介绍一下:

static int x = [](){ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        vector <int>hax(128,-1);
        int res=0;
        int left=-1;
        for(int i=0;i<s.size();++i)
        {
            left=max(left,hax[s[i]]);
            hax[s[i]]=i;
            res=max(i-left,res);
        }
        return res;
    }
};

这里着重解释一下static int x = [](){ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();这段代码。

这种写法是Lambda捕获(Lambda表达式是C++11引入的特性,是一种描述函数对象的机制,它的主要应用是描述某些具有简单行为的函数。Lambda也可以称为匿名函数。)

std::ios::sync_with_stdio(false),Sets whether the standard C++ streams are synchronized to the standard C streams after each input/output operation. 
设置在每次输入/输出操作后标准C ++流是否与标准C流同步。

其实主要原因就是C++中的cin和cout为了兼容C,不会与scanf和printf混乱,C++用一个流缓冲区来同步C的标准流,而std::ios::sync_with_stdio函数可以解除该同步,使之不经过缓冲区而节省时间。

由于std :: cin默认是与std :: cout绑定的,所以每次操作的时候(也就是调用”<<”或者”>>”)都要刷新(调用flush),这样增加了IO的负担,通过tie(nullptr)来解除std :: cinstd :: cout之间的绑定,来降低IO的负担使效率提升。

从而很大程度的提升了代码运行效率。

猜你喜欢

转载自blog.csdn.net/xiaomucgwlmx/article/details/86549305