14. Longest Common Prefix
Write a function to find the longest common prefix string amongst an array of strings.
这道题思路比较直观,实现也比较简单。题目要从一堆字符串中找出所有字符串的公共最长前缀。
要找出所有字符串的公共最长前缀,那么我们可以先找出前两个字符串的公共最长前缀,在用这个公共前缀与剩下的字符串一起比较,一旦公共前缀变为“”了,就直接返回“”,因为“”与任何字符串的公共前缀都是“”,不用再往下比较了。根据这个思路可以实现代码:
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if (strs.size() == 0)
return "";
if (strs.size() == 1)
return strs[0];
string res = longestInTow(strs[0], strs[1]);
for (int i = 2; i < strs.size(); i++){
res = longestInTow(res, strs[i]);
if (res == "")
return res;
}
return res;
}
string longestInTow(string pre, string below){
if (pre == "" || below == "")
return "";
int i = 0;
string res = "";
while (i < pre.size() && i < below.size() && pre[i] == below[i]){
res += pre[i];
i++;
}
return res;
}
};
然后还有另外一种角度的思路,应该了解掌握。我们刚才的思路是一个一个字符串的比较,来找到所有字符串的最长公共前缀。那么我们可不可以一个字符一个字符的比较呢?我们首先看所有字符串的第一个字符,一旦他们不完全相同,那么就可以直接返回“”了,否则则看所有字符串的第二个字符,以此类推。这样的话,在面对字符串数目比较多儿每个字符串中的字符数目比较少的情况时,会非常方便。
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if (strs.size() == 0)
return "";
string res = "";
string compare = strs[0];
for (int i = 0; i < compare.size(); i++){
for (int j = 1; j < strs.size(); j++){
if (strs[j][i] != strs[0][i])
return res;
}
res += compare[i];
}
return res;
}
};
问题的关键在于i 和j 的值要想清楚。i 代表这次比较的是第几个字符,j 代表这次是第几个字符串参与比较。
38. Count and Say
The count-and-say sequence is the sequence of integers beginning as follows:
1, 11, 21, 1211, 111221, ...
1
is read off as "one 1"
or 11
.
11
is read off as "two 1s"
or 21
.
21
is read off as "one 2
, then one 1"
or 1211
.
Given an integer n, generate the nth sequence.
Note: The sequence of integers will be represented as a string.
这道题主要在于弄清题意,如果我们多写几个出来,那么思路就会清晰一些。如题所述,序列应该是:1, 11, 21, 1211, 111221, 312211, 13122221, 1113114211, 311321141221。。。。。。
可以看出,i + 1个序列相当于“读出”第i 个数。根据这个特点,对于输入的数字n ,我们只能依次的从第一个、第二个、第三个开始计算一直到第n个。怎么计算呢?
假设cur是第i 个数,怎么计算i + 1呢?我们设立一个下标start, 如果s[start] == s[start + 1],那么计数器count ++,start ++,直到s[start] != s[start + 1],此时,我们将count 和s[start]填入nex之中,然后继续start 直到结束。这样,就能够使每个数的次数出现在前,本身出现在后。思路并不复杂,关键在于逻辑要清楚,不能乱。
class Solution {
public:
string countAndSay(int n) {
if (n <= 0)
return "";
string result = "1";
while (n > 1){
string cur = "";
for (int i = 0; i < result.size(); i++){
int count = 1;
while (i + 1 < result.size() && result[i] == result[i + 1]){
count ++;
i ++;
}
cur += to_string(count) + result[i];
}
result = cur;
n --;
}
return result;
}
};
345. Reverse Vowels of a String
Write a function that takes a string as input and reverse only the vowels of a string.
Example 1:
Given s = "hello", return "holle".
Example 2:
Given s = "leetcode", return "leotcede".
class Solution {
public:
string reverseVowels(string s) {
int low = 0;
int high = s.size() - 1;
while (low < high){
while (low < high && !isVowel(s[low]))
low ++;
while (low < high && !isVowel(s[high]))
high--;
swap(s[low ++], s[high --]);
}
return s;
}
bool isVowel(char input){
return input == 'a' || input == 'e' || input == 'i' || input == 'o' || input == 'u'
|| input == 'A' || input == 'E' || input == 'I' || input == 'O' || input == 'U';
}
};
以上实现中要注意 swap(s[low ++], s[high --]),其中的++和--一定不能忘记,如果写成了 swap(s[low], s[high]),那么在交换了两个元音字符后,下标就没有改变,那么再次检测的结果还是交换这两个字符,从而导致死循环。因此此处一定不能忘记++和--。
本题基于这种思路还有一种实现,可以使用find_first_of和find_last_of。s.find_first_of(vowels, low)表示在s字符串的low位置开始查找vowels字符串中任意一个字符在s字符串中第一次出现的位置。s.find_last_of(vowels, high)表示到s字符串的high位置为止查找vowels字符串中任意一个字符在s字符串中最后一次出现的位置。那么我们可以通过不断调用这两个函数,来不断缩小查找范围。以这样的方式来交换字符串。
class Solution {
public:
string reverseVowels(string s) {
int low = 0;
int high = s.size() - 1;
string vowels = "aeiouAEIOU";
while (low < high){
low = s.find_first_of(vowels, low);
high = s.find_last_of(vowels, high);
if (low < high)
swap(s[low ++], s[high --]);
}
return s;
}
};
459. Repeated Substring Pattern
Given a non-empty string check if it can be constructed by taking a substring of it and appending multiple copies of the substring together. You may assume the given string consists of lowercase English letters only and its length will not exceed 10000.
Input: "abab" Output: True Explanation: It's the substring "ab" twice.
Input: "abcabcabcabc" Output: True Explanation: It's the substring "abc" four times. (And the substring "abcabc" twice.)
这道题就是看字符串是否是由自己的某一个子串不断循环而生成的。首先要想清楚这一点。想到了这点,那么采用什么方法检测呢?应该只能依次检测,即第一次认为字符串以第一个字符循环出现,然后一个字符一个字符依次判定比较,如果到最后都一样则返回真;否则,就以两个字符串进行比较。直到每次选取的字符数>=原字符串长度的一半,那么我们有必要从1,2。。。一直到length / 2每次都判断吗?没有必要。因为如果要整个字符串都是某一个子串循环组成,那么这个子串的长度一定能被整个字符串的长度整除。
想清楚了这一点,那么思路就来了。从i = 1开始,一直到i <= lelngth / 2,如果length % i== 0,就判断整个字符串是否是以从0-i-1的子串循环生成的即可。那么怎样判断就是关键了。
我们这样看,假设重复取得子串是a,那么满足条件的情况下原始字符串的组成应该是aAa,其中A可以是“”,否则的话就是a重复数次的结果,也就是说A的结构也是aA'a,这也就是说,对整个字符串s,s.substr(i,length)和s.substr(0,length-i)应该是相同的!这就是区分是否满足该模式的条件,一定要想清楚,理解透彻!
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int n = s.length();
for (int i = 1; i <= n / 2; i++)
if (n % i == 0 && s.substr(i) == s.substr(0, n - i))
return true;
return false;
}
};