题目:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
解答:
方法一:
首先想到的是用两个迭代器iter iter2,看iter2所指向的字符是否存在于[iter,iter2]substring中,使用的是string的find_first_of
时间复杂度:O(n²)
int lengthOfLongestSubstring(string s) { if (s.length() == 0 || s.length()==1) { return s.length(); } int maxLen = -1; int len = 0; auto iter = s.begin(); auto iter2 = s.begin(); for (; iter != s.end(); iter++) { iter2 = iter + 1; while (iter2 != s.end()) { string subStr = s.substr(iter-s.begin(), iter2 - iter); auto pos = subStr.find_first_of(*iter2); if (pos == string::npos)//iter2已经存在在之前的subStrle,则continue { len = iter2 - iter+1; if (len > maxLen) { maxLen = iter2 - iter + 1; } iter2++; //cout << "maxLen:" << maxLen << endl; } else { len = iter2 - iter;//找到了,则iter++ if (len > maxLen) { maxLen = len; } //cout << "maxLen2:" << maxLen << endl; break; } }; } return maxLen; }
提交后,所占内存、运行时间都只超过5%,暴力遍历效果较差。
方法二:
- 使用类似于hashmap的方式,
- string可以通过s[i]访问第i个字符
- 上面的查找用的find_first_of,太慢了
string每个字符是一个char,而char的范围为0-127,因此创建一个char[128] map来存储所有出现的字符,以s[i]作为key,如果存在则map[s[i]]++,如果map[s[j]]的值>1则表示出现了多次,即存在重复的字符。
使用两个索引滑动窗口,满足条件的不重复长度为:j-i+1
代码如下:
int lengthOfLongestSubstring3(string s) { if (s.size() < 2) { return s.size(); } int maxLen = 0; char map[130] = { 0 }; int i = 0, j = 0; for (; j < s.length(); j++) { map[s[j]]++; //将第j个字符放到数组中; while (map[s[j]] > 1) { map[s[i]]--; //i向右移动 i++; } if (j - i + 1 > maxLen) { //cout << "maxLen:" << maxLen << endl; //cout << "i j :" << j - 1 + i << endl; maxLen = j - i + 1; } } return maxLen; }
提交结果:
总结:
1.感觉leetcode提交后,运行时间的排名不准,同样的代码提交几次,排名差别有百分几的浮动。
2.同样的问题,不同的代码的运行效率及内存占用差别还是很巨大的;
3.现在工作时,只注意完成功能,从来没有考虑到代码效率问题,而且没有代码审核环境,提高很慢;
4.闲着也是闲着,还是坚持刷题吧 ;