Thursday, June 11, 2015

Leetcode3: Longest Substring Without Repeating Characters

Leetcode 3: 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.

大意: 找到一个字符串里面最长无重复字母的子字符串

分析: 有两种做法,一种是用map, 一种是用set
M1: use map
       key: char value: index of that char
       需要一个start指针,表示当前最长子串的起始位置。
      如果char 不在map 中, 将该char 放进map, 并且同时更新最长子串
      如果char  在map 中, 我们需要删除从 start 到该char 的所有字符,使得这个字符在map中没有重复。首先获取该char 之前在map 中的index, 将所有的value = 0; 并且将新char的位置更新,然后update start 的位置。
 worst case : time complexity is O(n), 最多扫描两遍string
M2: use set
      keep a start pointer and an end pointer
     if end char is not in the set, insert the end char into set and do end++ to explore the next char, update the max_length of the substring; if end char is in the set, erase the start char and do start++ until the end char is erased;
     time complexity is O(nlogn), as the time complexity of insert and erase operation in set is both log(n), but the code is shorter and the space complexity is less than using map.
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        //sanity check
        if (s.size() == 0) return 0;
        //use a set to store unduplicate chars
        set<int> se;
        int max_len = 0;
        int left = 0;
        int right = 0;
        for (;right < s.size(); right++) {
            if (se.find(s[right]) == se.end()) { //case 1: char not in set
                se.insert(s[right]);
                //update max_len
                max_len = max(max_len, right-left+1);
            }else { //case2: char in set
                se.erase(s[left++]);
                right--;
            }
        }
        return max_len;
    }
};

updated:
 不需要用map/set,对于以char为key 的 map, 可以直接用一个size 为256的一维数组来存储,数组的index是key, value是该字符在string里的位置。 这样就节省了空间。
用下面的方法,对sliding window进行了特殊的处理方式,只需要扫描一遍string,节省了时间。
判断存在duplicate的条件,不再是看map或者set里面有没有这个元素,而是看当前元素的value是不是比窗口左边大,如果大,说明当前元素已经在array中,找到了一个duplicate;如果小,说明当前元素是在窗口左边之外,是已经无用的元素,需要更新其index值。  

class Solution {
public:
//sliding window
    int lengthOfLongestSubstring(string s) {
        //sanity check
        if (s.size() == 0) return 0;
        int left = 0;
        int right = 1;
        int carray[256];
        for (int i = 0; i < 256; i++) {
            carray[i] = -1;
        }
        int maxl = 1;
        carray[s[0]] = 0;
        for (; right < s.size(); right++) {
            if (carray[s[right]] >= left) {
                left = carray[s[right]] + 1;
            }
            maxl = max(maxl, right- left + 1);
            carray[s[right]] = right;
        }
        return maxl;
    }
};

updated:
最精简的写法了!

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if (s.size() == 0) return 0;
        //unordered_set<char> iset;
        int iset[256] = {0};
        int left = 0;
        int right = 0;
        int gmax = 0;
        while (right < s.size()) {
          if (iset[s[right]] > 0) {
              iset[s[left]]--;
              left++;
          } else {
              iset[s[right]]++;
              right++;
          }
          gmax = max(gmax, right-left);
        }
        return gmax;
    }
};

No comments:

Post a Comment