Showing posts with label 字符串处理. Show all posts
Showing posts with label 字符串处理. Show all posts

Monday, August 7, 2017

[Leetcode] One Edit Distance, Solution

Given two strings S and T, determine if they are both one edit distance apart.

[Thoughts]
这是个简化版。只要考虑几种可能, 如果s.length == t.length,只要看看不相同的字符是否超过一个即可。如果s.length < t.length,看看在s中插入一个字符是否能解决问题。

[Code]
1:    bool isOneEditDistance(string s, string t) {  
2:      int lena = s.size();  
3:      int lenb = t.size();  
4:      if(lenb > lena) return isOneEditDistance(t, s);  
5:      if(lena - lenb > 1) return false;  
6:        
7:      int diff = 0;  
8:      for(int i =0, j = 0; i< s.size() && j< t.size() && diff < 2; i++, j++) {  
9:        if(s[i] != t[j]) {  
10:          diff++;  
11:          if(lena != lenb) t.insert(j, 1, s[i]);  
12:        }  
13:      }  
14:        
15:      if((lena != lenb) && diff <2) return true;  
16:      if((lena == lenb) && diff ==1) return true;  
17:      return false;  
18:    }  

[Leetcode] Perfect Squares, Solution

Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.
For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.

[Thoughts]
一个一维的DP,比较简单。具体看code


[Code]
1:    int numSquares(int n) {  
2:        
3:      vector<int> dp(n+1, 0);  
4:      for(int i =1; i<= n; i++) {  
5:          
6:        int min_v = INT_MAX;  
7:        for(int j = 1; j*j <= i; j++) {  
8:          min_v = min(min_v, dp[i - j*j] +1);  
9:        }  
10:        dp[i] =min_v;  
11:      }  
12:        
13:      return dp[n];  
14:    }  

[Leetcode] Remove Duplicate Letters, Solution

Given a string which contains only lowercase letters, remove duplicate letters so that every letter appear once and only once. You must make sure your result is the smallest in lexicographical order among all possible results.
Example:
Given "bcabc"
Return "abc"
Given "cbacdcbc"
Return "acdb"

[Thoughts]
首先统计每个字符出现的次数,然后重新扫描数组,保证每个字符在新字符串中只出现一次。


[Code]
1:    string removeDuplicateLetters(string s) {  
2:      vector<int> count(26, 0);  
3:      vector<int> visited(26, 0);  
4:        
5:      for(char c : s) {  
6:        count[c-'a']++;  
7:      }  
8:      string result= "";  
9:      for(char c : s) {  
10:        if(visited[c-'a'] == 1) {  
11:          count[c-'a']--;  
12:          continue;  
13:        }  
14:        while(result.size() > 0 && c < result.back() && count[result.back()-'a'] >0) {  
15:          visited[result.back()-'a'] = 0;  
16:          result.pop_back();  
17:        }  
18:        result += c;  
19:        visited[c-'a'] = 1;  
20:        count[c-'a']--;  
21:      }  
22:        
23:      return result;   
24:    }  

[Leetcode] Maximum Product of Word Lengths, Solution

Given a string array words, find the maximum value of length(word[i]) * length(word[j]) where the two words do not share common letters. You may assume that each word will contain only lower case letters. If no such two words exist, return 0.
Example 1:
Given ["abcw", "baz", "foo", "bar", "xtfn", "abcdef"]
Return 16
The two words can be "abcw", "xtfn".
Example 2:
Given ["a", "ab", "abc", "d", "cd", "bcd", "abcd"]
Return 4
The two words can be "ab", "cd".
Example 3:
Given ["a", "aa", "aaa", "aaaa"]
Return 0
No such pair of words.

[Thoughts]
这里面比较有意思的是,只需要判断两个words是否有重复字符,并不需要知道具体重复的次数,所以用bitmap来做,很方便。

一个integer是32个bit,而英文字母只有26个,所以在第一轮循环中,先处理word,把26个字母是否出现映射到bitmap上。在第二轮循环中,对于bitmap不重复的words,计算长度的乘积,并保留最大值。


[Code]

1:    int maxProduct(vector<string>& words) {  
2:        
3:      if(words.size() < 2) return 0;  
4:      vector<int> counts(words.size(), 0);  
5:        
6:      for(int k = 0; k< words.size(); k++) {  
7:        string word = words[k];  
8:        int measure = 0;  
9:        for(int i =0; i< word.size(); i++)  
10:        {  
11:          // set bitmap  
12:          measure |= (1<< (word[i]-'a'));  
13:        }  
14:        counts[k] = measure;  
15:      }  
16:        
17:      int max_v = 0;  
18:      for(int i =0; i< words.size(); i++) {  
19:        for(int j = i+1; j< words.size(); j++)  
20:        {  
21:          // use bitmap to check no common char  
22:          if((counts[i] & counts[j]) ==0) {  
23:            int product= words[i].length()* words[j].length();  
24:            max_v = max(max_v, product);  
25:          }  
26:        }  
27:      }  
28:      return max_v;   
29:    }  


[Leetcode] Reverse Words in a String, Solution

Given an input string, reverse the string word by word.
For example,
Given s = "the sky is blue",
return "blue is sky the".
Update (2015-02-12):
For C programmers: Try to solve it in-place in O(1) space.
Clarification:
  • What constitutes a word?
    A sequence of non-space characters constitutes a word.
  • Could the input string contain leading or trailing spaces?
    Yes. However, your reversed string should not contain leading or trailing spaces.
  • How about multiple spaces between two words?
    Reduce them to a single space in the reversed string.

[Thoughts]
这是比较琐碎的一道实现题。先把字符串中的多余空格清除掉,然后对于每一个word做reverse,最后再对整个string做一遍reverse即可。


[Code]
注意,这里remove multiple spaces的循环和swap words的循环,可以merge成一个loop,这里分成两个是为了保证可读性。
1:    void reverseWords(string &s) {  
2:      int start = 0;  
3:      int end = 0;  
4:      string sn="";  
5:        
6:      // remove the multiple space  
7:      for(int i =start; i< s.size();){  
8:        if(s[i] == ' ') {  
9:          sn.push_back(' ');  
10:          while(i < s.size() && s[i] ==' ') {  
11:            i++;  
12:          }  
13:        } else {  
14:          sn.push_back(s[i]);  
15:          i++;  
16:        }  
17:      }  
18:      s = sn;  
19:        
20:      // swap the words  
21:      while(end < s.size()) {  
22:        while(end < s.size() && s[end] ==' ') {  
23:          start ++;  
24:          end++;  
25:        }  
26:          
27:        while(end < s.size() && s[end] != ' ') end++;  
28:          
29:        swapW(s, start, end-1);  
30:        start = end;  
31:      }  
32:        
33:      swapW(s, 0, s.size()-1);  
34:        
35:      //remove the leading or trailing spaces  
36:      start = s[0] == ' '? 1:0;  
37:      end = s[s.size()-1] == ' '? s.size()-2: s.size()-1;  
38:      s= s.substr(start, end-start +1);  
39:    }  
40:      
41:    void swapW(string& s, int start, int end) {  
42:      for(int i =start, j = end; i<j; i++, j--) {  
43:        swap(s[i],s[j]);  
44:      }  
45:    }  




Thursday, July 27, 2017

[Leetcode] Palindromic Substrings, Solution

Given a string, your task is to count how many palindromic substrings in this string.
The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters.
Example 1:
Input: "abc"
Output: 3
Explanation: Three palindromic strings: "a", "b", "c".
Example 2:
Input: "aaa"
Output: 6
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
Note:
  1. The input string length won't exceed 1000.

[Thoughts]
从左到右遍历字符串,以每一个字符为中心,向左右两边扩展扫描,统计palindromic string。

另外,这题也可以用DP,类似于 http://fisherlei.blogspot.com/2012/12/leetcode-longest-palindromic-substring.html

[Code]
1:    int countSubstrings(string s) {  
2:      if(s == "") return 0;  
3:        
4:      int count = 1;   
5:      for(int i =1; i< s.size(); i++) {  
6:        // palindrom length is odd and i in the middle  
7:        count += countPalindrom(s, i, i);  
8:          
9:        // palindrom length is even and (i-1, i) in themiddle  
10:        count += countPalindrom(s, i-1, i);  
11:      }  
12:      return count;  
13:    }  
14:      
15:    int countPalindrom(string& s, int start, int end) {  
16:      int count = 0;  
17:      for(int i =0; start >=0 && end <s.size(); i++)  
18:      {  
19:        if(s[start] != s[end]) break;  
20:          
21:        count++;  
22:        start--;  
23:        end++;  
24:      }  
25:        
26:      return count;  
27:    }  

[Leetcode] Replace Words, Solution

In English, we have a concept called root, which can be followed by some other words to form another longer word - let's call this word successor. For example, the root an, followed by other, which can form another word another.
Now, given a dictionary consisting of many roots and a sentence. You need to replace all the successor in the sentence with the rootforming it. If a successor has many roots can form it, replace it with the root with the shortest length.
You need to output the sentence after the replacement.
Example 1:
Input: dict = ["cat", "bat", "rat"]
sentence = "the cattle was rattled by the battery"
Output: "the cat was rat by the bat"
Note:
  1. The input will only have lower-case letters.
  2. 1 <= dict words number <= 1000
  3. 1 <= sentence words number <= 1000
  4. 1 <= root length <= 100
  5. 1 <= sentence words length <= 1000
[Thoughts]
把字典转成hashmap,这样查询节省时间。这里用stringstream来读取子字符串,然后在子字符串中处理prefix,第一个被查到的就是最短的那个。

很简单的一道题。可说的东西不多。


[Code]
1:    string replaceWords(vector<string>& dict, string sentence) {  
2:      if(dict.size() == 0) return sentence;  
3:      unordered_map<string, int> roots;  
4:      for(auto& root : dict) {  
5:        roots[root] = 1;  
6:      }  
7:        
8:      string result = "";  
9:        
10:      stringstream ss(sentence);  
11:      string successor ;  
12:      while(ss>>successor ) {  
13:          
14:        string prefix;  
15:        for(int i =1; i<= successor.size(); i++) {  
16:          prefix = successor.substr(0, i);  
17:          if(roots.find(prefix) != roots.end()) break;  
18:        }  
19:          
20:        result += prefix + " ";  
21:      }  
22:        
23:      //remove the end empty space  
24:      if (result != "") result.resize(result.size()-1);  
25:      return result;  
26:    }  


Monday, July 24, 2017

[Leetcode] Decode String, Solution

Given an encoded string, return it's decoded string.
The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated exactly k times. Note that k is guaranteed to be a positive integer.
You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, etc.
Furthermore, you may assume that the original data does not contain any digits and that digits are only for those repeat numbers, k. For example, there won't be input like 3a or 2[4].
Examples:
s = "3[a]2[bc]", return "aaabcbc".
s = "3[a2[c]]", return "accaccacc".
s = "2[abc]3[cd]ef", return "abcabccdcdcdef".


[Thoughts]
凡是这种decode的题,基本上都是用栈。当遇到左括号的时候,保留住当前的栈状态,当遇到右括号的时候,弹出当前栈状态,做一番处理。具体看code



[Code]
1:    string decodeString(string s) {  
2:      stack<int> repeat_counts;  
3:      stack<string> pre_fix;  
4:        
5:      int num = 0;  
6:      string decoded = "";  
7:      string cur = "";  
8:        
9:      s = "1[" + s +"]"; // wrap the input into a bracket to simplify the logic  
10:      for(int i = 0; i< s.size(); i++) {  
11:        if(isdigit(s[i])) {  
12:          num = num*10 + s[i] -'0';  
13:          continue;  
14:        }  
15:          
16:        if(s[i] == '[') {  
17:          repeat_counts.push(num);  
18:          num = 0;  
19:          pre_fix.push(cur);  
20:          cur = "";  
21:          continue;  
22:        }  
23:          
24:        if(s[i] == ']') {  
25:          int repeat = repeat_counts.top();  
26:          repeat_counts.pop();  
27:          string prefix = pre_fix.top();  
28:          pre_fix.pop();  
29:            
30:          cur = prefix + repeatString(cur, repeat);  
31:          continue;  
32:        }  
33:          
34:        cur += s[i];  
35:      }  
36:        
37:      return cur;  
38:    }  
39:      
40:    string repeatString(string& organic, int repeats) {  
41:      string result = "";  
42:      for(int i =0; i< repeats; i++) {  
43:        result += organic;  
44:      }  
45:        
46:      return result;  
47:    }  

Thursday, July 20, 2017

[Leetcode] Expression Add Operators, Solution


Given a string that contains only digits 0-9 and a target value, return all possibilities to add binary operators (not unary) +-, or *between the digits so they evaluate to the target value.
Examples: 
"123", 6 -> ["1+2+3", "1*2*3"] 
"232", 8 -> ["2*3+2", "2+3*2"]
"105", 5 -> ["1*0+5","10-5"]
"00", 0 -> ["0+0", "0-0", "0*0"]
"3456237490", 9191 -> []

[Thoughts]

这道题除了DFS,我还没想出更好的办法。需要注意的是如何处理*号。每当尝试用*号的时候,要注意处理上一次计算。比如第二个例子 “232”,当处理到2+3的时候,值是5,这时候对于下一个数字2,如果用*号,就得把上一次计算回滚,(5 - 3) + 3*2。

除此之外,没有难点。


[Code]

1:    vector<string> addOperators(string num, int target) {  
2:      vector<string> result;  
3:      if(num.size() == 0) return result;  
4:        
5:      nextStep(num, 0, target, 0, "", 0, result);  
6:      return result;  
7:    }  
8:      
9:    void nextStep(string& numStr, int cur_index, int& target, long value, string equation, long pre_num, vector<string>& result) {  
10:      if(value == target && cur_index == numStr.size()) {  
11:        result.push_back(equation);  
12:        return;  
13:      }  
14:        
15:      for(int i = 1; i< numStr.size() - cur_index +1; i++) {  
16:        if(i >1 && numStr[cur_index] == '0') break;  
17:        string temp = numStr.substr(cur_index, i);  
18:        long num = stol(temp);  
19:          
20:        if(cur_index == 0){  
21:          nextStep(numStr, cur_index +i, target, num, temp, num, result);  
22:          continue;  
23:        }  
24:          
25:        nextStep(numStr, cur_index +i, target, value + num, equation + '+' + temp, num, result);  
26:        nextStep(numStr, cur_index +i, target, value - num, equation + '-' + temp, -num, result);  
27:        nextStep(numStr, cur_index +i, target, value - pre_num + pre_num * num, equation + '*' + temp, pre_num * num, result);  
28:      }  
29:    }  




[Leetcode] Palindrome Pairs, Solution

Given a list of unique words, find all pairs of distinct indices (i, j) in the given list, so that the concatenation of the two words, i.e. words[i] + words[j] is a palindrome.
Example 1:
Given words = ["bat", "tab", "cat"]
Return [[0, 1], [1, 0]]
The palindromes are ["battab", "tabbat"]
Example 2:
Given words = ["abcd", "dcba", "lls", "s", "sssll"]
Return [[0, 1], [1, 0], [3, 2], [2, 4]]
The palindromes are ["dcbaabcd", "abcddcba", "slls", "llssssll"]


[Thoughts]

这题不难,找的是words[i] + words[j]是个palindrome。找两个例子就可以清晰的分析出规律来。

比如 “sssll”这个词,如果把这个词从中间切成两块, 就是 “ss” + “sll”。 ss本身就是palindrome,而“sll”的翻转就是字典里的“lls”

所以对于任意一个词,我们总是可以在其中任意一个位置K把它一切为二:



那么对于可能的candidate只有情况:

  1. left 是 palindrome,那么可能的组合是 candidate | left | right,candidate就是right的翻转
  2. right 是palindrome, 那么可能的组合是 left | right | candidate, 而这里candidate是left的翻转

所以,一开始有个hashmap,把翻转的字符串保存下来,这样在后面切字符串的时候,方便查询即可。

[Code]


1:    vector<vector<int>> palindromePairs(vector<string>& words) {  
2:      unordered_map<string, int> dict;  
3:      set<vector<int>> result;  
4:      for(int i =0; i< words.size(); i++) {  
5:        string word = words[i];  
6:        reverse(word.begin(), word.end());  
7:        dict[word] = i;  
8:      }  
9:      for(int i =0; i< words.size(); i++) {  
10:        string word = words[i];  
11:        // 切字符串三种情况,最左边切,中间切,和最右边切。   
12:        //注意,这里j<= word.size()为了cover最右边切这种情况  
13:        for(int j = 0; j<=word.size(); j++) {  
14:          string left = word.substr(0, j);  
15:          string right = word.substr(j, word.size() - j);  
16:          // candi | left | right  
17:          if(isPalindro(left) && dict.find(right) != dict.end() && dict[right] != i) {  
18:            result.insert({dict[right], i});  
19:          }  
20:          // left | right | candi  
21:          if(isPalindro(right) && dict.find(left) != dict.end() && dict[left] != i) {  
22:            result.insert({i, dict[left]});  
23:          }  
24:        }   
25:      }  
26:      std::vector<vector<int>> output(result.begin(), result.end());   
27:      return output;  
28:    }  
29:    bool isPalindro(string& str) {  
30:      int left = 0, right = str.size() -1;  
31:      while(left < right) {  
32:        if(str[left++] != str[right--]) return false;  
33:      }  
34:      return true;  
35:    }  



Saturday, October 17, 2015

[Leetcode] Valid Anagram, Solution

Given two strings s and t, write a function to determine if t is an anagram of s.
For example,
s = "anagram", t = "nagaram", return true.
s = "rat", t = "car", return false.
Note:
You may assume the string contains only lowercase alphabets.
[Thoughts]
对于字符出现次数做个统计就好了。因为只有26个小写字母,所以可以建立一个大小为26的索引数组charcount,用来统计每个字符的出现次数。
对于s, 将其作为字符数组进行遍历,在遍历的过程中,对每个出现的字符计数加一。
对于t, 同样将其遍历,对每个出现的字符计数减一。
如果s和t是anagram , 那么最后的charcount数组中所有字符的计数都应该是0, 否则就不是anagram。

[Code]
1:  class Solution {  
2:  public:  
3:    bool isAnagram(string s, string t) {  
4:      vector<int> charcount(26, 0);  
5:      for(int i =0; i< s.length(); i++) {  
6:        charcount[s[i] - 'a'] ++;  
7:      }  
8:      for(int i =0; i< t.length(); i++) {  
9:        charcount[t[i] - 'a'] --;  
10:      }  
11:      for(int i =0; i<charcount.size(); i++) {  
12:        if(charcount[i] != 0) {  
13:          return false;  
14:        }  
15:      }  
16:      return true;  
17:    }  
18:  };  

Monday, January 7, 2013

[LeetCode] Substring with Concatenation of All Words 解题报告


You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.
For example, given:
S"barfoothefoobarman"
L["foo", "bar"]
You should return the indices: [0,9].
(order does not matter).
» Solve this problem

[解题思路]
没想出什么太好的办法,猜测这题应该是一道实现题。用两个map来统计字符串的出现次数,然后从左往右扫描主字符串。


[Code]
1:    vector<int> findSubstring(string S, vector<string> &L) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      map<string, int> expectCount;  
5:      map<string, int> realCount;  
6:      for(int i =0; i< L.size(); i++)  
7:      {  
8:        expectCount[L.at(i)]++;  
9:      }  
10:      vector<int> result;  
11:      int row = L.size();  
12:      if(row ==0) return result;  
13:      int len = L[0].size();  
14:      for(int i =0; i< (int)S.size() - row*len+1; i++)  
15:      {  
16:        realCount.clear();  
17:        int j =0;  
18:        for(; j< row; j++)  
19:        {  
20:          string sub = S.substr(i+j*len, len);  
21:          if(expectCount.find(sub) != expectCount.end())  
22:          {  
23:            realCount[sub]++;  
24:          }  
25:          else  
26:            break;  
27:          if(realCount[sub] > expectCount[sub])  
28:          {  
29:            break;  
30:          }  
31:        }  
32:        if(j == row)  
33:          result.push_back(i);  
34:      }  
35:      return result;  
36:    }  

[注意]
Line 14 红字部分。如果S.size()是unsigned int,如果不先转换为int的话,计算结果会被promote成unsigned int。 比如 (unsigned int) 1 - (int)2, 最后的结果不是-1,而是4294967295。



Thursday, December 27, 2012

[LeetCode] Minimum Window Substring 解题报告


Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
For example,
S = "ADOBECODEBANC"
T = "ABC"
Minimum window is "BANC".
Note:
If there is no such window in S that covers all characters in T, return the emtpy string "".
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
» Solve this problem

[解题报告]
双指针,动态维护一个区间。尾指针不断往后扫,当扫到有一个窗口包含了所有T的字符后,然后再收缩头指针,直到不能再收缩为止。最后记录所有可能的情况中窗口最小的

[Code]
1:    string minWindow(string S, string T) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:         if(S.size() == 0) return "";  
5:            if(S.size() < T.size()) return "";            
6:            int appearCount[256];  
7:            int expectCount[256];  
8:            memset(appearCount, 0, 256*sizeof(appearCount[0]));  
9:            memset(expectCount, 0, 256*sizeof(appearCount[0]));  
10:            for(int i =0; i < T.size(); i++)  
11:            {  
12:                 expectCount[T[i]]++;                 
13:            }  
14:            int minV = INT_MAX, min_start = 0;  
15:            int wid_start=0;  
16:            int appeared = 0;   
17:            for(int wid_end = 0; wid_end< S.size(); wid_end++)  
18:            {  
19:                 if(expectCount[S[wid_end]] > 0)// this char is a part of T  
20:                 {  
21:                      appearCount[S[wid_end]]++;  
22:                      if(appearCount[S[wid_end]] <= expectCount[S[wid_end]])  
23:                           appeared ++;                      
24:                 }  
25:                 if(appeared == T.size())  
26:                 {                 
27:                      while(appearCount[S[wid_start]] > expectCount[S[wid_start]]   
28:                      || expectCount[S[wid_start]] == 0)  
29:                      {  
30:                           appearCount[S[wid_start]]--;  
31:                           wid_start ++;  
32:                    }                      
33:                      if(minV > (wid_end - wid_start +1))  
34:                      {  
35:                           minV = wid_end - wid_start +1;  
36:                           min_start = wid_start;  
37:                      }  
38:                 }                 
39:            }  
40:      if(minV == INT_MAX) return "";  
41:            return S.substr(min_start, minV);      
42:    }  

[已犯错误]
1. Line 8&9
不熟悉这个api,最初写成了

memset(expectCount, 0, 256);

结果老是出问题,检查了很多遍logic,也没发现有问题,最后还是放到VS下debug才发现原来是地址空间大小没有传对。正确的应该是:

memset(expectCount, 0, 256*sizeof(appearCount[0]));






Monday, December 24, 2012

[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.
» Solve this problem

[解题思路]
从左往右扫描,当遇到重复字母时,以上一个重复字母的index +1,作为新的搜索起始位置。比如

直到扫描到最后一个字母。


[Code]
Version 1
1:    int lengthOfLongestSubstring(string s) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      int count[26];  
5:      if(s.size() ==0) return 0;  
6:      memset(count,-1, sizeof(count));  
7:      int start = 0;  
8:      int maxV = 0;  
9:      for(int i=0; i< s.size(); i++)  
10:      {  
11:        int index = s[i] - 97;  
12:        if(count[index] >= 0)  
13:        {            
14:          if(maxV < (i -start))  
15:          {  
16:            maxV = i-start;  
17:          }  
18:          i = count[index];  
19:          start = i+1;  
20:          memset(count,-1, sizeof(count));  
21:          continue;  
22:        }  
23:        count[index] = i;  
24:      }  
25:      if(maxV < (s.size() -start))  
26:      {  
27:        maxV = s.size()-start;  
28:      }  
29:      return maxV;  
30:    }  


Version 2, refactor the code at 3/4/2013
1:       int lengthOfLongestSubstring(string s) {  
2:            int count[26];  
3:            memset(count, -1, 26*sizeof(int));  
4:            int len=0, maxL = 0;  
5:            for(int i =0; i< s.size(); i++,len++)  
6:            {  
7:                 if(count[s[i]-'a']>=0)  
8:                 {  
9:                      maxL = max(len, maxL);  
10:                      len =0;          
11:                      i = count[s[i]-'a']+1;  
12:                      memset(count, -1, 26*sizeof(int));   
13:                 }  
14:                 count[s[i]-'a']=i;  
15:            }      
16:            return max(len, maxL);  
17:       }  

Note:
1. Line 3, since we store the index in array, so initializing the array as 0 will mistake the logic.
2. Line 16, catch the last string. for example, "abcd", if no Line 16, it will just return 0 since the Line 9 won't be triggered.

[LeetCode] Longest Palindromic Substring 解题报告


Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
» Solve this problem

[解题思路]
O(n*n)。对于每一个字符,以之作为中间元素往左右寻找。注意处理奇偶两种模式:
1. aba
2. abba

1:  string longestPalindrome(string s) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      int startIndex = 0;  
5:      int len = 0;            
6:      int sI,eI;  
7:      for(int i =0; i< s.size() -1; i++)  
8:      {  
9:           if(s[i] == s[i+1])  
10:          {  
11:               sI = i;  
12:               eI = i+1;  
13:               Search(s, sI, eI, len, startIndex);  
14:          }  
15:          sI = i;  
16:          eI = i;  
17:          Search(s, sI, eI, len, startIndex);  
18:      }       
19:      if(len == 0)  
20:        len = s.size();  
21:      return s.substr(startIndex, len);  
22:    }  
23:    void Search(string&s, int sI, int eI, int&len, int& startIndex)  
24:    {  
25:      int step = 1;   
26:      while((sI-step)>=0&& (eI+step)<s.size())  
27:      {  
28:        if(s[sI-step] != s[eI+step])  
29:        {       
30:          break;  
31:        }                      
32:        step++;  
33:      }  
34:      int wid = eI- sI+2*step -1;  
35:      if(wid > len)  
36:      {  
37:        len = wid;  
38:        startIndex = sI - step+1;   
39:      }  
40:    }  

此题也有O(n)解法。相当巧妙,http://www.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html


Version2: add DP solution, 3/5/2013
定义函数
P[i,j] = 字符串区间[i,j]是否为palindrome.

首先找个例子,比如S="abccb",
    S=    a  b  c  c  b
Index = 0  1  2  3  4

P[0,0] =1  //each char is a palindrome
P[0,1] =S[0] == S[1]    , P[1,1] =1
P[0,2] = S[0] == S[2] && P[1,1], P[1,2] = S[1] == S[2] , P[2,2] = 1
P[0,3] = S[0] == S[3] && P[1,2], P[1,3] = S[1] == S[3] && P[2,2] , P[2,3] =S[2] ==S[3],  P[3,3]=1      
......................
由此就可以推导出规律

P[i,j] = 1  if i ==j
        =  S[i] ==S[j]   if j = i+1
        =  S[i] == S[j] && P[i+1][j-1]  if j>i+1

实现如下:
1:       string longestPalindrome(string s) {  
2:            int len = s.size();  
3:            int P[len][len];  
4:            memset(P, 0, len*len*sizeof(int));  
5:            int maxL=0, start=0, end=0;  
6:            for(int i =0; i< s.size(); i++)  
7:            {  
8:                 for(int j =0; j<i; j++)  
9:                 {  
10:                      P[j][i] = (s[j] == s[i] && (i-j<2 || P[j+1][i-1]));  
11:                      if(P[j][i] && maxL < (i-j+1))  
12:                      {  
13:                           maxL = i-j+1;  
14:                           start = j;  
15:                           end = i;  
16:                      }  
17:                 }  
18:                 P[i][i] =1;  
19:            }  
20:            return s.substr(start, end-start +1);  
21:       }  






[LeetCode] Longest Common Prefix 解题报告


Write a function to find the longest common prefix string amongst an array of strings.
» Solve this problem

[解题报告]
又一个实现题。遍历字符串数组,每次用当前prefix和下一个字符串匹配以生成新的prefix。

[Code]
1:    string longestCommonPrefix(vector<string> &strs) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      string compare;  
5:      if(strs.size() == 0) return compare;  
6:      compare = strs[0];  
7:      for(int i =1; i< strs.size() ; i++)  
8:      {  
9:        string prefix;  
10:        int k =0;  
11:        while(k< compare.size() && k< strs[i].size())  
12:        {  
13:          if(compare[k] != strs[i][k])  
14:            break;  
15:          prefix.append(1, compare[k]);  
16:          k++;  
17:        }  
18:        compare.clear();  
19:        compare.append(prefix.c_str());        
20:      }  
21:      return compare;  
22:    }  

另一个直观的解法就是对于每一个字母比较所有字符串,直到遇到任何一个不匹配。这个时间复杂度比上一个解法好一些,避免了不必要的比较。

1:    string longestCommonPrefix(vector<string> &strs) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      string prefix;  
5:      if(strs.size() ==0) return prefix;  
6:      int k=0;  
7:      while(1)  
8:      {  
9:        if(k == strs[0].size()) break;  
10:        char p = strs[0][k];  
11:        int i =1;  
12:        for(; i< strs.size(); i++)  
13:        {  
14:          if(k==strs[i].size()) break;  
15:          if(p != strs[i][k])  
16:            break;  
17:        }  
18:        if(i != strs.size())  
19:          break;  
20:        prefix.append(1,p);  
21:        k++;  
22:      }  
23:      return prefix;  
24:    }  

Update 2, 3/7/2013
refactor code  a bit
1:     string longestCommonPrefix(vector<string> &strs) {  
2:            string prefix;  
3:            if(strs.size() ==0) return prefix;  
4:            int len =0;  
5:            while(1)  
6:            {  
7:                 char var;  
8:                 int i=0;  
9:                 for(; i< strs.size(); i++)  
10:                 {  
11:                      if(i ==0) var =strs[0][len];  
12:                      if(strs[i].size() == len || var != strs[i][len])  
13:                      break;  
14:                 }  
15:                 if(i!= strs.size())  
16:                      break;                 
17:                 len++;  
18:                 prefix.append(1, var);  
19:            }  
20:            return prefix;  
21:       }  

[Leetcode] Length of Last Word 解题报告


Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the length of last word in the string.
If the last word does not exist, return 0.
Note: A word is defined as a character sequence consists of non-space characters only.
For example,
Given s = "Hello World",
return 5.
» Solve this problem

[解题思路]
这题完全是实现题。没有算法难度。从最后往前扫描。处理如下三种模式:(*表示若干个空格)
1. "*"
2. "*word"
3. "*word*"
4. "word*"

1:    int lengthOfLastWord(const char *s) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      int len = strlen(s);  
5:      if( len== 0) return 0;  
6:      int i = len-1;  
7:      while(s[i] == ' ' && i>=0) i--;  
8:      if(i == -1)   
9:      {  
10:        return 0;  
11:      }  
12:      int end = i;  
13:      for(; i >=0; i--)  
14:      {  
15:        if(s[i] == ' ')  
16:          break;  
17:      }  
18:      if(i ==-1)  
19:        return end+1;  
20:      return end-i;  
21:    }  

[已犯错误]
1. Line 8, 18。 一开始写成i ==0了,当模式2及模式3时就算不对了。

Update 3/15/2013: refactor code

1:       int lengthOfLastWord(const char *s) {  
2:            int len = strlen(s);  
3:            int count = 0;  
4:            for(int i =len-1; i>=0; i--)  
5:            {  
6:                 if(s[i] == ' ')  
7:                 {  
8:                      if(count ==0) continue;  
9:                      else return count;  
10:                 }  
11:                 count++;  
12:            }  
13:            return count;  
14:       }  


Update 4/7/2013:Refactor Code
上面的解法多跑了一趟,没有必要。这一题期待的解法应该是从左到右只扫描一遍。不过上面解法的好处是写起来很简洁、漂亮。。。
1:       int lengthOfLastWord(const char *s) {  
2:            const char *p =s;  
3:            const char *start=p;  
4:            int len=0;  
5:            while(*p!='\0')  
6:            {  
7:                 if(*p == ' ')  
8:                 {  
9:                      len = p - start;  
10:                      while(*p == ' ') p++;  
11:                      start = p;   
12:                      continue;  
13:                 }  
14:                 p++;                 
15:            }  
16:            if(*start !='\0')  
17:                 len = p-start;  
18:            return len;  
19:       }  



Update 08/24/2014 Refactor Code
Another way to track the length of word

1:       int lengthOfLastWord(const char *s) {  
2:            const char* pStart=s;  
3:            const char* pEnd=s;  
4:            const char* p = s;  
5:            const char* pre=s;  
6:            while(*p!='\0')  
7:            {  
8:                 if(*pre == ' ' && *p !=' ') pStart = p;  
9:                 if(*pre != ' ' && *p == ' ') pEnd = p;  
10:                 pre = p;  
11:                 p++;  
12:            }  
13:            if(*pre != ' ' && *p == '\0') pEnd = p;  
14:            return pEnd - pStart;  
15:       }  



Sunday, December 23, 2012

[LeetCode] Interleaving String 解题报告


Given s1s2s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 = "aabcc",
s2 = "dbbca",
When s3 = "aadbbcbcac", return true.
When s3 = "aadbbbaccc", return false.
» Solve this problem

[解题思路]
第一个想法是merge sort或许可以做。
1:   bool isInterleave(string s1, string s2, string s3) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function    
4:      if(s3.size() != (s1.size() + s2.size()))  
5:      {  
6:        return false;  
7:      }  
8:      int i =0, j= 0, k=0;  
9:      while(i< s1.size() && j< s2.size())  
10:      {  
11:        if(s1[i] == s3[k])  
12:        {  
13:          i ++;  
14:        }  
15:        else if(s2[j] == s3[k])  
16:        {  
17:          j++;  
18:        }  
19:        else  
20:        {  
21:          return false;  
22:        }  
23:        k++;  
24:      }  
25:      while(i< s1.size())  
26:      {  
27:        if(s1[i] == s3[k])  
28:        {  
29:          i++;k++;  
30:        }  
31:        else  
32:        {  
33:          return false;  
34:        }  
35:      }  
36:      while(j<s2.size())  
37:      {  
38:        if(s2[j] == s3[k])  
39:        {  
40:          j++;k++;  
41:        }  
42:        else  
43:        {  
44:          return false;  
45:        }  
46:      }  
47:      return true;  
48:    }  

但是merge sort没法考虑两个字符串的组合顺序问题。当处理{"C","CA", "CAC"}的时候,就不行了。

最后还是得用DP。对于
s1 = a1, a2 ........a(i-1), ai
s2 = b1, b2, .......b(j-1), bj
s3 = c1, c3, .......c(i+j-1), c(i+j)

定义 match[i][j] 意味着,S1的(0, i)和S2的(0,j),匹配与S3的(i+j)
如果 ai == c(i+j), 那么 match[i][j] = match[i-1][j], 等价于如下字符串是否匹配。

s1 = a1, a2 ........a(i-1)
s2 = b1, b2, .......b(j-1), bj
s3 = c1, c3, .......c(i+j-1)

同理,如果bj = c(i+j), 那么match[i][j] = match[i][j-1];

所以,转移方程如下:
Match[i][j]
    =   (s3.lastChar == s1.lastChar) && Match[i-1][j]
      ||(s3.lastChar == s2.lastChar) && Match[i][j-1]
初始条件:
    i=0 && j=0时,Match[0][0] = true;
    i=0时, s3[j] = s2[j], Match[0][j] |= Match[0][j-1]
           s3[j] != s2[j], Match[0][j] = false;

    j=0时, s3[i] = s1[i], Match[i][0] |= Match[i-1][0]
           s3[i] != s1[i], Match[i][0] = false;


[Code]
1:    bool isInterleave(string s1, string s2, string s3) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function    
4:      bool *matchUp = new bool[s2.size() +1];  
5:      bool *matchDown = new bool[s2.size()+1];  
6:      if(s3.size() != (s1.size() + s2.size())) return false;  
7:      //initialize  
8:      matchDown[0] = true;  
9:      for(int i =1; i< s2.size() +1; i++)  
10:      {  
11:        if(s2[i-1] == s3[i-1])  
12:          matchDown[i] |= matchDown[i-1];  
13:        else  
14:          matchDown[i]= false;  
15:      }  
16:      matchUp[0] = true;  
17:      for(int i =1; i< s1.size() +1; i++)  
18:      {  
19:        if(s1[i-1] == s3[i-1])  
20:          matchUp[0] |= matchDown[0];  
21:        else  
22:          matchUp[0]= false;  
23:        for(int j =1;j<s2.size() +1; j++)  
24:        {  
25:          matchUp[j]=false;  
26:          if(s1[i-1] == s3[i+j-1])  
27:          {  
28:            matchUp[j] |= matchDown[j];  
29:          }  
30:          if(s2[j-1] == s3[i+j-1])  
31:          {  
32:            matchUp[j] |= matchUp[j-1];  
33:          }  
34:        }  
35:        bool* temp = matchUp;  
36:        matchUp = matchDown;  
37:        matchDown = temp;        
38:      }  
39:      return matchDown[s2.size()];  
40:    }  

[总结]
代码实现中注意初始条件即可。用二维数组实现也可,只是浪费点空间。

代码中有个bug,程序结束时,忘了删除数组。 应该加上Delete matchUp; Delete MatchDown;  写惯了C#,再用c++,老是往最后的清理工作。

Saturday, December 22, 2012

[LeetCode] Implement strStr() 解题报告


Implement strStr().
Returns a pointer to the first occurrence of needle in haystack, or null if needle is not part of haystack.
» Solve this problem


[解题思路]
时间复杂度线性的解法明显是KMP算法,但是早忘了具体实现了。简单写一个普通的解法。

Update: add a KMP implementation in the end.

[Code]
1:    char *strStr(char *haystack, char *needle) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      if(haystack == NULL || needle == NULL)  
5:        return NULL;  
6:      int hLen = strlen(haystack);  
7:      int nLen = strlen(needle);  
8:      if(hLen<nLen)  
9:        return NULL;  
10:      for(int i=0; i<hLen - nLen+1; i++)  
11:      {  
12:        int j=0;  
13:        char* p = &haystack[i];  
14:        for(; j< nLen; j++)  
15:        {  
16:          if(*p != needle[j])  
17:            break;  
18:          p++;  
19:        }  
20:        if(j == nLen)  
21:          return &haystack[i];  
22:      }  
23:      return NULL;  
24:    }  


[注意]
1. Line 10, 循环的结束应该是hLen-nLen+1,减少不必要运算。
2. Line18, 好久没写指针操作,忘了递增p指针。


增加一个KMP实现, 算法请参考算法导论第32章。

1:    char *strStr(char *haystack, char *needle) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      if(haystack == NULL || needle == NULL) return NULL;  
5:         int hlen = strlen(haystack);  
6:      int nlen = strlen(needle);  
7:      if(nlen ==0) return haystack;  
8:      if(hlen == 0 ) return NULL;  
9:      int pattern[100000];  
10:      GeneratePattern(needle, nlen, pattern);  
11:      return Match(haystack, needle, pattern);  
12:    }  
13:    void GeneratePattern(char* str, int len, int* pattern)  
14:    {  
15:      pattern[0] = -1;  
16:      int k =-1;  
17:      for(int j =1; j< len; j++)  
18:      {  
19:        while(k >-1 && str[k+1] != str[j])  
20:          k = pattern[k];  
21:        if(str[k+1] == str[j])  
22:          k++;  
23:        pattern[j] = k;  
24:      }  
25:    }  
26:    char* Match(char* haystack, char* needle, int* pattern)  
27:    {  
28:      int hlen = strlen(haystack);  
29:      int nlen = strlen(needle);      
30:      int k =-1;  
31:      for(int j =0; j< hlen; j++, haystack++)  
32:      {  
33:        while(k >-1 && needle[k+1] != *haystack)  
34:          k = pattern[k];  
35:        if(needle[k+1] == *haystack)  
36:          k++;  
37:        if(k == nlen-1)  
38:          return haystack-k;  
39:      }  
40:            return NULL;  
41:    }