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;
};
这是我总结的一些思考方法,希望自己以后回头看现在的代码时,会有种醍醐灌顶的感觉。

谢谢~我会继续努力的~


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值