3、无重复字符的最长子串

博客围绕给定字符串找出无重复字符的最长子串长度的问题展开。介绍了两种方法,暴力法时间复杂度O(n^3),会超出时间限制;滑动窗口法时间复杂度O(n),通过hashMap记录字符及其下标,还说明了开始位置选择较大值的原因,并给出了LeetCode讲解链接。

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

输入: "abcabcbb"

输出: 3

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

方法一:暴力法 时间复杂度O(n^3) 空间复杂度O(min(m, n)) 超出时间限制

思路:

【1】以长度length为for循环进行截取字符串​ for(int i=length;i>0;i--)

【2】对于截取的字符串进行判断,若无重复字符则返回当前长度​

//判断字符串有无重复部分
 bool isRepeat(string str) {
	 set<char> s;
	 for (int i = 0;i < str.length();++i) {
		 char ch = str[i];
		 //有重复部分
		 if (s.find(ch) != s.end()) {
			 return true;
		 }
		 s.insert(ch);
	 }

	 return false;
 }


 int lengthOfLongestSubstring(string s) {
	 int length; //截取长度
	 for (length = s.length();length > 0;length--) {
		 //index为截取开始位置
		 for (int index = 0;index <= s.length() - length;++index) {
			 string str = s.substr(index, length);
			 if (!isRepeat(str)) {
				 return length;
			 }
		 }
	 }
	 return 0;
 }

方法二:滑动窗口 时间复杂度O(n),空间复杂度O(min(m, n))//n为字符串的大小,m为字符集的大小

思路:

【1】如果从索引 i 到 j - 1 之间的子字符串 s(i,j-1​) 已经被检查为没有重复字符。我们只需要检查 s_j 对应的字符是否已经存在于子字符串 s(i,j-1)​ 中。​

【2】用hashMap记录字符及其下标,​未出现重复字符则将其添加到hashMap中。

【3】若出现重复字符则计算开始位置begin的下标,当前长度currLen为index-begin+1。并更新重复字符的下标

​int lengthOfLongestSubstring(string s) {
	if (s.length() <= 1)
		return s.length();
	unordered_map<char, int> hashMap;
	int max = -1, begin = 0, index = 0, currLen = 0; //begin为无重复字符串开始位置
	for (;index < s.length();++index) {
		char ch = s[index];
		//未出现重复的字符
		if (hashMap.find(ch) == hashMap.end()) {
			hashMap.insert({ ch,index });
		}
		else {	
			int temp = hashMap[ch]+1;	//出现重复字符的下一个下标
			begin = begin > temp ? begin : temp;	//开始位置为较大的位置
			hashMap[ch] = index;
		}
		currLen = index - begin + 1;	//现有长度
		max = max > currLen ? max : currLen;
	}
	return max;
}

对于开始位置begin选择较大位置的说明

例:字符串"twswqpt",当遍历到第二个w时,begin将等于重复字符下一个字符的下标,即s的下标(2)。begin=2

之后遍历到第二个t时,如果没有选择较大位置的begin,begin将等于第一个t后一个字符的下标,即第一个w的下标(1),

显然这是错误的,因为begin等于1的话,字符串中w就重复了。所以要比较begin和temp的大小,选择较大的位置。

最后贴出leetcode中关于本题的讲解

https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

【四轴飞行器】非线性三自由度四轴飞行器模拟器研究(Matlab代码实现)内容概要:本文围绕非线性三自由度四轴飞行器模拟器的研究展开,重点介绍了基于Matlab的建模与仿真方法。通过对四轴飞行器的动力学特性进行分析,构建了非线性状态空间模型,并实现了姿态与位置的动态模拟。研究涵盖了飞行器运动方程的建立、控制系统设计及数值仿真验证等环节,突出非线性系统的精确建模与仿真优势,有助于深入理解飞行器在复杂工况下的行为特征。此外,文中还提到了多种配套技术如PID控制、状态估计与路径规划等,展示了Matlab在航空航天仿真中的综合应用能力。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的高校学生、科研人员及从事无人机系统开发的工程技术人员,尤其适合研究生及以上层次的研究者。; 使用场景及目标:①用于四轴飞行器控制系统的设计与验证,支持算法快速原型开发;②作为教学工具帮助理解非线性动力学系统建模与仿真过程;③支撑科研项目中对飞行器姿态控制、轨迹跟踪等问题的深入研究; 阅读建议:建议读者结合文中提供的Matlab代码进行实践操作,重点关注动力学建模与控制模块的实现细节,同时可延伸学习文档中提及的PID控制、状态估计等相关技术内容,以全面提升系统仿真与分析能力。
无重复字符长子问题指的是,给定一个字符`s`,找出其中不含有重复字符的长子的长度,该问题可使用滑动窗口和哈希表解决,这一组合能解决一系列字符问题,如小覆盖子、找到字符中所有字母异位词、长重复子等[^3]。 ### 算法思路 使用滑动窗口结合哈希表的方法。定义一个哈希表来存储每个字符在字符中出现的位置,同时定义双指针`left`和`right`,其中`left`指向滑动窗口的左端,而`right`则向右移动。在移动`right`指针的同时不断更新哈希表,以及记录当前无重复字符长子的长度。当遇到重复字符时,利用哈希表中记录的信息来更新左指针,并重新计算当前的长子[^1]。 ### 代码实现 #### Python实现 ```python def lengthOfLongestSubstring(s): # 哈希表,记录字符及其近一次出现的位置 char_index_map = {} # 滑动窗口的左边界 left = 0 # 长无重复子的长度 max_length = 0 for right in range(len(s)): current_char = s[right] # 如果当前字符已经存在于窗口中,更新左边界 if current_char in char_index_map: left = max(left, char_index_map[current_char] + 1) # 更新哈希表,记录当前字符的位置 char_index_map[current_char] = right # 计算当前窗口的长度,并更新大长度 max_length = max(max_length, right - left + 1) return max_length ``` #### Java实现 ```java import java.util.HashMap; import java.util.Map; class Solution { public int lengthOfLongestSubstring(String s) { int n = s.length(); // 字符长度 int maxLength = 0; // 长无重复子的长度 Map<Character, Integer> map = new HashMap<>(); // 哈希表,记录字符及其近一次出现的位置 // 滑动窗口的左右边界分别为 i 和 j for (int j = 0, i = 0; j < n; j++) { char currentChar = s.charAt(j); // 当前字符 // 如果当前字符已经存在于窗口中,更新左边界 i if (map.containsKey(currentChar)) { i = Math.max(map.get(currentChar) + 1, i); } // 更新哈希表,记录当前字符的位置 map.put(currentChar, j); // 计算当前窗口的长度,并更新大长度 maxLength = Math.max(maxLength, j - i + 1); } return maxLength; // 返回长无重复子的长度 } } ``` #### C++实现 ```cpp #include <iostream> #include <string> #include <unordered_map> #include <algorithm> class Solution { public: int lengthOfLongestSubstring(std::string s) { int n = s.size(); int maxLength = 0; std::unordered_map<char, int> charIndexMap; for (int right = 0, left = 0; right < n; right++) { char currentChar = s[right]; if (charIndexMap.find(currentChar) != charIndexMap.end()) { left = std::max(left, charIndexMap[currentChar] + 1); } charIndexMap[currentChar] = right; maxLength = std::max(maxLength, right - left + 1); } return maxLength; } }; ``` ### 复杂度分析 - **时间复杂度**:$O(n)$,其中`n`是字符的长度。因为只需要遍历一次字符。 - **空间复杂度**:$O(min(n, m))$,其中`m`是字符集的大小(ASCII 字符集大小为 128),哈希表多存储所有唯一字符 [^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值