[leetcode]Longest Substring Without Repeating Characters

题目:

Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.

解题:

  首先想到是维护一个窗口,实现如下:

int lengthOfLongestSubstring(string s) {
        int start = 0;
		int lenOfLongest = 0;
		int curLenOfLongest = 0;
		int i;
		int j;
		int prev = 0;
		map<char, int> window; //字符->在s中的索引
		map<char, int>::iterator it;
		window.clear();
		for(i = 0; i < s.size(); i++){
			it = window.find(s[i]);
			if(it == window.end()){
			//如果当前字符不在window中,则加入,
				window[s[i]] = i;
				curLenOfLongest = i - start + 1;
			}else{
			//如果当前字符在window中,
			//则需要计算当前lenOfLongest,start后移到前一个s[i]的后一位,
			//删除window中前一个s[i]和s[i]之前的字符
			//...,start,...,prev,prev+1,...,i,...
				prev = it->second;
				curLenOfLongest = i - start;
				for(j = start; j <= prev; j++){
					window.erase(window.find(s[j]));
				}
				window[s[i]] = i;
				start = prev + 1;
			}
			if(lenOfLongest < curLenOfLongest)lenOfLongest = curLenOfLongest;
		}
		return lenOfLongest;
    }

  这个算法通过了,但时间上惨不忍睹,124ms。

  从leetcode discuss里找到下面这样一个算法,号称5ms,他是传参char* 进去的,我改成string,提交之后17ms,表现不错。

     int lengthOfLongestSubstring(string s) {
		int m[129] = {0};      //索引为0的元素不用
		int i, j;
		int cnt = 0, pre = 0;
		int max = 0;
		int c;

		for (i = 0; c = s[i]; i++) {
			if (pre < m[c]) {       //c已存在于当前子串中
				if (max < cnt)
					max = cnt;

				cnt = i-m[c];
				pre = m[c];
			}

			cnt++;
			m[c] = i+1;
		}
		return max > cnt ? max : cnt;
	}

  用下面这个算法来分析这种思路:

int lengthOfLongestSubstring(string s) {
    int present[128] ;       // track positions of each characters
    std::fill_n(present, 128, -1); // invalidate all positions
    int start, len, max_len; // unique string tracking
    int i;
    for (start=0, len=0, max_len=0, i=0; i<s.size(); ++i) {
        int ch = (int) s[i];
        if ( present[ch] < 0 ||  // if new character OR
             present[ch] < start) {  // character is not in the current unique string
            ++len;
        }
        else { // duplicated char
            len -= present[ch] - start; // adjust length
            start = present[ch] + 1;    // move forward one past dup. char
        }
        present[ch] = i;    // update char position
        if (max_len < len)
            max_len = len;
    }
    return max_len;
}

  初始化一个128个元素的数组,代表acsii码表中前128个字符,每个元素的索引即代表字符,元素的值代表字符在字符串s中的位置,如present[97]=2代表‘a’字符在s的第3个位置。初始化的时候,每个元素的值都是-1。

  然后维护一个窗口,start代表着当前子串开始的位置(s中的位置),max_len表示当前获得的最大子串长度,len表示当前的子串长度。

  这个算法的时间复杂度是O(n)。

  再回过头来看第二个算法,它的思想跟第三个算法是一样的,pre记录子串开始的位置,cnt记录当前子串长度,max记录最大子串长度。

 

posted @ 2015-02-14 11:46  山楂条子  阅读(139)  评论(0编辑  收藏  举报