Tag Archives: 字符串

LeetCode Design Compressed String Iterator

LeetCode Design Compressed String Iterator Design and implement a data structure for a compressed string iterator. It should support the following operations: next and hasNext. The given compressed string will be in the form of each letter followed by a positive integer representing the number of this letter existing in the original uncompressed string. next() – if the original string still has uncompressed characters, return the next letter; Otherwise return a white space. hasNext() – Judge whether there is any letter needs to be uncompressed. Note: Please remember to RESET your class variables declared in StringIterator, as static/class variables are persisted across multiple test cases. Please see here for more details. Example:

StringIterator iterator = new StringIterator("L1e2t1C1o1d1e1");
iterator.next(); // return 'L'
iterator.next(); // return 'e'
iterator.next(); // return 'e'
iterator.next(); // return 't'
iterator.next(); // return 'C'
iterator.next(); // return 'o'
iterator.next(); // return 'd'
iterator.hasNext(); // return true
iterator.next(); // return 'e'
iterator.hasNext(); // return false
iterator.next(); // return ' '

本题设计了一种压缩字符串格式,即把多个连续相同字符用单个字符已经频率代替了,比如”L1e2t1C1o1d1e1″展开其实就是”LeetCode”。现在要针对这种压缩字符串,设计一个迭代器,实现next和hasNext函数。 我一开始上暴力,即首先把压缩字符串展开成常规字符串,然后直接下标操作。代码如下: [cpp] class StringIterator { private: string line; int cur, n; public: StringIterator(string compressedString) { line = ""; cur = n = 0; vector<char> letters; vector<int> rep; string digits = ""; for (int i = 0; i < compressedString.size(); ++i) { if (isalpha(compressedString[i])) { letters.push_back(compressedString[i]); if (digits != "") { rep.push_back(atoi(digits.c_str())); digits = ""; } } else digits += string(1, compressedString[i]); } rep.push_back(atoi(digits.c_str())); for (int i = 0; i < letters.size(); ++i) { line += string(rep[i], letters[i]); } n = line.size(); } char next() { if (cur < n)return line[cur++]; else return ‘ ‘; } bool hasNext() { return cur < n; } }; [/cpp] 本代码MLE了。因为有个样例是“a1234567890b1234567890”,我表示无语,如果展开确实会MLE。 其实写上面的代码的时候我就知道可以优化,不对压缩字符串展开,而是表示成(a,1234567890)和(b,1234567890),next的时候只对频率递减。这样只需要存储少量字符以及对应的频率。 代码如下: [cpp] typedef long long ll; class StringIterator { private: int cur, n; vector<char> letters; vector<ll> rep; public: StringIterator(string compressedString) { cur = n = 0; string digits = ""; for (int i = 0; i < compressedString.size(); ++i) { if (isalpha(compressedString[i])) { letters.push_back(compressedString[i]); if (digits != "") { rep.push_back(atoll(digits.c_str())); digits = ""; } } else digits += string(1, compressedString[i]); } rep.push_back(atoi(digits.c_str())); n = letters.size(); } char next() { if (rep[cur] > 0) { char ans = letters[cur]; –rep[cur]; return ans; } else { if (cur == n – 1)return ‘ ‘; else { char ans = letters[++cur]; –rep[cur]; return ans; } } } bool hasNext() { return cur < n – 1 || (cur == n – 1 && rep[cur] > 0); } }; [/cpp] 本代码提交AC,用时13MS。]]>

LeetCode Palindrome Partitioning

131. Palindrome Partitioning


Given a string s, partition s such that every substring of the partition is a palindrome.

Return all possible palindrome partitioning of s.

Example:

Input: "aab"
Output:
[
  ["aa","b"],
  ["a","a","b"]
]

本题要求把字符串s分割成若干个子串,使得每个子串都是回文串。如果有多种分割方法,输出所有的分割方案。 很有意思的一道题。我是这样做的:首先用DP求出任意一个子串s[i,…,j]是否为回文串,这就相当于知道了s中哪几个位置可以切割;然后就在s中DFS每个割点,求出所有的分割方案。
DP求s[i,…,j]是否为回文串的过程是这样的,如果s[i]==s[j],且dp[i+1][j-1]也是回文串,则dp[i][j]也是回文串。所以我们需要先求到长度比较短的s[i+1,j-1]是否为回文串,然后再求长度更长的是否为回文串。所以在helper函数的外层循环是子串的长度。

求到了任意一个子串是否为回文串之后,DFS每个割点就好了,这个和枚举排列情况很类似,就不再赘述了。完整代码如下:

class Solution {
private:
    void helper(const string& s, vector<vector<int> >& dp)
    {
        int n = s.size();
        for (int i = 0; i < n; ++i)
            dp[i][i] = 1; // 单个字符自身就是回文串
        for (int len = 2; len <= n; ++len) {
            for (int i = 0; i + len – 1 < n; ++i) {
                if (s[i] == s[i + len – 1] && ((i + 1 <= i + len – 2 && dp[i + 1][i + len – 2] == 1) || i + 1 > i + len – 2)) {
                    dp[i][i + len – 1] = 1;
                }
            }
        }
    }
    void dfs(const string& s, vector<vector<int> >& dp, vector<vector<string> >& ans, vector<string>& cand, int idx)
    {
        if (idx == s.size()) {
            ans.push_back(cand);
            return;
        }
        for (int i = idx; i < s.size(); ++i) {
            if (dp[idx][i] == 1) {
                cand.push_back(s.substr(idx, i – idx + 1));
                dfs(s, dp, ans, cand, i + 1);
                cand.pop_back();
            }
        }
    }
public:
    vector<vector<string> > partition(string s)
    {
        int n = s.size();
        vector<vector<int> > dp(n, vector<int>(n, 0));
        helper(s, dp);
        vector<vector<string> > ans;
        vector<string> cand;
        dfs(s, dp, ans, cand, 0);
        return ans;
    }
};

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

二刷。不用DP提前判断,而是每次都暴力判断是否为回文:

class Solution {
public:
	bool IsPal(const string &s, int l, int r) {
		if (l > r)return false;
		if (l == r)return true;
		while (l < r) {
			if (s[l] != s[r])break;
			++l;
			--r;
		}
		return l >= r;
	}
	void DFS(vector<vector<string>> &ans, vector<string> &cur, string &s, int idx) {
		int n = s.size();
		if (idx >= n) {
			ans.push_back(cur);
			return;
		}
		for (int i = idx; i < n; ++i) {
			if (IsPal(s, idx, i)) {
				cur.push_back(s.substr(idx, i - idx + 1));
				DFS(ans, cur, s, i + 1);
				cur.pop_back();
			}
		}
	}
	vector<vector<string>> partition(string s) {
		vector<vector<string>> ans;
		vector<string> cur;
		DFS(ans, cur, s, 0);
		return ans;
	}
};

本代码提交AC,用时12MS,比第一种方法慢,还是第一种方法提前求DP更高效。

LeetCode Minimum Index Sum of Two Lists

LeetCode Minimum Index Sum of Two Lists Suppose Andy and Doris want to choose a restaurant for dinner, and they both have a list of favorite restaurants represented by strings. You need to help them find out their common interest with the least list index sum. If there is a choice tie between answers, output all of them with no order requirement. You could assume there always exists an answer. Example 1:

Input:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]
Output: ["Shogun"]
Explanation: The only restaurant they both like is "Shogun".
Example 2:
Input:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["KFC", "Shogun", "Burger King"]
Output: ["Shogun"]
Explanation: The restaurant they both like and have the least index sum is "Shogun" with index sum 1 (0+1).
Note:
  1. The length of both lists will be in the range of [1, 1000].
  2. The length of strings in both lists will be in the range of [1, 30].
  3. The index is starting from 0 to the list length minus 1.
  4. No duplicates in both lists.

给定两个字符串数组,要求在两个数组中都出现的字符串在各自数组中的下标之和最小的字符串,如果有多个这样的字符串下标之和一样小,则都输出。 简单题,对两个数组,建立两个hash表,存储字符串对应下标的关系。然后遍历其中一个hash表,在如果该字符串在另一个hash表中存在,则更新下标之和。 代码如下: [cpp] class Solution { public: vector<string> findRestaurant(vector<string>& list1, vector<string>& list2) { unordered_map<string, int> hash1, hash2; for (int i = 0; i < list1.size(); ++i)hash1[list1[i]] = i; for (int i = 0; i < list2.size(); ++i)hash2[list2[i]] = i; int global_min_sum = INT_MAX; vector<string> ans; for (int i = 0; i < list1.size(); ++i) { if (hash2.find(list1[i]) != hash2.end()) { if (i + hash2[list1[i]] < global_min_sum) { global_min_sum = i + hash2[list1[i]]; ans.clear(); ans.push_back(list1[i]); } else if (i + hash2[list1[i]] == global_min_sum) { ans.push_back(list1[i]); } } } return ans; } }; [/cpp] 本代码提交AC,用时115MS。]]>

LeetCode Tag Validator

LeetCode Tag Validator Given a string representing a code snippet, you need to implement a tag validator to parse the code and return whether it is valid. A code snippet is valid if all the following rules hold:

  1. The code must be wrapped in a valid closed tag. Otherwise, the code is invalid.
  2. A closed tag (not necessarily valid) has exactly the following format : <TAG_NAME>TAG_CONTENT</TAG_NAME>. Among them, <TAG_NAME> is the start tag, and </TAG_NAME> is the end tag. The TAG_NAME in start and end tags should be the same. A closed tag is valid if and only if the TAG_NAME and TAG_CONTENT are valid.
  3. A valid TAG_NAME only contain upper-case letters, and has length in range [1,9]. Otherwise, the TAG_NAME is invalid.
  4. A valid TAG_CONTENT may contain other valid closed tags, cdata and any characters (see note1) EXCEPT unmatched <, unmatched start and end tag, and unmatched or closed tags with invalid TAG_NAME. Otherwise, the TAG_CONTENT is invalid.
  5. A start tag is unmatched if no end tag exists with the same TAG_NAME, and vice versa. However, you also need to consider the issue of unbalanced when tags are nested.
  6. A < is unmatched if you cannot find a subsequent >. And when you find a < or </, all the subsequent characters until the next > should be parsed as TAG_NAME (not necessarily valid).
  7. The cdata has the following format : <![CDATA[CDATA_CONTENT]]>. The range of CDATA_CONTENT is defined as the characters between <![CDATA[ and the first subsequent]]>.
  8. CDATA_CONTENT may contain any characters. The function of cdata is to forbid the validator to parse CDATA_CONTENT, so even it has some characters that can be parsed as tag (no matter valid or invalid), you should treat it as regular characters.
Valid Code Examples:
Input: "<DIV>This is the first line <![CDATA[<div>]]></DIV>"
Output: True
Explanation:
The code is wrapped in a closed tag : <DIV> and </DIV>.
The TAG_NAME is valid, the TAG_CONTENT consists of some characters and cdata.
Although CDATA_CONTENT has unmatched start tag with invalid TAG_NAME, it should be considered as plain text, not parsed as tag.
So TAG_CONTENT is valid, and then the code is valid. Thus return true.
Input: "<DIV>>>  ![cdata[]] <![CDATA[<div>]>]]>]]>>]</DIV>"
Output: True
Explanation:
We first separate the code into : start_tag|tag_content|end_tag.
start_tag -> "<DIV>"
end_tag -> "</DIV>"
tag_content could also be separated into : text1|cdata|text2.
text1 -> ">>  ![cdata[]] "
cdata -> "<![CDATA[<div>]>]]>", where the CDATA_CONTENT is "<div>]>"
text2 -> "]]>>]"
The reason why start_tag is NOT "<DIV>>>" is because of the rule 6.
The reason why cdata is NOT "<![CDATA[<div>]>]]>]]>" is because of the rule 7.
Invalid Code Examples:
Input: "<A>  <B> </A>   </B>"
Output: False
Explanation: Unbalanced. If "<A>" is closed, then "<B>" must be unmatched, and vice versa.
Input: "<DIV>  div tag is not closed  <DIV>"
Output: False
Input: "<DIV>  unmatched <  </DIV>"
Output: False
Input: "<DIV> closed tags with invalid tag name  <b>123</b> </DIV>"
Output: False
Input: "<DIV> unmatched tags with invalid tag name  </1234567890> and <CDATA[[]]>  </DIV>"
Output: False
Input: "<DIV>  unmatched start tag <B>  and unmatched end tag </C>  </DIV>"
Output: False
Note:
  1. For simplicity, you could assume the input code (including the any characters mentioned above) only contain letters, digits, '<','>','/','!','[',']' and ' '.

本题需要写一个检查简单html源代码标签是否匹配的程序。规则有很多,8条,比如tag长度必须在[1,9],且必须是大写字母,还有<![CDATA[CDATA_CONTENT]]>这个东西,经常会在html源代码中看见。 这题在比赛的时候没想清楚,思路比较乱。比赛结束之后,看了讨论区的解答,感觉思路好清晰,借鉴过来。 需要检查的主要有两个部分,一是Tag标签匹配,二是cdata。对于cdata,只要找到,则可以过滤掉<![CDATA[和]]>之间的所有内容。对于Tag标签匹配,类似括号匹配,可以用栈来实现。 但是因为Tag和cdata的开头都有<,我们匹配的时候, 应该从特殊到一般,即首先考虑是<![CDATA,其次考虑是</,然后考虑是<,最后就是一般性的字符了。 当遇到<![CDATA时,找到对应的]]>,下标快速跳到]]>的下一位。 当遇到</时,说明遇到了一个结束Tag,此时判断Tag是否合法,如果合法,从栈中弹出开始Tag,判断开始Tag和结束Tag是否匹配。 当遇到<时,说明遇到了一个开始Tag,判断Tag是否合法,如果合法,则压栈。 如果是一般性的字符,下标直接向前进。 需要注意的是,如果i!=0但是栈为空,说明当前的字符不在某个Tag标签内,比如这个样例:<![CDATA[wahaha]]]><![CDATA[]> wahaha]]>,一上来就是cdata,这是不合法的,因为所有内容都应该在标签对内。 完整代码如下: [cpp] class Solution { private: bool checkTag(const string &tag) { if (tag.size() < 1 || tag.size() > 9)return false; for (const auto &c : tag) { if (!isupper(c))return false; } return true; } public: bool isValid(string code) { stack<string> stk; int i = 0; while (i < code.size()) { if (i > 0 && stk.empty())return false; if (code.substr(i, 9) == "<![CDATA[") { int end = code.find("]]>", i); if (end == string::npos)return false; i = end + 3; } else if (code.substr(i, 2) == "</") { int end = code.find(‘>’, i); if (end == string::npos)return false; string tag = code.substr(i + 2, end – i – 2); if (!checkTag(tag))return false; if (stk.empty() || stk.top() != tag)return false; else stk.pop(); i = end + 1; } else if (code[i] == ‘<‘) { int end = code.find(‘>’, i); if (end == string::npos)return false; string tag = code.substr(i + 1, end – i – 1); if (!checkTag(tag))return false; stk.push(tag); i = end + 1; } else { ++i; } } return stk.empty(); } }; [/cpp] 本代码提交AC,用时12MS。]]>

LeetCode Find Duplicate File in System

LeetCode Find Duplicate File in System Given a list of directory info including directory path, and all the files with contents in this directory, you need to find out all the groups of duplicate files in the file system in terms of their paths. A group of duplicate files consists of at least two files that have exactly the same content. A single directory info string in the input list has the following format: "root/d1/d2/.../dm f1.txt(f1_content) f2.txt(f2_content) ... fn.txt(fn_content)" It means there are n files (f1.txt, f2.txtfn.txt with content f1_content, f2_contentfn_content, respectively) in directory root/d1/d2/.../dm. Note that n >= 1 and m >= 0. If m = 0, it means the directory is just the root directory. The output is a list of group of duplicate file paths. For each group, it contains all the file paths of the files that have the same content. A file path is a string that has the following format: "directory_path/file_name.txt" Example 1:

Input:
["root/a 1.txt(abcd) 2.txt(efgh)", "root/c 3.txt(abcd)", "root/c/d 4.txt(efgh)", "root 4.txt(efgh)"]
Output:
[["root/a/2.txt","root/c/d/4.txt","root/4.txt"],["root/a/1.txt","root/c/3.txt"]]
Note:
  1. No order is required for the final output.
  2. You may assume the directory name, file name and file content only has letters and digits, and the length of file content is in the range of [1,50].
  3. The number of files given is in the range of [1,20000].
  4. You may assume no files or directories share the same name in a same directory.
  5. You may assume each given directory info represents a unique directory. Directory path and file infos are separated by a single blank space.
Follow up beyond contest:
  1. Imagine you are given a real file system, how will you search files? DFS or BFS ?
  2. If the file content is very large (GB level), how will you modify your solution?
  3. If you can only read the file by 1kb each time, how will you modify your solution?
  4. What is the time complexity of your modified solution? What is the most time consuming part and memory consuming part of it? How to optimize?
  5. How to make sure the duplicated files you find are not false positive?

给定一个文件系统,要找出所有文件内容相同的集合,分group输出。 也是简单题,对所有文件根据content Hash,Hash到同一个桶内的文件内容相同,把它们group起来就好。 需要注意是只有当一个桶内的文件数目多于1个时,才输出该桶内所有文件。 代码如下: [cpp] class Solution { private: struct MyFile { string name, directory; MyFile(string n_, string d_) :name(n_), directory(d_) {}; }; public: vector<vector<string>> findDuplicate(vector<string>& paths) { unordered_map<string, vector<MyFile>> ump; for (int i = 0; i < paths.size(); ++i) { string line = paths[i] + " "; int pos_blank = line.find(" "); string directory = line.substr(0, pos_blank); int start = pos_blank + 1, end = line.find(" ", start); while (end != string::npos) { string one_file = line.substr(start, end – start); int pos_parenthesis = one_file.find("("); string name = one_file.substr(0, pos_parenthesis); string content = one_file.substr(pos_parenthesis + 1, one_file.size() – pos_parenthesis – 2); ump[content].push_back(MyFile(name, directory)); start = end + 1; end = line.find(" ", start); } } vector<vector<string>> ans; for (const auto &it : ump) { if (it.second.size() > 1) { vector<string> group; for (const auto &f : it.second) { group.push_back(f.directory + "/" + f.name); } ans.push_back(group); } } return ans; } }; [/cpp] 本代码提交AC,用时122MS。]]>

HDOJ 1159-Common Subsequence

HDOJ 1159-Common Subsequence

Common Subsequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 59402    Accepted Submission(s): 27503

Problem DescriptionA subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = <x1, x2, …, xm> another sequence Z = <z1, z2, …, zk> is a subsequence of X if there exists a strictly increasing sequence <i1, i2, …, ik> of indices of X such that for all j = 1,2,…,k, xij = zj. For example, Z = <a, b, f, c> is a subsequence of X = <a, b, c, f, b, c> with index sequence <1, 2, 4, 6>. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.
The program input is from a text file. Each data set in the file contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.

Sample Input

abcfbc abfcab
programming contest 
abcd mnp

Sample Output

4
2
0

SourceSoutheastern Europe 2003
RecommendIgnatius   |   We have carefully selected several similar problems for you:  10871176100310581069


求最长公共子序列。DP模板题,使用一个dp数组即可,用pre记录原来左上角的值。 代码如下,如果要求出一个lcs,参考《算法导论》P225,使用一个二维数组direction记录每个格子最大值来自哪个方向,重构lcs时从右下角不停的往前找。

#include <string>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int lcs(const string& a, const string& b)
{
    int n = a.size(), m = b.size();
    if (n == 0 || m == 0)
        return 0;
    vector<int> dp(m + 1, 0);
    for (int i = 1; i <= n; ++i) {
        int pre = 0;
        for (int j = 1; j <= m; ++j) {
            int cur = 0;
            if (a[i – 1] == b[j – 1])
                cur = pre + 1;
            else
                cur = max(dp[j – 1], dp[j]);
            pre = dp[j];
            dp[j] = cur;
        }
    }
    return dp[m]; // 最大值就是右下角的值
}
void construct_lcs(vector<vector<int> >& direction, const string& a, int i, int j, string& lcs)
{
    if (i == 0 || j == 0)
        return;
    if (direction[i][j] == 3) {
        construct_lcs(direction, a, i – 1, j – 1, lcs);
        lcs += string(1, a[i – 1]); // direction下标1对应a下标0,所以i-1
    }
    else if (direction[i][j] == 2) {
        construct_lcs(direction, a, i – 1, j, lcs);
    }
    else {
        construct_lcs(direction, a, i, j – 1, lcs);
    }
}
string lcs_string(const string& a, const string& b)
{
    int n = a.size(), m = b.size();
    if (n == 0 || m == 0)
        return 0;
    vector<int> dp(m + 1, 0);
    vector<vector<int> > direction(n + 1, vector<int>(m + 1, 0)); // 1:left,2:up,3:diagonal
    for (int i = 1; i <= n; ++i) {
        int pre = 0;
        for (int j = 1; j <= m; ++j) {
            int cur = 0;
            if (a[i – 1] == b[j – 1]) {
                cur = pre + 1;
                direction[i][j] = 3;
            }
            else {
                if (dp[j – 1] > dp[j]) {
                    cur = dp[j – 1];
                    direction[i][j] = 1;
                }
                else {
                    cur = dp[j];
                    direction[i][j] = 2;
                }
            }
            pre = dp[j];
            dp[j] = cur;
        }
    }
    string ans;
    construct_lcs(direction, a, n, m, ans); // 从右下角递归往前找,LCRS P225
    return ans;
}
int main()
{
    //freopen("input.txt", "r", stdin);
    string a, b;
    while (cin >> a >> b) {
        cout << lcs(a, b) << endl;
        //cout << lcs(a, b) << "\t" << lcs_string(a, b) << endl;;
    }
    return 0;
}

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

LeetCode Different Ways to Add Parentheses

241. Different Ways to Add Parentheses241. Different Ways to Add Parentheses

Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are +- and *.

Example 1:

Input: "2-1-1"
Output: [0, 2]
Explanation: 
((2-1)-1) = 0 
(2-(1-1)) = 2

Example 2:

Input: "2*3-4*5" Output: [-34, -14, -10, -10, 10] Explanation:  (2*(3-(4*5))) = -34  ((2*3)-(4*5)) = -14  ((2*(3-4))*5) = -10  (2*((3-4)*5)) = -10  (((2*3)-4)*5) = 10241. Different Ways to Add Parentheses

给定一个包含+-*的运算字符串,求所有加括号的方案计算到的值。
采用分治法的思路,尝试在每个操作符分成两个部分,这就相当于分别把操作符左右两边括起来单独计算。然后left和right分开进行递归,最后merge。递归的终止条件是当字符串中不包含操作符时,直接返回这个字符串对应的数值。
分治法很经典的例子。
代码如下:

class Solution {
private:
    int operate(int a, int b, char c)
    {
        switch (c) {
        case ‘+’:
            return a + b;
        case ‘-‘:
            return a – b;
        case ‘*’:
            return a * b;
        }
    }
public:
    vector<int> diffWaysToCompute(string input)
    {
        int n = input.size();
        vector<int> ans;
        bool found = false;
        for (int i = 0; i < n; ++i) {
            if (input[i] == ‘+’ || input[i] == ‘-‘ || input[i] == ‘*’) {
                found = true;
                vector<int> lefts = diffWaysToCompute(input.substr(0, i));
                vector<int> rights = diffWaysToCompute(input.substr(i + 1));
                for (int j = 0; j < lefts.size(); ++j) {
                    for (int k = 0; k < rights.size(); ++k) {
                        ans.push_back(operate(lefts[j], rights[k], input[i]));
                    }
                }
            }
        }
        if (!found)
            return { atoi(input.c_str()) };
        return ans;
    }
};

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

LeetCode Delete Operation for Two Strings

LeetCode Delete Operation for Two Strings Given two words word1 and word2, find the minimum number of steps required to make word1 and word2 the same, where in each step you can delete one character in either string. Example 1:

Input: "sea", "eat"
Output: 2
Explanation: You need one step to make "sea" to "ea" and another step to make "eat" to "ea".
Note:
  1. The length of given words won’t exceed 500.
  2. Characters in given words can only be lower-case letters.

给定两个字符串,求最少的删除次数,使得两个字符串相等。 这其实就是求两个字符串的最长公共子序列,因为最少的删除次数之后,两个字符串都变成了lcs,则每个字符串删除的次数就是原始长度减去lcs的长度。 代码如下: [cpp] class Solution { private: int lcs(const string& s1, const string& s2) { int n1 = s1.size(), n2 = s2.size(); vector<int> dp1(n2 + 1, 0), dp2(n2 + 1, 0); int ans = 0; for (int i = 1; i <= n1; ++i) { for (int j = 1; j <= n2; ++j) { if (s1[i – 1] == s2[j – 1])dp2[j] = dp1[j – 1] + 1; else dp2[j] = max(dp1[j], dp2[j – 1]); ans = max(ans, dp2[j]); } dp1.swap(dp2); } return ans; } public: int minDistance(string word1, string word2) { int l = lcs(word1, word2); return word1.size() – l + word2.size() – l; } }; [/cpp] 本代码提交AC,用时52MS。]]>

LeetCode Student Attendance Record I

LeetCode Student Attendance Record I You are given a string representing an attendance record for a student. The record only contains the following three characters:

  1. ‘A’ : Absent.
  2. ‘L’ : Late.
  3. ‘P’ : Present.
A student could be rewarded if his attendance record doesn’t contain more than one ‘A’ (absent) or more than two continuous ‘L’ (late). You need to return whether the student could be rewarded according to his attendance record. Example 1:
Input: "PPALLP"
Output: True
Example 2:
Input: "PPALLL"
Output: False

给定一个学生出席字符串,P表示出席了,A表示未出席,L表示迟到。如果有超过1个A或者超过2个L,则该同学不能被评奖,否则可以。先给定一个字符串,问该同学能否被评奖。 简单题,一遍扫描,记录A的数量以及连续L的数量,根据规则判断就好。 代码如下: [cpp] class Solution { public: bool checkRecord(string s) { int n = s.size(); int A = 0, L = 0; for(size_t i = 0; i < n; ++i){ if(s[i] == ‘A’){ ++A; if(A > 1) return false; } else if(s[i] == ‘L’){ int tmp = 0; while(i < n && s[i] == ‘L’){ ++tmp; ++i; } –i; // caution L = max(tmp, L); if(L > 2) return false; } } return true; } }; [/cpp] 本代码提交AC,用时3MS。]]>

LeetCode Longest Uncommon Subsequence I

LeetCode Longest Uncommon Subsequence I Given a group of two strings, you need to find the longest uncommon subsequence of this group of two strings. The longest uncommon subsequence is defined as the longest subsequence of one of these strings and this subsequence should not be any subsequence of the other strings. A subsequence is a sequence that can be derived from one sequence by deleting some characters without changing the order of the remaining elements. Trivially, any string is a subsequence of itself and an empty string is a subsequence of any string. The input will be two strings, and the output needs to be the length of the longest uncommon subsequence. If the longest uncommon subsequence doesn’t exist, return -1. Example 1:

Input: "aba", "cdc"
Output: 3
Explanation: The longest uncommon subsequence is "aba" (or "cdc"),
because "aba" is a subsequence of "aba",
but not a subsequence of any other strings in the group of two strings.
Note:
  1. Both strings’ lengths will not exceed 100.
  2. Only letters from a ~ z will appear in input strings.

求两个字符串的最长公共子序列。以前都是用DP求最长公共子序列,现在是要求最长公共子序列。 其实很简单的一个题,如果两个字符串完全相等的话,肯定没有公共子序列的,因为A字符串的任意一个子序列一定也是B字符串的子序列,所以返回-1。但是如果A和B不相等,则可以取A,B中较长的字符串,假设是A的话,则A肯定不是B的子序列,因为A的长度大于B,而且A不等于B。 所以就很简单了,如果A和B相等的话,返回-1,否则返回A,B中较大的长度。 代码如下: [cpp] class Solution { public: int findLUSlength(string a, string b) { return a == b ? -1 : max(a.size(), b.size()); } }; [/cpp] 本代码提交AC,用时0MS。]]>