Tag Archives: 字符串

LeetCode String Matching in an Array

1408. String Matching in an Array

Given an array of string words. Return all strings in words which is substring of another word in any order. 

String words[i] is substring of words[j], if can be obtained removing some characters to left and/or right side of words[j].

Example 1:

Input: words = ["mass","as","hero","superhero"]
Output: ["as","hero"]
Explanation: "as" is substring of "mass" and "hero" is substring of "superhero".
["hero","as"] is also a valid answer.

Example 2:

Input: words = ["leetcode","et","code"]
Output: ["et","code"]
Explanation: "et", "code" are substring of "leetcode".

Example 3:

Input: words = ["blue","green","bu"]
Output: []

Constraints:

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 30
  • words[i] contains only lowercase English letters.
  • It’s guaranteed that words[i] will be unique.

给定一个字符串数组,如果某个字符串是其他字符串的子串,则输出,找出所有这种字符串。

简单题,直接两遍for循环查找即可,代码如下:

class Solution {
public:
	vector<string> stringMatching(vector<string>& words) {
		vector<string> ans;
		for (int i = 0; i < words.size(); ++i) {
			for (int j = 0; j < words.size(); ++j) {
				if (i == j)continue;
				if (words[j].find(words[i]) != string::npos) {
					ans.push_back(words[i]);
					break;
				}
			}
		}
		return ans;
	}
};

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

LeetCode HTML Entity Parser

1410. HTML Entity Parser

HTML entity parser is the parser that takes HTML code as input and replace all the entities of the special characters by the characters itself.

The special characters and their entities for HTML are:

  • Quotation Mark: the entity is &quot; and symbol character is ".
  • Single Quote Mark: the entity is &apos; and symbol character is '.
  • Ampersand: the entity is &amp; and symbol character is &.
  • Greater Than Sign: the entity is &gt; and symbol character is >.
  • Less Than Sign: the entity is &lt; and symbol character is <.
  • Slash: the entity is &frasl; and symbol character is /.

Given the input text string to the HTML parser, you have to implement the entity parser.

Return the text after replacing the entities by the special characters.

Example 1:

Input: text = "&amp; is an HTML entity but &ambassador; is not."
Output: "& is an HTML entity but &ambassador; is not."
Explanation: The parser will replace the &amp; entity by &

Example 2:

Input: text = "and I quote: &quot;...&quot;"
Output: "and I quote: \"...\""

Example 3:

Input: text = "Stay home! Practice on Leetcode :)"
Output: "Stay home! Practice on Leetcode :)"

Example 4:

Input: text = "x &gt; y &amp;&amp; x &lt; y is always false"
Output: "x > y && x < y is always false"

Example 5:

Input: text = "leetcode.com&frasl;problemset&frasl;all"
Output: "leetcode.com/problemset/all"

Constraints:

  • 1 <= text.length <= 10^5
  • The string may contain any possible characters out of all the 256 ASCII characters.

给定一个HTML字符串,要求把其中的特殊符号转换为其原来的表示。

简单题,遍历字符串,找到以&开头,以;结尾的子串,根据情况把它转换为原来的字符即可。请注意,有可能该子串不属于文中6种情况中的任何一种,此时不需要转义,直接原样拷贝。代码如下:

class Solution {
public:
	string entityParser(string text) {
		int n = text.size(), i = 0;
		string ans = "";
		while (i < n) {
			while (i < n&&text[i] != '&') {
				ans.push_back(text[i]);
				++i;
			}
			if (i >= n)break;
			int j = i + 1;
			while (j < n&&text[j] != ';')++j;
			string mark = text.substr(i, j - i + 1);
			if (mark == "&quot;")ans.push_back('\"');
			else if (mark == "&apos;")ans.push_back('\'');
			else if (mark == "&amp;")ans.push_back('&');
			else if (mark == "&gt;")ans.push_back('>');
			else if (mark == "&lt;")ans.push_back('<');
			else if (mark == "&frasl;")ans.push_back('/');
			else ans += mark;
			i = j + 1;
		}
		return ans;
	}
};

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

LeetCode Backspace String Compare

844. Backspace String Compare

Given two strings S and T, return if they are equal when both are typed into empty text editors. # means a backspace character.

Example 1:

Input: S = "ab#c", T = "ad#c"
Output: true
Explanation: Both S and T become "ac".

Example 2:

Input: S = "ab##", T = "c#d#"
Output: true
Explanation: Both S and T become "".

Example 3:

Input: S = "a##c", T = "#a#c"
Output: true
Explanation: Both S and T become "c".

Example 4:

Input: S = "a#c", T = "b"
Output: false
Explanation: S becomes "c" while T becomes "b".

Note:

  1. 1 <= S.length <= 200
  2. 1 <= T.length <= 200
  3. S and T only contain lowercase letters and '#' characters.

Follow up:

  • Can you solve it in O(N) time and O(1) space?

给定两个字符串,其中包含小写字母和#,#表示删除前一个字符。问这两个字符串的最终结果是否一致。

这道题如果不考虑Follow up的话很简单,新建一个string,看到字母就push_back,看到#就pop_back,最后看剩余字符串是否相等即可。

但是Follow up要求只使用O(1)的空间,这就需要思考一下了。思路是这样的,从后往前处理两个字符串,统计#的数目,模拟删除过程,直到无法删除找到一个能被留在最终字符串中的字母,比较S和T的这个字符是否相等。完整代码如下:

class Solution {
public:
	bool backspaceCompare(string S, string T) {
		int i = S.size() - 1, j = T.size() - 1;
		while (i >= 0 || j >= 0) {
			int skipS = 0, skipT = 0;
			while (i >= 0) {
				if (S[i] == '#') {
					++skipS;
					--i;
				}
				else if (skipS > 0) {
					--skipS;
					--i;
				}
				else {
					break;
				}
			}

			while (j >= 0) {
				if (T[j] == '#') {
					++skipT;
					--j;
				}
				else if (skipT > 0) {
					--skipT;
					--j;
				}
				else {
					break;
				}
			}

			if ((i >= 0) != (j >= 0))return false;
			if (i >= 0 && S[i] != T[j])return false;
			--i;
			--j;
		}
		return true;
	}
};

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

LeetCode Generate a String With Characters That Have Odd Counts

1374. Generate a String With Characters That Have Odd Counts

Given an integer nreturn a string with n characters such that each character in such string occurs an odd number of times.

The returned string must contain only lowercase English letters. If there are multiples valid strings, return any of them.  

Example 1:

Input: n = 4
Output: "pppz"
Explanation: "pppz" is a valid string since the character 'p' occurs three times and the character 'z' occurs once. Note that there are many other valid strings such as "ohhh" and "love".

Example 2:

Input: n = 2
Output: "xy"
Explanation: "xy" is a valid string since the characters 'x' and 'y' occur once. Note that there are many other valid strings such as "ag" and "ur".

Example 3:

Input: n = 7
Output: "holasss"

Constraints:

  • 1 <= n <= 500

简单题。要求构造一个长度为n的字符串,使得字符串中所有字符出现的频率都为奇数。不要被样例迷惑了。如果n为奇数,直接重复一个字符n次即可;如果n为偶数,则重复一个字符n-1次,外加另一个字符。

完整代码如下:

class Solution {
public:
	string generateTheString(int n) {
		if (n % 2 == 0) {
			return string(n - 1, 'a') + "b";
		}
		else {
			return string(n, 'a');
		}
	}
};

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

LeetCode Rank Teams by Votes

1366. Rank Teams by Votes

In a special ranking system, each voter gives a rank from highest to lowest to all teams participated in the competition.

The ordering of teams is decided by who received the most position-one votes. If two or more teams tie in the first position, we consider the second position to resolve the conflict, if they tie again, we continue this process until the ties are resolved. If two or more teams are still tied after considering all positions, we rank them alphabetically based on their team letter.

Given an array of strings votes which is the votes of all voters in the ranking systems. Sort all teams according to the ranking system described above.

Return a string of all teams sorted by the ranking system.

Example 1:

Input: votes = ["ABC","ACB","ABC","ACB","ACB"]
Output: "ACB"
Explanation: Team A was ranked first place by 5 voters. No other team was voted as first place so team A is the first team.
Team B was ranked second by 2 voters and was ranked third by 3 voters.
Team C was ranked second by 3 voters and was ranked third by 2 voters.
As most of the voters ranked C second, team C is the second team and team B is the third.

Example 2:

Input: votes = ["WXYZ","XYZW"]
Output: "XWYZ"
Explanation: X is the winner due to tie-breaking rule. X has same votes as W for the first position but X has one vote as second position while W doesn't have any votes as second position. 

Example 3:

Input: votes = ["ZMNAGUEDSJYLBOPHRQICWFXTVK"]
Output: "ZMNAGUEDSJYLBOPHRQICWFXTVK"
Explanation: Only one voter so his votes are used for the ranking.

Example 4:

Input: votes = ["BCA","CAB","CBA","ABC","ACB","BAC"]
Output: "ABC"
Explanation: 
Team A was ranked first by 2 voters, second by 2 voters and third by 2 voters.
Team B was ranked first by 2 voters, second by 2 voters and third by 2 voters.
Team C was ranked first by 2 voters, second by 2 voters and third by 2 voters.
There is a tie and we rank teams ascending by their IDs.

Example 5:

Input: votes = ["M","M","M","M"]
Output: "M"
Explanation: Only team M in the competition so it has the first rank.

Constraints:

  • 1 <= votes.length <= 1000
  • 1 <= votes[i].length <= 26
  • votes[i].length == votes[j].length for 0 <= i, j < votes.length.
  • votes[i][j] is an English upper-case letter.
  • All characters of votes[i] are unique.
  • All the characters that occur in votes[0] also occur in votes[j] where 1 <= j < votes.length.

给定很多人对很多team的打分排序列表,如果一个队排在前面的名次越多,则其最终名次越高,据此输出最终排序列表。

规则很复杂,其实很简单。设计一个Team的类,它有一个scores数组,scores[i]表示这个队被多少人投票排在了第i名。由于最多只有26个队,所以scores的维度为26。对Team自定义排序函数,排序规则是依次比较scores的每个元素大小,如果都相等的话,最后比较name的大小。

完整代码如下:

const int MAXN = 26;
class Team {
public:
	char name;
	vector<int> scores;

	Team() :name(0) {
		scores.resize(MAXN, 0);
	};

	bool operator<(const Team& t) {
		for (int i = 0; i < MAXN; ++i) {
			if (scores[i] > t.scores[i]) {
				return true;
			}
			else if (scores[i] < t.scores[i]) {
				return false;
			}
		}
		return name < t.name;
	}
};

class Solution {
public:
	string rankTeams(vector<string>& votes) {
		vector<Team> teams(MAXN, Team());
		for (int j = 0; j < votes[0].size(); ++j) {
			int idx = votes[0][j] - 'A';
			teams[idx].name = votes[0][j]; // 出现的team name
		}
		for (int i = 0; i < votes.size();++i) {
			for (int j = 0; j < votes[i].size(); ++j) {
				int idx = votes[i][j] - 'A';
				++teams[idx].scores[j];
			}
		}
		vector<Team> showups;
		for (int i = 0; i < MAXN; ++i) {
			if (teams[i].name != 0) {
				showups.push_back(teams[i]);
			}
		}
		sort(showups.begin(), showups.end());
		string ans = "";
		for (int i = 0; i < showups.size(); ++i) {
			ans += showups[i].name;
		}
		return ans;
	}
};

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

LeetCode Judge Route Circle

LeetCode Judge Route Circle Initially, there is a Robot at position (0, 0). Given a sequence of its moves, judge if this robot makes a circle, which means it moves back to the original place. The move sequence is represented by a string. And each move is represent by a character. The valid robot moves are R (Right), L (Left), U (Up) and D (down). The output should be true or false representing whether the robot makes a circle. Example 1:

Input: "UD"
Output: true
Example 2:
Input: "LL"
Output: false

一个机器人,初始站在原点(0,0),UDLR分别表示上下左右,给定一个机器人行走的轨迹字符串,问最终机器人能回到原点吗。 简单题,直接判断走过的水平和垂直方向的差值是否为0,代码如下: [cpp] class Solution { public: bool judgeCircle(string moves) { int horizon = 0, vertical = 0; for (auto c : moves) { if (c == ‘U’)++vertical; else if (c == ‘D’)–vertical; else if (c == ‘L’)–horizon; else if (c == ‘R’)++horizon; } return horizon == 0 && vertical == 0; } }; [/cpp] 本代码提交AC,用时29MS。]]>

LeetCode Replace Words

LeetCode Replace Words

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

给定一个词典和一个句子,词典是一系列的词根,要求把句子中的每个词替换成其最短词根(如果有词根的话)。 简单题,明显是Trie树的应用。首先把词典中的所有词根建一个Trie树,然后对句子中的每个单词,去Trie树中查找,返回最先找到的词根(也就是最短的词根);如果该词不在Trie树中,则说明不存在词根,直接用原来的单词。 完整代码如下: [cpp] const int kMaxN = 26; class Solution { private: struct Node { bool is_word_; vector<Node*> children_; Node() :is_word_(false) { for (int i = 0; i < kMaxN; ++i) children_.push_back(NULL); } }; Node *root_; void InsertWord(const string& word) { Node *cur = root_; for (const auto& c : word) { int idx = c – ‘a’; if (cur->children_[idx] == NULL)cur->children_[idx] = new Node(); cur = cur->children_[idx]; } cur->is_word_ = true; } void ConstructTree(const vector<string>& dict) { root_ = new Node(); for (const auto& w : dict) { InsertWord(w); } } string SearchTree(const string& word) { Node *cur = root_; string ans = ""; for (const auto& c : word) { int idx = c – ‘a’; if (cur->children_[idx] == NULL)return ""; cur = cur->children_[idx]; ans.push_back(c); if (cur->is_word_)return ans; } return ""; } public: string replaceWords(vector<string>& dict, string sentence) { ConstructTree(dict); string ans = ""; int i = 0, n = sentence.size(); for (int j = 0; j <= n; ++j) { if (j == n || sentence[j] == ‘ ‘) { string successor = sentence.substr(i, j – i); string root = SearchTree(successor); if (root == "") ans += successor + " "; else ans += root + " "; i = j + 1; } } return ans.substr(0, ans.size() – 1); } }; [/cpp] 本代码提交AC,用时98MS。]]>

LeetCode Design Search Autocomplete System

LeetCode Design Search Autocomplete System Design a search autocomplete system for a search engine. Users may input a sentence (at least one word and end with a special character '#'). For each character they type except ‘#’, you need to return the top 3 historical hot sentences that have prefix the same as the part of sentence already typed. Here are the specific rules:

  1. The hot degree for a sentence is defined as the number of times a user typed the exactly same sentence before.
  2. The returned top 3 hot sentences should be sorted by hot degree (The first is the hottest one). If several sentences have the same degree of hot, you need to use ASCII-code order (smaller one appears first).
  3. If less than 3 hot sentences exist, then just return as many as you can.
  4. When the input is a special character, it means the sentence ends, and in this case, you need to return an empty list.
Your job is to implement the following functions: The constructor function: AutocompleteSystem(String[] sentences, int[] times): This is the constructor. The input is historical dataSentences is a string array consists of previously typed sentences. Times is the corresponding times a sentence has been typed. Your system should record these historical data. Now, the user wants to input a new sentence. The following function will provide the next character the user types: List<String> input(char c): The input c is the next character typed by the user. The character will only be lower-case letters ('a' to 'z'), blank space (' ') or a special character ('#'). Also, the previously typed sentence should be recorded in your system. The output will be the top 3 historical hot sentences that have prefix the same as the part of sentence already typed.   Example: Operation: AutocompleteSystem([“i love you”, “island”,”ironman”, “i love leetcode”], [5,3,2,2]) The system have already tracked down the following sentences and their corresponding times: "i love you" : 5 times "island" : 3 times "ironman" : 2 times "i love leetcode" : 2 times Now, the user begins another search: Operation: input(‘i’) Output: [“i love you”, “island”,”i love leetcode”] Explanation: There are four sentences that have prefix "i". Among them, “ironman” and “i love leetcode” have same hot degree. Since ' ' has ASCII code 32 and 'r' has ASCII code 114, “i love leetcode” should be in front of “ironman”. Also we only need to output top 3 hot sentences, so “ironman” will be ignored. Operation: input(‘ ‘) Output: [“i love you”,”i love leetcode”] Explanation: There are only two sentences that have prefix "i ". Operation: input(‘a’) Output: [] Explanation: There are no sentences that have prefix "i a". Operation: input(‘#’) Output: [] Explanation: The user finished the input, the sentence "i a" should be saved as a historical sentence in system. And the following input will be counted as a new search.   Note:
  1. The input sentence will always start with a letter and end with ‘#’, and only one blank space will exist between two words.
  2. The number of complete sentences that to be searched won’t exceed 100. The length of each sentence including those in the historical data won’t exceed 100.
  3. Please use double-quote instead of single-quote when you write test cases even for a character input.
  4. Please remember to RESET your class variables declared in class AutocompleteSystem, as static/class variables are persisted across multiple test cases. Please see herefor more details.

本题要求实现一个搜索引擎的自动补全功能,正好是我想在我的新闻搜索引擎里实现的功能。首先会给出一些历史数据,就是哪些句子被访问了多少次。现在模拟用户输入,每输入一个字符,给出以输入的所有字符为前缀的历史句子,并且只给出被访频率前3的句子作为自动补全的候选。 Trie树的应用题。Trie树的节点属性包含is_sentence_以该字符结尾是否是一个句子,cnt_该句子的频率。首先把历史数据插入到Trie树中,记录好相应的is_sentence_和cnt_。 用一个成员变量cur_sentence_记录当前输入的字符串前缀。查找的时候,用cur_sentence_在Trie树中找,先找到这个前缀,然后在26个字母+一个空格中递归查找所有孩子节点,把能形成句子的字符串及其频率插入到一个优先队列中。该优先队列先以句子频率排序,如果频率相等,再以字典序排列。这样我们直接从优先队列中取出前三个堆顶句子,就是自动补全的候选。 如果遇到#,说明输入结束,把cur_sentence_及其频率1也插入到Trie树中。注意插入之后树中节点的频率是累加的,即第34行。 注意AutocompleteSystem类初始化的时候需要清空cur_sentence_和Trie树,更多的细节请看代码中的caution。 [cpp] const int N = 26; class AutocompleteSystem { private: struct Node { bool is_sentence_; int cnt_; vector<Node*> children_; Node() :is_sentence_(false), cnt_(0){ for (int i = 0; i < N + 1; ++i)children_.push_back(NULL); } }; Node *root; string cur_sentence_; struct Candidate { int cnt_; string sentence_; Candidate(int &cnt, string &sentence) :cnt_(cnt), sentence_(sentence) {}; bool operator<(const Candidate& cand) const { return (cnt_ < cand.cnt_) || (cnt_ == cand.cnt_&&sentence_ > cand.sentence_); // caution } }; void AddSentence(const string& sentence, const int& time) { Node *cur = root; for (const auto& c : sentence) { int idx = c – ‘a’; if (c == ‘ ‘)idx = N; if (cur->children_[idx] == NULL)cur->children_[idx] = new Node(); cur = cur->children_[idx]; } cur->is_sentence_ = true; cur->cnt_ += time; // caution } void FindSentences(Node *root, string &sentence, priority_queue<Candidate>& candidates) { if (root != NULL&&root->is_sentence_)candidates.push(Candidate(root->cnt_, sentence)); if (root == NULL)return; for (int i = 0; i < N + 1; ++i) { if (root->children_[i] != NULL) { if (i == N) sentence.push_back(‘ ‘); else sentence.push_back(‘a’ + i); FindSentences(root->children_[i], sentence, candidates); sentence.pop_back(); } } } void StartWith(priority_queue<Candidate>& candidates) { Node *cur = root; for (const auto& c : cur_sentence_) { int idx = c – ‘a’; if (c == ‘ ‘)idx = N; if (cur->children_[idx] == NULL)return; cur = cur->children_[idx]; } string sentence = cur_sentence_; FindSentences(cur, sentence, candidates); } public: AutocompleteSystem(vector<string> sentences, vector<int> times) { root = new Node(); // caution cur_sentence_ = ""; // caution for (int i = 0; i < sentences.size(); ++i)AddSentence(sentences[i], times[i]); } vector<string> input(char c) { if (c == ‘#’) { AddSentence(cur_sentence_, 1); // caution cur_sentence_ = ""; // caution return{}; } else { cur_sentence_.push_back(c); priority_queue<Candidate> candidates; StartWith(candidates); if (candidates.empty())return{}; vector<string> ans; while (!candidates.empty()) { ans.push_back(candidates.top().sentence_); candidates.pop(); if (ans.size() == 3)break; } return ans; } } }; [/cpp] 本代码提交AC,用时329MS。]]>

LeetCode Exclusive Time of Functions

LeetCode Exclusive Time of Functions Given the running logs of n functions that are executed in a nonpreemptive single threaded CPU, find the exclusive time of these functions. Each function has a unique id, start from 0 to n-1. A function may be called recursively or by another function. A log is a string has this format : function_id:start_or_end:timestamp. For example, "0:start:0" means function 0 starts from the very beginning of time 0. "0:end:0" means function 0 ends to the very end of time 0. Exclusive time of a function is defined as the time spent within this function, the time spent by calling other functions should not be considered as this function’s exclusive time. You should return the exclusive time of each function sorted by their function id. Example 1:

Input:
n = 2
logs =
["0:start:0",
 "1:start:2",
 "1:end:5",
 "0:end:6"]
Output:[3, 4]
Explanation:
Function 0 starts at time 0, then it executes 2 units of time and reaches the end of time 1.
Now function 0 calls function 1, function 1 starts at time 2, executes 4 units of time and end at time 5.
Function 0 is running again at time 6, and also end at the time 6, thus executes 1 unit of time.
So function 0 totally execute 2 + 1 = 3 units of time, and function 1 totally execute 4 units of time.
Note:
  1. Input logs will be sorted by timestamp, NOT log id.
  2. Your output should be sorted by function id, which means the 0th element of your output corresponds to the exclusive time of function 0.
  3. Two functions won’t start or end at the same time.
  4. Functions could be called recursively, and will always end.
  5. 1 <= n <= 100

给定一个单核单线程的CPU,并且给出了该CPU跑不同函数的开始时间和结束时间,问每个函数单独运行的时间是多少。因为有些函数可能会调用其他函数,还可能递归调用自己,所以需要去掉调用其他函数的时间,只给出该函数自己运行的时间。 用Node记录每一个记录,Node包含四个属性:function_id,start_or_end,timestamp和exclude_time,前三个就是题目中描述的属性,最后一个exclude_time是指该函数调用其他函数花费的时间,需要减去的时间。 考虑到递归调用,递归返回之类的,马上想到函数调用的时候需要用堆栈保存现场,所以这里也用堆栈保存所有递归调用的函数。每次遇到新函数的start时,压栈,遇到end时,和栈顶求一下时间差,弹栈,并把时间差记录到结果数组中。同时,需要把这个函数用掉的时间累加到栈顶(也就是主调函数)Node的exclude_time中,这一点非常重要。 最后,因为一个函数可能出现多次,所以不论是对结果数组的赋值还是对exclude_time的赋值,都用+=,不能用赋值,否则会覆盖掉之前的数据。 完整代码如下: [cpp] class Solution { private: struct Node { int id_; bool start_; int timestamp_; int exclude_time_; }; void ParseLog(const string& log, Node& node) { size_t colon_pos = log.find(‘:’); node.id_ = stoi(log.substr(0, colon_pos)); if (log[colon_pos + 1] == ‘s’) node.start_ = true; else node.start_ = false; colon_pos = log.find(‘:’, colon_pos + 1); node.timestamp_ = stoi(log.substr(colon_pos + 1)); node.exclude_time_ = 0; } public: vector<int> exclusiveTime(int n, vector<string>& logs) { vector<int> ans(n); stack<Node> stk; for (const auto& log : logs) { Node node; ParseLog(log, node); if (node.start_) { stk.push(node); } else { Node start_node = stk.top(); stk.pop(); int cur_time = node.timestamp_ – start_node.timestamp_ + 1 – start_node.exclude_time_; // caution ans[node.id_] += cur_time; // caution if (!stk.empty())stk.top().exclude_time_ += cur_time + start_node.exclude_time_; // caution } } return ans; } }; [/cpp] 本代码提交AC,用时23MS。]]>

LeetCode Decode Ways II

LeetCode Decode Ways II A message containing letters from A-Z is being encoded to numbers using the following mapping way:

'A' -> 1
'B' -> 2
...
'Z' -> 26
Beyond that, now the encoded string can also contain the character ‘*’, which can be treated as one of the numbers from 1 to 9. Given the encoded message containing digits and the character ‘*’, return the total number of ways to decode it. Also, since the answer may be very large, you should return the output mod 109 + 7. Example 1:
Input: "*"
Output: 9
Explanation: The encoded message can be decoded to the string: "A", "B", "C", "D", "E", "F", "G", "H", "I".
Example 2:
Input: "1*"
Output: 9 + 9 = 18
Note:
  1. The length of the input string will fit in range [1, 105].
  2. The input string will only contain the character ‘*’ and digits ‘0’ – ‘9’.

本题是LeetCode Decode Ways的升级版本,引入了一个星号’*’,可以表示’1′-‘9’这9个数字。给定一个加密的字符串,问有多少种解密方法。 这个题说难也难,说简单也简单,我居然跪在了int上,把dp数组由int改为long long就AC了! 和前一题的思路差不多,对于每个字符,都有两种可能的选择,要么该字符单独解码,要么和前一个字符组合起来解码。 设dp[i]表示前i个字符总的解密数。 对于当前字符是数字,前一个字符也是数字的情况,和前一题的思路完全一样,如果是’1’-‘9’,则可以自行解码,dp[i]+=dp[i-1];如果前一个字符和当前字符组合的数字范围在[10,26],可以和前一个字符组合解码,dp[i]+=dp[i-2]。 如果当前字符是数字,但前一个字符是*。如果要和前一个字符组合,当前字符如果在[‘0′,’6’],则前一个*可以取’1’或者’2’,所以dp[i]+=dp[i-2]*2;如果当前字符是[‘7′,’9’],则前一个*只能取’1’,所以dp[i]+=dp[i-2]。 对于*需要特殊处理。如果当前字符是*,前一个字符不是*,要和前一个字符组合,则如果前一个是’1’,则当前*可以取[‘0′,’9’],所以dp[i]+=dp[i-2]*9;如果前一个是’2’,则当前*可以取[‘0′,’6’],所以dp[i]+=dp[i-2]*6。其他情况都不能组合。 如果当前字符和前一个字符都是*的情况,要组合,则**的情况只有15种,注意不是26种,因为要去掉那些个位数和包含0的十位数的情况,剩下就只有15种了。所以dp[i]+=dp[i-2]*15。 完整代码如下: [cpp] const int MOD = 1000000007; typedef long long ll; class Solution { public: int numDecodings(string s) { if (s == "" || s[0] == ‘0’)return 0; s = "^" + s; int n = s.size(); vector<ll> dp(n, 0); dp[0] = 1; if (s[1] == ‘*’)dp[1] = 9; else dp[1] = 1; for (int i = 2; i < n; i++) { if (s[i] >= ‘1’ && s[i] <= ‘9’) dp[i] += dp[i – 1] % MOD; // 独自解析 if ((s[i – 1] == ‘1’ && s[i] >= ‘0’ && s[i] <= ‘9’) || (s[i – 1] == ‘2’ && s[i] >= ‘0’ && s[i] <= ‘6’)) dp[i] += dp[i – 2] % MOD; if (s[i – 1] == ‘*’&&s[i] >= ‘0’&&s[i] <= ‘9’) { if (s[i] >= ‘0’&&s[i] <= ‘6’)dp[i] += dp[i – 2] * 2 % MOD; if (s[i] > ‘6’)dp[i] += dp[i – 2] % MOD; } if (s[i] == ‘*’) { dp[i] += dp[i – 1] * 9 % MOD; // 独自解析 if (s[i – 1] != ‘*’) { if (s[i – 1] == ‘1’)dp[i] += dp[i – 2] * 9 % MOD; else if (s[i – 1] == ‘2’)dp[i] += dp[i – 2] * 6 % MOD; } else { dp[i] += dp[i – 2] * 15 % MOD; } } dp[i] %= MOD; } return dp[n – 1]; } }; [/cpp] 本代码提交AC,用时72MS。比赛的时候dp数组用int存的,死活WA,比赛结束那一秒,改成long long之后就AC了,但是比赛已经结束了。。。 看了下TOP代码,思路比我的稍微清晰一点,原理都是一样的,重构我的代码如下: [cpp] class Solution { public: int numDecodings(string s) { if (s == "" || s[0] == ‘0’)return 0; s = "^" + s; int n = s.size(); vector<ll> dp(n, 0); dp[0] = 1; if (s[1] == ‘*’)dp[1] = 9; else dp[1] = 1; for (int i = 2; i < n; i++) { char cur = s[i], pre = s[i – 1]; ll &curCnt = dp[i], preCnt = dp[i – 1], prePreCnt = dp[i – 2]; if (cur == ‘0’) { if (pre == ‘1’|| pre == ‘2’)curCnt += prePreCnt % MOD; else if (pre == ‘*’)curCnt += prePreCnt * 2 % MOD; else return 0; } else if (cur == ‘*’) { curCnt += preCnt * 9 % MOD; if (pre == ‘1’)curCnt += prePreCnt * 9 % MOD; else if (pre == ‘2’)curCnt += prePreCnt * 6 % MOD; else if (pre == ‘*’)curCnt += prePreCnt * 15 % MOD; } else { // [‘1′,’9′] curCnt += preCnt % MOD; if(pre==’1’)curCnt += prePreCnt % MOD; else if (pre == ‘2’ && cur <= ‘6’)curCnt += prePreCnt % MOD; else if (pre == ‘*’) { if (cur <= ‘6’)curCnt += prePreCnt * 2 % MOD; else curCnt += prePreCnt % MOD; } } curCnt %= MOD; } return dp[n – 1]; } }; [/cpp] 本代码提交AC,用时105MS。]]>