leetcode 14, 38, 345

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".

这道题其实思路和实现大都非常简单。总结出来只是为了让自己熟悉一种string对象的函数用法和功能。本题要翻转字符串中的元音字母,因此设置两个下表low 和high。一个初始化在开头,一个初始化在末尾,接着两个都往中间靠拢,遇到元音字母则停下来交换彼此的位置,直到low >= high。

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;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值