Longest Common Prefix
Write a function to find the longest common prefix string amongst an array of strings.
直观的想法是弄个while(true)循环,然后遍历array,每遍历一次取出来一个字符,直到取出来的字符不是共有的为止(后面会看到这种其实是最好的,避免了很多重复计算)。也可以不要每次只取出来一个字符,而采用二分法去搜索分割点(引入了很多重复计算)。
"""1. LCP(S1,S2,...,Sn)=LCP(LCP(LCP(S1,S2),S3),...,Sn)
6 ms, beats 24.06%
时间复杂度:O(S),S是vector中字符总数
空间复杂度:O(1)
"""
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// A Utility Function to find the common prefix between
// strings- str1 and str2
string lcp2(string str1, string str2)
{
string result;
int n1 = str1.length(), n2 = str2.length();
// Compare str1 and str2
for (int i = 0, j = 0; i <= n1 - 1 && j <= n2 - 1; i++, j++)
{
if (str1[i] != str2[j])
break;
result.push_back(str1[i]);
}
return (result);
}
string longestCommonPrefix(vector<string>& strs) {
if (strs.size() == 0) //careful
return "";
string result = *(strs.begin());
for (vector<string>::iterator it = strs.begin(); it != strs.end(); ++it){
result = lcp2(result, *it);
}
return result;
}
int main(){
cout << lcp2("", "abc") << endl;
cout << lcp2("ab", "abc") << endl;
cout << lcp2(lcp2("", "abc"), "abc") << endl;
vector<string> strs = { "abc", "ab" ,"a"};
string result = longestCommonPrefix(strs);
cout << result << endl;
vector<string> strs2 = { "", "ab", "a" };
string result2 = longestCommonPrefix(strs2);
cout << result2 << endl;
vector<string> strs3 = {};
string result3 = longestCommonPrefix(strs3);
cout << result3 << endl;
system("pause");
return 0;
}
"""2. Vertical scanning
就是一开始我们说的那个直观的想法,弄个while(true)循环,然后遍历array,每遍历一次取出来一个字符,直到取出来的字符不是共有的为止。
时空复杂度与1相同,但是in the best case there are at most n*minLenn comparisons where minLen is the length of the shortest string in the array.
下面是一个比较紧凑的写法,6 ms,和前面的代码一样。
"""
string longestCommonPrefix(vector<string>& strs) {
string prefix = "";
for(int idx=0; strs.size()>0; prefix+=strs[0][idx], idx++)
for(int i=0; i<strs.size(); i++)
if(idx >= strs[i].size() ||(i > 0 && strs[i][idx] != strs[i-1][idx]))
return prefix;
return prefix;
}
"""3, Binary search
参见一开始的直观想法。
时间复杂度是O(S∗log(m)),比前面两种都要大。log(m)是二分查找的次数,最坏情况时每个字符串的长度都是m。每次二分查找要做的比较是S次。
时间复杂度增大了,原因是每次二分查找做的比较有很多重复(如看前k个是不是cp,然后又要看前k+k'个是不是cp,这里面有k个字符都是重复的),所以还不如不用二分查找,直接一个位置一个位置逐个查找。
空间复杂度O(1)。
"""
"""4, Divide and conquer
在这个问题中并不是最好的,2中简单的方案是最好的。但是我们趁机复习一下分而治之。
T(n)=2T(n/2)+O(m), T(2)=O(m)
T(4)=2T(2)+O(m)=O(3m)
T(8)=O(7m)
通过简单的递推解得T(n)=O(nm)=O(S)
空间复杂度O(m*log(n)),原因是在log(n)次递归调用中,每次要用O(m)来保存计算结果以便返回来整合。
"""
Valid Parentheses
Given a string containing just the characters ‘(‘, ‘)’, ‘{‘, ‘}’, ‘[’ and ‘]’, determine if the input string is valid.
The brackets must close in the correct order, “()” and “()[]{}” are all valid but “(]” and “([)]” are not.
先自己思考一下。
([)]
[(]
可以弄个链表,存三种节点代表三种括号。然后遍历字符串,每遇到一个左括号就增加一个相应节点,每遇到一个右括号就看最后一个位置是不是该括号,如是则删除该节点,否则return false。最后遍历完了节点刚好全被删除,return true。
时间复杂度O(n),n是字符串长度
空间复杂度O(n)
"""1. 看一下discussion,有个用栈(stack)实现的,思路和上面一致。
3 ms, beats 6.94%
"""
bool isValid(string s) {
stack<char> paren;
for (char& c : s) {
switch (c) {
case '(':
case '{':
case '[': paren.push(c); break;
case ')': if (paren.empty() || paren.top()!='(') return false; else paren.pop(); break;
case '}': if (paren.empty() || paren.top()!='{') return false; else paren.pop(); break;
case ']': if (paren.empty() || paren.top()!='[') return false; else paren.pop(); break;
default: ; // pass
}
}
return paren.empty() ;
}