Tag Archives: 字符串

LeetCode Compare Version Numbers

165. Compare Version Numbers

Compare two version numbers version1 and version2.
If version1 > version2 return 1; if version1 < version2 return -1;otherwise return 0.

You may assume that the version strings are non-empty and contain only digits and the . character.

The . character does not represent a decimal point and is used to separate number sequences.

For instance, 2.5 is not “two and a half” or “half way to version three”, it is the fifth second-level revision of the second first-level revision.

You may assume the default revision number for each level of a version number to be 0. For example, version number 3.4 has a revision number of 3 and 4 for its first and second level revision number. Its third and fourth level revision number are both 0.

Example 1:

Input: version1 = "0.1", version2 = "1.1"
Output: -1

Example 2:

Input: version1 = "1.0.1", version2 = "1"
Output: 1

Example 3:

Input: version1 = "7.5.2.4", version2 = "7.5.3"
Output: -1

Example 4:

Input: version1 = "1.01", version2 = "1.001"
Output: 0
Explanation: Ignoring leading zeroes, both “01” and “001" represent the same number “1”

Example 5:

Input: version1 = "1.0", version2 = "1.0.0"
Output: 0
Explanation: The first version number does not have a third level revision number, which means its third level revision number is default to "0"

Note:

  1. Version strings are composed of numeric strings separated by dots . and this numeric strings may have leading zeroes.
  2. Version strings do not start or end with dots, and they will not be two consecutive dots.

本题要求比较两个版本号的大小。简单题,按点.分隔,然后转换为int依次比较就好。 为了防止有的版本号没有点.,开始先给两个版本号末尾添加上一个点。另外1.0和1这两个版本号是相等的,所以如果版本位数有差别时,需要补0,而不是简单的认为长的比短的大。 完整代码如下:

class Solution {
public:
    int compareVersion(string version1, string version2)
    {
        version1 += ".";
        version2 += ".";
        size_t p1 = version1.find(‘.’), p2 = version2.find(‘.’);
        int v1, v2;
        while (p1 != string::npos || p2 != string::npos) {
            if (p1 == string::npos)
                v1 = 0;
            else {
                v1 = atoi(version1.substr(0, p1).c_str());
                version1 = version1.substr(p1 + 1);
                p1 = version1.find(‘.’);
            }
            if (p2 == string::npos)
                v2 = 0;
            else {
                v2 = atoi(version2.substr(0, p2).c_str());
                version2 = version2.substr(p2 + 1);
                p2 = version2.find(‘.’);
            }
            if (v1 < v2)
                return -1;
            else if (v1 > v2)
                return 1;
        }
        return 0;
    }
};

本代码提交AC,用时3MS。

二刷。更简洁的代码:

class Solution {
private:
	void ParseVersion(const string &version, vector<int> &v) {
		int n = version.size();
		int i = 0, j = 0;
		while (i < n) {
			j = i + 1;
			while (j < n&&version[j] != '.')++j;
			int tmp = atoi(version.substr(i, j - i).c_str());
			v.push_back(tmp);
			i = j + 1;
		}
	}
public:
	int compareVersion(string version1, string version2) {
		vector<int> v1, v2;
		ParseVersion(version1, v1);
		ParseVersion(version2, v2);
		int i = 0, j = 0, n1 = v1.size(), n2 = v2.size();
		while (i < n1 || j < n2) {
			int a = (i < n1 ? v1[i] : 0);
			int b = (j < n2 ? v2[j] : 0);
			if (a > b)return 1;
			else if (a < b)return -1;
			else {
				++i;
				++j;
			}
		}
		return 0;
	}
};

本代码提交AC,用时8MS。

LeetCode Reverse Words in a String

151. Reverse Words in a String

Given an input string, reverse the string word by word.

Example 1:

Input: "the sky is blue"
Output: "blue is sky the"

Example 2:

Input: "  hello world!  "
Output: "world! hello"
Explanation: Your reversed string should not contain leading or trailing spaces.

Example 3:

Input: "a good   example"
Output: "example good a"
Explanation: You need to reduce multiple spaces between two words to a single space in the reversed string.

Note:

  • A word is defined as a sequence of non-space characters.
  • Input string may contain leading or trailing spaces. However, your reversed string should not contain leading or trailing spaces.
  • You need to reduce multiple spaces between two words to a single space in the reversed string.

Follow up:

For C programmers, try to solve it in-place in O(1) extra space.


对一个字符串,以单词为单位进行逆序。注意字符串中可能会有多个连续的空格,还可能在首尾有空格。 如果允许使用额外的空间,那就好办,先把字符串分词,然后逆序拼接。代码如下:

class Solution {
public:
    void reverseWords(string& s)
    {
        string ans = "";
        int start = 0, end = 0, n = s.size();
        while (true) {
            while (start < n && s[start] == ‘ ‘)
                ++start;
            if (start >= n)
                break;
            end = start + 1;
            while (end < n && s[end] != ‘ ‘)
                ++end;
            if (end >= n)
                break;
            ans = s.substr(start, end – start) + " " + ans;
            start = end + 1;
        }
        if (end > start)
            ans = s.substr(start, end – start) + " " + ans;
        s = ans.substr(0, ans.size() – 1);
    }
};

本代码提交AC,用时9MS。

如果不借助额外空间,则只能在原字符串上进行逆序了,有意思。我们可以进行两次翻转,第一次对整个字符串翻转,然后遍历新字符串,对每个单词进行翻转。比如原字符串是”the sky is blue”,第一次翻转之后就是”eulb si yks eht”,再依次对每个单词翻转,就变成了”blue is sky the”。
我们知道对一个字符串进行翻转可以使用首尾指针的方法in-place实现,代码中为了可读性,直接调用了STL的reverse函数。

class Solution {
public:
    void reverseWords(string& s)
    {
        reverse(s.begin(), s.end()); 
        //i,j为新字符串每个单词的首尾位置,u,v为旧字符串每个单词的首尾位置
        int i = 0, j = 0, u = 0, v = 0, n = s.size();
        while (true) {
            while (u < n && s[u] == ‘ ‘)
                ++u;
            if (u >= n)
                break;
            v = u;
            while (v < n && s[v] != ‘ ‘)
                s[j++] = s[v++];
            reverse(s.begin() + i, s.begin() + j);
            if (v >= n)
                break;
            s[j++] = ‘ ‘;
            i = j;
            u = v;
        }
        if (j == 0)
            s = "";
        else if (s[j – 1] == ‘ ‘)
            s.resize(j – 1);
        else
            s.resize(j);
    }
};

本代码提交AC,用时6MS。虽然第二种方法更快,也更省空间,但是有很多边界条件很容易出错,我还是觉得第一种方法安全。
参考:http://www.cnblogs.com/grandyang/p/4606676.html

LeetCode Reverse Vowels of a String

LeetCode 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”. Note: The vowels does not include the letter “y”.


把字符串中的所有元音字母逆序。简单题,使用首尾两个指针i,j,找到元音后交换,直到i>j。 完整代码如下: [cpp] class Solution { public: string reverseVowels(string s) { unordered_set<char> vowels = { ‘a’,’e’,’i’,’o’,’u’,’A’,’E’,’I’,’O’,’U’ }; int i = 0, j = s.size() – 1; while (i < j) { while (i < j&&vowels.find(s[i]) == vowels.end())++i; if (i >= j)break; while (i < j&&vowels.find(s[j]) == vowels.end())–j; if (i >= j)break; swap(s[i++], s[j–]); } return s; } }; [/cpp] 本代码提交AC,用时52MS。]]>

LeetCode Repeated Substring Pattern

LeetCode 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. Example 1:

Input: "abab"
Output: True
Explanation: It's the substring "ab" twice.
Example 2:
Input: "aba"
Output: False
Example 3:
Input: "abcabcabcabc"
Output: True
Explanation: It's the substring "abc" four times. (And the substring "abcabc" twice.)

本题问一个字符串能否由其子串通过复制多次得到。如果能的话,中间肯定有一个字符和第一个字符相同,所以我们只需要遍历中间字符,找到和第一个字符相等的位置,那么这个位置往前就是重复子串pattern,我们再看这个位置往后是否都是pattern的重复。 其实如果字符串确实由pattern重复而来,则这个pattern的长度应该小于等于总长度的一半,所以我们只需要查找总长度的一半来找和第一个字符相同的字符。 完整代码如下: [cpp] class Solution { public: bool repeatedSubstringPattern(string str) { if (str.size() == 1)return false; for (int i = 1; i <= str.size() / 2; ++i) { if (str[i] == str[0]) { string pattern = str.substr(0, i); int j = i; while (j < str.size()) { string sub = str.substr(j, pattern.size()); if (pattern != sub)break; j += pattern.size(); } if (j == str.size())return true; } } return false; } }; [/cpp] 本代码提交AC,用时56MS。]]>

LeetCode Decode String

LeetCode Decode String 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][/c]]", return "accaccacc".
s = "2[abc]3[cd]ef", return "abcabccdcdcdef".

题意:要求把加密的字符串解密。加密规则是重复k次的子串str写成k[str],方括号可能会有嵌套。 所以我们需要解析加密字符串,把方括号中的内容提取出来,然后复制k份,因为有嵌套,面对括号匹配问题,堆栈是最好的解决办法。我们不断把字符串压栈,直到遇到],从栈中不断弹出,直到遇到[,期间的字符串就是我们要重复的str,然后弹出k,重复k次,把重复的字符串再次压栈。如此不断循环,最后只要把栈中的字符串连接起来就好了。 完整代码如下: [cpp] class Solution { public: string decodeString(string s) { stack<string> stk; for (int i = 0; i < s.size(); ++i) { if (s[i] != ‘]’)stk.push(string(1, s[i])); else { string cur = ""; while (stk.top() != "[") { // stk不可能为空 cur = stk.top() + cur; stk.pop(); } stk.pop(); string cnt = ""; while (!stk.empty() && isdigit(stk.top()[0])) { // 此处stk可能为空 cnt = stk.top() + cnt; stk.pop(); } int n = atoi(cnt.c_str()); string repeated = ""; while (n–)repeated += cur; stk.push(repeated); } } string ans = ""; while (!stk.empty()) { ans = stk.top() + ans; stk.pop(); } return ans; } }; [/cpp] 本代码提交AC,用时3MS。]]>

LeetCode License Key Formatting

LeetCode License Key Formatting Now you are given a string S, which represents a software license key which we would like to format. The string S is composed of alphanumerical characters and dashes. The dashes split the alphanumerical characters within the string into groups. (i.e. if there are M dashes, the string is split into M+1 groups). The dashes in the given string are possibly misplaced. We want each group of characters to be of length K (except for possibly the first group, which could be shorter, but still must contain at least one character). To satisfy this requirement, we will reinsert dashes. Additionally, all the lower case letters in the string must be converted to upper case. So, you are given a non-empty string S, representing a license key to format, and an integer K. And you need to return the license key formatted according to the description above. Example 1:

Input: S = "2-4A0r7-4k", K = 4
Output: "24A0-R74K"
Explanation: The string S has been split into two parts, each part has 4 characters.
Example 2:
Input: S = "2-4A0r7-4k", K = 3
Output: "24-A0R-74K"
Explanation: The string S has been split into three parts, each part has 3 characters except the first part as it could be shorter as said above.
Note:
  1. The length of string S will not exceed 12,000, and K is a positive integer.
  2. String S consists only of alphanumerical characters (a-z and/or A-Z and/or 0-9) and dashes(-).
  3. String S is non-empty.

题目有点长,其实很简单。题意是一个被dash插乱的字符串,现在要格式化它,规则就是以长度K分组,每组之间用dash连接,但是第一组的长度可以不是K,另外还要把小写字母转换为大写字母。 解法:首先把所有dash删掉,并把小写转换为大写,得到一个新的字符串strNew,然后计算strNew.size()%K,如果等于0,表明第一组的长度也为K;否则第一组的长度就是strNew.size()%K。接下来就是把每K长度的字符串用dash拼接起来了。完整代码如下: [cpp] class Solution { public: string licenseKeyFormatting(string S, int K) { string strNew = ""; for (int i = 0; i < S.size(); ++i) { if (S[i] == ‘-‘)continue; strNew += toupper(S[i]); } string ans = ""; int offset = strNew.size() % K; if (offset != 0) { ans = strNew.substr(0, offset) + "-"; } while (offset < strNew.size()) { ans += strNew.substr(offset, K) + "-"; offset += K; } return ans.substr(0, ans.size() – 1); } }; [/cpp] 本代码提交AC,用时9MS。]]>

LeetCode Valid Anagram

242. Valid Anagram 242. Valid Anagram

Given two strings s and , write a function to determine if t is an anagram of s.

Example 1:

Input: s = "anagram", t = "nagaram"
Output: true

Example 2:

Input: s = "rat", t = "car"
Output: false

Note:
You may assume the string contains only lowercase alphabets.

Follow up:
What if the inputs contain unicode characters? How would you adapt your solution to such case? 242. Valid Anagram


“Anagram”这个词的意思是“易位构词游戏”,就是把一个word中的letter打乱。本题要判断两个字符串是否是anagram。简单题,直接对两个字符串hash,分别统计出现字符的频率,如果两个hash的结果完全一样,则是anagram;否则不是。 这题和LeetCode Word Pattern类似,也是要保证两个字符串hash到的频率完全一样,即是一个双射。完整代码如下:

class Solution {
public:
    bool isAnagram(string s, string t)
    {
        unordered_map<char, int> ums, umt;
        for (int i = 0; i < s.size(); ++i) {
            ++ums[s[i]];
        }
        for (int i = 0; i < t.size(); ++i) {
            ++umt[t[i]];
        }
        unordered_map<char, int>::iterator it = ums.begin();
        while (it != ums.end()) {
            if (umt[it->first] != it->second)
                return false;
            ++it;
        }
        it = umt.begin();
        while (it != umt.end()) {
            if (ums[it->first] != it->second)
                return false;
            ++it;
        }
        return true;
    }
};

本代码提交AC,用时16MS。
还有一种方法就是对两个字符串都排个序,然后判等,代码很简单,但是排序复杂度要比直接hash稍高。代码如下:

class Solution {
public:
    bool isAnagram(string s, string t)
    {
        sort(s.begin(), s.end());
        sort(t.begin(), t.end());
        return s == t;
    }
};

本代码提交AC,用时26MS。

LeetCode First Unique Character in a String

LeetCode First Unique Character in a String Given a string, find the first non-repeating character in it and return it’s index. If it doesn’t exist, return -1. Examples:

s = "leetcode"
return 0.
s = "loveleetcode",
return 2.
Note: You may assume the string contain only lowercase letters.
本题要求找出字符串中第一个没有重复出现的字符。简单题,先对所有字符hash,找出字符和频率的对应关系,然后遍历字符串,返回第一个频率为1的字符。完整代码如下: [cpp] class Solution { public: int firstUniqChar(string s) { unordered_map<char, int> hash; for (int i = 0; i < s.size(); ++i) { ++hash[s[i]]; } for (int i = 0; i < s.size(); ++i) { if (hash[s[i]] == 1)return i; } return -1; } }; [/cpp] 本代码提交AC,用时92MS。]]>

LeetCode Magical String

LeetCode Magical String A magical string S consists of only ‘1’ and ‘2’ and obeys the following rules: The string S is magical because concatenating the number of contiguous occurrences of characters ‘1’ and ‘2’ generates the string Sitself. The first few elements of string S is the following: S = “1221121221221121122……” If we group the consecutive ‘1’s and ‘2’s in S, it will be: 1 22 11 2 1 22 1 22 11 2 11 22 …… and the occurrences of ‘1’s or ‘2’s in each group are: 1 2 2 1 1 2 1 2 2 1 2 2 …… You can see that the occurrence sequence above is the S itself. Given an integer N as input, return the number of ‘1’s in the first N number in the magical string S. Note: N will not exceed 100,000. Example 1:

Input: 6
Output: 3
Explanation: The first 6 elements of magical string S is "12211" and it contains three 1's, so return 3.

这道题给了一个magic字符串,具体怎么magic题目说得很清楚了。这个字符串只包含字符1和2,依次计算字符串中连续的1或2出现的次数,把这些数字串起来,构成的一个新的字符串和原字符串是完全一样的!然后问字符串中前n个字符出现1的次数。 这是一个模拟题,我们根据magic的规则模拟生成这个字符串,然后统计一下前n个字符中1出现的次数。 模拟的方法就是把字符串中的数当做原字符串中1或2出现的次数,然后不断在原字符串中追加新的字符。比如开始是122:1表示1出现1次;第一个2表示出现两次,因为前面有1出现1次的约束,所以出现两次的只可能是2;第二个2也表示出现两次,因为前面已经出现了两个2了,所以这里不能再接两个2了(要不然就出现4个2了),只能表示出现了两次1,所以我们可以在原字符串中追加两个1,变为12211。如此不断的模拟下去,直到字符串长度满足要求。 完整代码如下: [cpp] class Solution { public: int magicalString(int n) { string magic = "122"; int pos = 2; while (magic.size() < n) { switch (magic[magic.size()-1]) { case ‘1’: magic += string(magic[pos] – ‘0’, ‘2’); break; case ‘2’: magic += string(magic[pos] – ‘0’, ‘1’); break; } ++pos; } int ans = 0; for (int i = 0; i < n; ++i) { ans += magic[i] == ‘1’ ? 1 : 0; } return ans; } }; [/cpp] 本代码提交AC,用时9MS。]]>

LeetCode Sort Characters By Frequency

LeetCode Sort Characters By Frequency Given a string, sort it in decreasing order based on the frequency of characters. Example 1:

Input:
"tree"
Output:
"eert"
Explanation:
'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
Example 2:
Input:
"cccaaa"
Output:
"cccaaa"
Explanation:
Both 'c' and 'a' appear three times, so "aaaccc" is also a valid answer.
Note that "cacaca" is incorrect, as the same characters must be together.
Example 3:
Input:
"Aabb"
Output:
"bbAa"
Explanation:
"bbaA" is also a valid answer, but "Aabb" is incorrect.
Note that 'A' and 'a' are treated as two different characters.

把一个字符串中的字符按出现频率重新排序并输出。 简单题,因为ascii的字符有128个,所以构造一个128长的hash表,先统计一下每个字符出现的次数,然后对频率排个序,最后按频率从高到低重新构造字符串。 完整代码如下: [cpp] typedef struct Character{ char c; int cnt; bool operator<(const Character& ch) const { return this->cnt < ch.cnt; } }; class Solution { public: string frequencySort(string s) { vector<Character> hash(128); for (int i = 0; i < s.size(); ++i) { hash[s[i]].c = s[i]; ++hash[s[i]].cnt; } sort(hash.begin(), hash.end()); string ans = ""; for (int i = 127; i >=0; –i) { if (hash[i].cnt == 0)break; ans += string(hash[i].cnt, hash[i].c); } return ans; } }; [/cpp] 本代码提交AC,用时23MS。]]>