[LeetCode]HashTable主题系列{第3题}
时间:2022-05-06
本文章向大家介绍[LeetCode]HashTable主题系列{第3题},主要内容包括1. 内容介绍、2. 题目和解题过程、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
1. 内容介绍
开一篇文章记录在leetcode中HashTable主题下面的题目和自己的思考以及优化过程,具体内容层次按照{题目,分析,初解,初解结果,优化解,优化解结果,反思}的格式来记录,供日后复习和反思[注:有些题目的解法比较单一,就没有优化过程]。题目的顺序按照leetcode给出的题目顺序,有些题目在并不是按照题目本身序号顺序排列的,也不是严格按照难易程度来排列的。
因此,这篇文章并不具有很强的归类总结性,归类总结性知识将会在其他文章记录,本篇重点在记录解题过程中的思路,希望能对自己有所启发。
2. 题目和解题过程
2.1 Longest Substring Without Repeating Characters
-
题目:Given a string, find the length of the longest substring without repeating characters.Examples:Given
"abcabcbb"
, the answer is"abc"
, which the length is 3.Given"bbbbb"
, the answer is"b"
, with the length of 1.Given"pwwkew"
, 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. - 分析:题目点明了三个要素:子串,无重复字符,最长。其中子串意味着选取的字符串在源字符串中是连续存在的,无重复和最长是自明的。题目的难点之一是对于一个字符,如何在现有子串中快速判重,显然,遍历搜索时间复杂度是O(n),红黑树set查询的时间复杂度是O(logn),而哈希表unordered_set拥有最快速的速度,其时间复杂度是O(1)。以下先给出一个暴力解法,便于理清基本思路和观察可以优化的地方,同时也方便拿时间和优化解法的时间进行对比,凸显算法设计的重要性。
- 初解:先从源字符串S头部第一个字符开始,向后连续生成子串,对于每一个后续的字符进行判重,如果重复则记录下当前子串长度和内容,然后移动到第二个字符重复之前的过程,依次类推,直到源字符串的最后一个字符。其中如果遇到比当前最长无重复子串长度更长的子串,则更新此记录。该解法的时间复杂度约为O(n2)。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
string longest_substr="";
for(int index=0; index < s.size(); ++index)
{
set<char> char_set;
string tmp_substr = "";
find_longest_substr(s, index, char_set, tmp_substr);
if(tmp_substr.size() > longest_substr.size())
longest_substr = tmp_substr;
}
return longest_substr.size();
}
void find_longest_substr(string& s, int index, set<char>& char_set, string& tmp_substr)
{
for(int start = index; start < s.size(); ++start)
{
if(char_set.find(s[start])==char_set.end())
{
char_set.insert(s[start]);
tmp_substr+=s[start];
}
else break;
}
}
};
- 初解结果:
- 优化解法1:初解中每次遇到重复字符时,重新从当前起始字符的下一个字符开始搜索,这样会做额外的无用功,因为例如字符串abcdad,从a开始搜索时a字符重复但是中间字符串bcd并未重复,因此可以不必重新从b开始搜索,而是将首部的a去掉直接从bcda后的d开始继续搜索。根据上面的例子可以总结出一个规律:当出现重复字符时,只需要将该字符在子串中重复的位置以前的字符去除掉,然后判断当前剩余的字符长度加上现有子串长度之和小于当前计算出来的最长子串长度时,可以终止搜索了,否则继续沿着当前搜索的位置向后搜索,直到源字符串结尾。此处的优化思想是从现有结果中提取无需重复计算的结果,节省计算时间,减少总体重复计算的总量。至于查重方法,暂时使用红黑树实现的set。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() <= 1)
return s.size();
int length = 0, last_pos = 0;
set<char> substring;
for(int i = 0; i < s.size(); ++i)
find_longest_substr(s, i, substring, last_pos, length);
if(length < substring.size())
length = substring.size();
return length;
}
void find_longest_substr(string& s, int& index, set<char>& substring, int& last_pos, int& length)
{
if(substring.find(s[index]) == substring.end())
substring.insert(s[index]);
else
erase_duplicate_subsubstring(s, index, substring, last_pos, length);
}
void erase_duplicate_subsubstring(string& s, int& index, set<char>& substring, int& last_pos, int& length)
{
if(length < substring.size())
length = substring.size();
for(int j = last_pos; j < index; ++j)
{
substring.erase(s[j]);
if(s[j]==s[index])
{
last_pos = j+1;
break;
}
}
substring.insert(s[index]);
}
};
- 优化结果1:
- 优化解法2:将查重方式改为哈希表unordered_set。
- 优化结果2:结果差别不大,不予展示。
- R语言数据清洗实战——复杂数据结构与list解析
- R语言爬虫实战——知乎live课程数据爬取实战
- Python爬虫系列(二)Quotes to Scrape(谚语网站的爬取实战)
- R语言数据清洗实战——世界濒危遗产地数据爬取案例
- Leetcode-Easy 437. Path Sum III
- R语言爬虫实战——网易云课堂数据分析课程板块数据爬取
- 左手用R右手Python系列14——日期与时间处理
- 如何使用管道操作符优雅的书写R语言代码
- 第四周编程作业(二)-Deep Neural Network for Image Classification: ApplicationDeep Neural Network for Image Cl
- 第四周编程作业(一)-Building your Deep Neural Network: Step by StepBuilding your Deep Neural Network: Step by
- Python数据抓取与可视化实战——网易云课堂人工智能与大数据板块课程实战
- 商务图表案例——仿经济学人分组漏斗图~
- 第二周编程作业 -Logistic Regression with a Neural Network mindsetLogistic Regression with a Neural Network
- 左手用R右手Python系列——任务进度管理
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 安排上了!PC人脸识别登录,出乎意料的简单
- valgrind使用介绍
- 实用!一键生成数据库文档,堪称数据库界的Swagger
- 算法集锦(2)|scikit-learn| 如何利用文本挖掘推荐Ted演讲
- 算法集锦(3)|采用医疗数据预测糖尿病的算法
- 谁说Cat不能做链路跟踪的,给我站出来
- Libra:一种Python工具,可以用几行代码自动实现机器学习过程
- 国内首个“新基建”安全大赛启动了!
- Kubernetes 中 Informer 的使用
- 嵌入式开发中常见3个的C语言技巧
- 恕我直言,我也是才知道ElasticSearch条件更新是这么玩的
- 有了MinIO,你还会用FastDFS么?
- STP 实验
- 算法集锦(6) |基于GPU框架的tensorflow数据增强算法
- 交换机端口安全实验