leetcode第三题

最近终于拾起了久违的编程,开始做leetcode上的题,开始看啊哈磊的《啊哈!算法》,忽然觉得算法其实是很有意思的,当然这是建立在会编程的基础之上的,所以我现在致力于学好C++和编程,也许有一天我也可以成为大神呢哈哈~不得不承认我真的是太菜,需要学习的东西还有很多,抱大牛们大腿啊。。由于数据结构知识不牢固,导致对于最简答的题目都想不到好的解决方法,可是我已经开始在不断地进步和学习了,每天学习一点,会有收获的~我要开始坚持写CSDN博客了,看到大牛们的高深莫测,让我更有动力去学习!

最近接触排序的算法,发现了一个很好用的思路,就是充分利用数组的下标来标记元素是否出现过,排序中的桶排序就是这个原理,需要注意的是,只要涉及到去重或者无重复这样的关键词,就要想到用哈希表(如leetcode第一题)或者是标记法。

leetcode上的第三题让我受益匪浅,我学习到了很多不同的解决方法。

思路一:最直接的枚举法。从所给字符串中找出所有的子串,然后判断每一个子串是否含有相同的元素即可。

class Solusion{
public:
    int lengthOfLongestSubstring(string s){
		int i = 0, j = 0, k = 0;
		int len = s.length();
		int maxlen = 0;
		string tempstr = "";
		
		for (i = 0; i < len; i++){
			for (j = i+1; j <= len; j++){
				//获得从i到j的子字符串,一共有n*(n+1)/2个子字符串
				tempstr = s.substr(i, j-i);
				//判断子串中是否有重复出现的元素
				bool exist[256] = {false};
				bool repeat = false;
				for (k = 0; k < tempstr.length(); k++){
					//如果字串中存在重复元素
					if (exist[tempstr[k]] == true){
						repeat = true;
						break;
					}
					exist[tempstr[k]] = true;
				}
				//如果当前处理的子串没有重复字符
				if (!repeat){
					if (tempstr.length() > maxlen){
						maxlen = tempstr.length();
					}
				}
			}
		}
		return maxlen;
	}
};
这个代码在leetcode上能够正常运行,一个网友写的代码中有个错误,现已改正:
k < tempstr.length();

在提交代码的时候,出现错误Time Limit Exeeded,该算法的时间复杂度是O(n^3),算法复杂度太高。

思路二:用一个数组(256个)来标记元素是否出现,用两个指针 i,j 来表示子串的起始和终止位置,这也是leetcode官网给出的答案,算法时间复杂度是O(n)。这里值得注意的一个问题是,最后一次比较不要忘记,因为在 j 非0的时候,i - j 并不是子串的长度。

 012345678910
要查找的字符串abcdcabcde 
 i , j 初始位置 i, j          
无重复元素时 i 往前移动 j  i ->         
第一次查到重复元素位置 j   i      
此时 j 移动到重复元素位置   j i      
 i, j 同时往前移动一个位置    j  i     
如此反复    j    i   
       j    i 
注意:最后一次也是需要比较的      j     i

class Solution{
public:
    int lengthOfLongestSubstring(string s){
        if (s.empty())
			return 0;
		int len = s.size();
		int bitmap[256] = {0};
		int maxlen = 0;
		int j = 0;
		for (int i = 0; i < len; i++){
			if (bitmap[s[i]] == 0){
				bitmap[s[i]] = 1;
			}
			else{
				maxlen = max(maxlen, i - j);
				//对bitmap进行设置,将重复元素之前的所有元素对应的位置设为0,因为这些元素不参与下一次子串
				while (s[i] != s[j]){
					bitmap[s[j]] = 0;
					j++;
				}
				j++;
			}
		}
		maxlen = max(maxlen, len - j); //注意最后还要判断一下
		return maxlen;
	}
};

思路三:网友的一种巧妙的解决方案值得思考,就是首先将数组(256个)的每个元素设为-1,idx表示当前子串的起始位置的前一个位置的下标,算法复杂度也是O(n)。(反正这个解法我是想不出来。。至今还在感叹某人的聪慧。。)直接放上大神的代码和自己的一点理解吧~

class Solution{
public:
    int lengthOfLongestSubstring(string s)
	int locs[256]; //标记元素是否出现过
	memset(locs, -1, sizeof(locs));
	int idx = -1, max = 0; //idx为当前子串的起始位置的前一个位置
	for (int i = 0; i < s.size(); i++){
		//如果当前元素出现过,那么当前子串的起始位置为这个字符上一次出现的位置+1
		if (locs[s[i]] > idx){
			//新子串的起始位置设为s[i]出现的位置+1
			//idx为当前子串的起始位置的前一个位置的下标
			idx = locs[s[i]];
		}
		//如果当前子串的长度大于最大值
		if (i - idx > max){
			max = i - idx;
		}
		//更新元素s[i]出现的位置
		locs[s[i]] = i;
	}
	return max;
};
这是我总结的一些思考方法,希望自己以后回头看现在的代码时,会有种醍醐灌顶的感觉。

谢谢~我会继续努力的~


### LeetCode 第三:无重复字符的最长子串 LeetCode 第三的目标是找到给定字符串中的 **无重复字符的最长子串** 的长度。以下是基于 C 语言的一种解决方案。 #### 解决方案描述 一种高效的解决方法是利用滑动窗口技术配合哈希表来记录字符的位置。这种方法的核心思想如下: 1. 定义一个大小为 `128` 的整型数组作为哈希表,用于存储 ASCII 字符集中的每个字符是否存在以及其最后出现的位置。 2. 初始化两个指针 `start` 和 `i` 来表示当前子串的起始位置和遍历到的当前位置。 3. 遍历整个字符串,如果当前字符未在哈希表中标记,则将其标记并扩展右边界;否则调整左边界以移除重复字符的影响。 4. 在每次迭代过程中动态维护最大子串长度。 下面是具体的代码实现: ```c int lengthOfLongestSubstring(char* s) { int Hash[128] = { 0 }; // 哈希表初始化,ASCII码范围为128 int max = 0; // 记录最大长度 int start = 0; // 子串起点 int i = 0; // 当前索引 int length = strlen(s); while (i < length && start < length) { if (Hash[s[i]] == 0) { // 如果当前字符尚未出现过 Hash[s[i]] = 1; // 将其加入哈希表 i++; // 移动右侧指针 max = ((i - start) > max) ? (i - start) : max; // 更新最大长度 } else { // 出现重复字符 Hash[s[start]] = 0; // 清除左侧字符的状态 start++; // 缩小窗口,移动左侧指针 } } return max; } ``` 上述代码实现了 O(n) 时间复杂度的算法[^2],其中 n 是输入字符串的长度。相比暴力法(O(n³)),这种优化显著提高了效率。 #### 关键点解析 - **时间复杂度**: 整个过程只需一次扫描即可完成,因此时间复杂度为 O(n),优于暴力枚举方式。 - **空间复杂度**: 使用了一个固定大小的辅助数组(即哈希表),故空间复杂度为 O(128)=O(1)。 - **适用场景**: 此方法适用于任何包含标准 ASCII 字符的字符串处理问
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值