[ LeetCode ] #3. Longest Substring Without Repeating Characters (C++ & Python)

题目:3. Longest Substring Without Repeating Characters 题目连接

题目描述:

Given a string, find the length of the longest substring without repeating characters.

Example 1:

Input: "abcabcbb"
Output: 3 
Explanation: The answer is "abc", with the length of 3. 

Example 2:

Input: "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.

Example 3:

Input: "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3. 
             Note that the answer must be a substring, "pwke" is a subsequence and not a substring.

题意:

这道题 题意非常的简单明了即 给一个字符串,输出这个字符串不包含重复字符的最长字串长度。

分析:

  1. 第一种思路:最直接的是使用类似字符串匹配的思想来做,这种方法简单易懂,但时间复杂度极高。实现如下code1:
  2. 第二种思路:参考第一种方法可知,其中包含了很多不必要的循环和查找,如何来简化呢? 可分以下几个步骤:
    1. 使用unordered_set (无序集合容器) 来存储字符串中唯一出现过的字符。
    2. 顺序遍历字符串,且当 当前字符在容器中不存在时继续往后遍历,否则终止循环。
    3. 循环终止之后 更新不重复字串长度最大值,这时如果是因为循环到了字符串最后位置,则可跳出循环,完成查找。
    4. 当访问的字符已经在无序容器中时,终止上述循环,然后擦除头元素(因为 如果出现重复的字符,那么重复的字符肯定为头元素),指向最左侧的下表往后移一位。
    5. 完成查找,返回结果,实现代码见Code2。
  3. 第三种思路:在前面两种得到结果之后发现,算法执行的效率仍不理想,因此现在换用另外一种容器,尝试是否能够更加高效一些,这里使用了hash的概念。实现思路类同第二种思路, 代码实现见Code3。

 

Code1

class Solution {
public:
    int lengthOfLongestSubstring(string str) {
        int right=1,maxLength=0, len=str.size();
        for(int i=0;i<len-1;++i){
            string tmp = str.substr(i,1);
            while( i+right<len && (tmp.find(str[i+right]) == string::npos)){
                tmp += str[i+right];
                ++right;
            }
            if(tmp.size()>maxLength){
                maxLength = tmp.size();
            }
        }
        return maxLength;
    }
};

结果:

Runtime: 140 ms, faster than 14.21% of C++ online submissions for Longest Substring Without Repeating Characters.

Memory Usage: 27 MB, less than 100.00% of C++ online submissions for Longest Substring Without Repeating Characters.

 

Code2

class Solution {
public:
    int lengthOfLongestSubstring(string str) {
        if(str.size()<1) return 0;
	unordered_set<char> current_set;
	int maxLength=0, start=0, index=0;
	while(index < str.size()){
		while(index<str.size() && current_set.find(str[index]) == current_set.end()){
			current_set.insert(str[index]);
			++index;
		}
		maxLength = maxLength>current_set.size()?maxLength:current_set.size();
		if(index == str.size()){
			break;
		}else{
			current_set.erase(current_set.find(str[start]));
			++start;
		}
	}
	return maxLength;
    }
};

结果:

Runtime: 52 ms, faster than 30.02% of C++ online submissions for Longest Substring Without Repeating Characters.

Memory Usage: 18.9 MB, less than 100.00% of C++ online submissions for Longest Substring Without Repeating Characters.

对比以上两种方法 可以看出 在简化掉一些不必要的循环之后,执行速度快了将近三倍。

可以发现在以上优化之后faster than 30.02% of C++, 说明仍有很多需要优化的地方。接下来第三种方法使用hash继续简化。

 

Code3

    	vector<int> res(256,-1);
	int maxLength=0,start=-1;
	for(int i=0;i<str.length();++i){
		if(res[str[i]]>start){
			start = res[str[i]];
		}
		res[str[i]] = i;
		maxLength = max(maxLength, i-start);
	}
	return maxLength;

使用更加简洁一点的vector实现hash的效果,可以看到简化之后代码也更加的清晰。

结果

Runtime:20 ms, faster than 98.96%of C++ online submissions for Longest Substring Without Repeating Characters.

Memory Usage: 16.2 MB, less than 100.00% of C++ online submissions for Longest Substring Without Repeating Characters.

现在可以看到,使用hash之后相比之前的unordered_set 执行速度又快了一倍。

 

Python

下面python按照上面一样的思路来实现。代码如下

class Solution:
    def lengthOfLongestSubstring(self, s: 'str') -> 'int':
        a = {}
        maxlength=0
        start=-1
        index=0
        for i,ch in enumerate(s):
            if ch in a and a[ch] > start:
                start = a[ch]
            a[ch] = i
            maxlength = max(i-start,maxlength)
        return maxlength

结果:

Runtime: 72 ms, faster than 96.26% of Python3 online submissions for Longest Substring Without Repeating Characters.

Memory Usage: 12.6 MB, less than 100.00% of Python3 online submissions for Longest Substring Without Repeating Characters.

 

Status Accepted

 

                                                                            下划线                                                                             

 

补充一点点偶然见看到的小知识点(C++ string.size() 和 string.length()有什么区别呢):

我们都经常使用到string字符串,那么如何获取字符串的长度呢(比如在循环遍历字符串的每一个字符的时候),之前常用的方法是 这种方法。

string str;
int len = str.size();

今天偶然看到另一种很少用的方法:

string str;
int len = str.length();

那么,两者有什么区别呢?

先来看下官方文档怎么介绍的。

没错,以上就是C++官方对string::size 以及 string::length 的介绍,可以看到他们是完全等价的。两个函数返回值均为字符串的字节数。

那么,如此严谨的C++ 为什么就同一个功能维护两个函数呢?

因为,length主要是一开始C++为了和C兼容,而保留下来的。string类最初只有length,在加入STL之后,才加入了size,它也是作为STL的属性存在的。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值