Category Archives: LeetCode

LeetCode Range Addition II

LeetCode Range Addition II Given an m * n matrix M initialized with all 0‘s and several update operations. Operations are represented by a 2D array, and each operation is represented by an array with two positive integers a and b, which means M[i][j] should be added by one for all 0 <= i < a and 0 <= j < b. You need to count and return the number of maximum integers in the matrix after performing all the operations. Example 1:

Input:
m = 3, n = 3
operations = [[2,2],[3,3]]
Output: 4
Explanation:
Initially, M =
[[0, 0, 0],
 [0, 0, 0],
 [0, 0, 0]]
After performing [2,2], M =
[[1, 1, 0],
 [1, 1, 0],
 [0, 0, 0]]
After performing [3,3], M =
[[2, 2, 1],
 [2, 2, 1],
 [1, 1, 1]]
So the maximum integer in M is 2, and there are four of it in M. So return 4.
Note:
  1. The range of m and n is [1,40000].
  2. The range of a is [1,m], and the range of b is [1,n].
  3. The range of operations size won’t exceed 10,000.

给定一个全为0的矩阵M,和一系列的操作,每个操作都是一对(a,b),表示要对所有i在[0,a)和j在[0,b)的元素M[i][j],问最终矩阵M中最大元素的个数。 这个题稍微想一下就会发现非常简单。 假设矩阵的左下角坐标为(0,0),对于某一个操作(a,b),表示把以(0,0)和(a,b)为对角顶点的子矩阵元素加1。那么(a1,b1)和(a2,b2)两个操作的重叠区域(0,0)-(a2,b1)所在子矩阵的元素就被加了两次,他们的值最大且相同。 所以我们只需要遍历所有操作,分别找到行和列的最小值,则他们和原点围成的子矩阵的元素值最大,且相等。 代码非常简单,如下: [cpp] class Solution { public: int maxCount(int m, int n, vector<vector<int>>& ops) { int minRow = m, minCol = n; for (const auto &op : ops) { minRow = min(minRow, op[0]); minCol = min(minCol, op[1]); } return minRow*minCol; } }; [/cpp] 本代码提交AC,用时6MS。 ]]>

LeetCode Array Nesting

LeetCode Array Nesting A zero-indexed array A consisting of N different integers is given. The array contains all integers in the range [0, N – 1]. Sets S[K] for 0 <= K < N are defined as follows: S[K] = { A[K], A[A[K]], A[A[A[K]]], … }. Sets S[K] are finite for each K and should NOT contain duplicates. Write a function that given an array A consisting of N integers, return the size of the largest set S[K] for this array. Example 1:

Input: A = [5,4,0,3,1,6,2]
Output: 4
Explanation:
A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2.
One of the longest S[K]:
S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0}
Note:
  1. N is an integer within the range [1, 20,000].
  2. The elements of A are all distinct.
  3. Each element of array A is an integer within the range [0, N-1].

求嵌套集合的最大长度。首先给定原数组A,嵌套集合为S[K] = { A[K], A[A[K]], A[A[A[K]]], … },就是不断的把值当下标递归的取值,因为数组A中的值的范围也是0~n-1的,所以下标不会超出范围。 暴力方法就是求出每一个S[K]的大小,然后求最大值。但是仔细分析一个样例就会发现,很多S[K]集合是完全一样的,比如第一个样例中,S[0]和S[2]都等于{5,6,2,0},因为他们构成了一个循环。所以我们可以创建一个visited数组,访问过就置1,只对哪些visited为0的下标开始递归。这样对于第一个样例,其实只需要3次递归就可以了,也就是下标到值的构成的图中环的个数:{5,6,2,0},{3},{1,4}。所以总的复杂度其实只有O(n)。 代码如下: [cpp] class Solution { private: int nest(vector<int> &nums, vector<int> &visited, int k) { int ans = 0; while (visited[k] == 0) { visited[k] = 1; ++ans; k = nums[k]; } return ans; } public: int arrayNesting(vector<int>& nums) { int n = nums.size(); vector<int> visited(n, 0); int ans = 0; for (int i = 0; i < nums.size(); ++i) { if (visited[i] == 0) { int cur = nest(nums, visited, i); ans = max(ans, cur); } } return ans; } }; [/cpp] 本代码提交AC,用时39MS。]]>

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。]]>

LeetCode Construct String from Binary Tree

LeetCode Construct String from Binary Tree You need to construct a string consists of parenthesis and integers from a binary tree with the preorder traversing way. The null node needs to be represented by empty parenthesis pair “()”. And you need to omit all the empty parenthesis pairs that don’t affect the one-to-one mapping relationship between the string and the original binary tree. Example 1:

Input: Binary tree: [1,2,3,4]
       1
     /   \
    2     3
   /
  4
Output: "1(2(4))(3)"
Explanation: Originallay it needs to be "1(2(4)())(3()())",
but you need to omit all the unnecessary empty parenthesis pairs.
And it will be "1(2(4))(3)".
Example 2:
Input: Binary tree: [1,2,3,null,4]
       1
     /   \
    2     3
     \
      4
Output: "1(2()(4))(3)"
Explanation: Almost the same as the first example,
except we can't omit the first parenthesis pair to break the one-to-one mapping relationship between the input and the output.

本题要求把一棵二叉树转换为一个字符串,使用先序遍历的方法,并且左右子树需要用括号括起来,但是要保证从该字符串能唯一恢复回原来的二叉树,而且要去掉不必要的空括号。 首先明确先序遍历:根左右,不难。然后要删掉不必要的空括号,观察第二个样例,发现如果左孩子为空,则左孩子的空括号不能省,但是如果右孩子或者左右孩子都为空,则他们的空括号可以省略。所以分几种情况递归求解即可。 代码如下: [cpp] class Solution { public: string tree2str(TreeNode* t) { if (!t)return ""; if (!t->left && !t->right)return to_string(t->val); if (!t->left)return to_string(t->val) + "()(" + tree2str(t->right) + ")"; if (!t->right)return to_string(t->val) + "(" + tree2str(t->left) + ")"; return to_string(t->val) + "(" + tree2str(t->left) + ")(" + tree2str(t->right) + ")"; } }; [/cpp] 本代码提交AC,用时19MS。]]>

LeetCode Can Place Flowers

LeetCode Can Place Flowers Suppose you have a long flowerbed in which some of the plots are planted and some are not. However, flowers cannot be planted in adjacent plots – they would compete for water and both would die. Given a flowerbed (represented as an array containing 0 and 1, where 0 means empty and 1 means not empty), and a number n, return if n new flowers can be planted in it without violating the no-adjacent-flowers rule. Example 1:

Input: flowerbed = [1,0,0,0,1], n = 1
Output: True
Example 2:
Input: flowerbed = [1,0,0,0,1], n = 2
Output: False
Note:
  1. The input array won’t violate no-adjacent-flowers rule.
  2. The input array size is in the range of [1, 20000].
  3. n is a non-negative integer which won’t exceed the input array size.

今天第一次做Leetcode的weekly contest,AC了三题,最后一题看起来好繁琐,没A。 第一题,简单贪心即可,从第0个位置开始,检查每个位置的前后是否为1,如果不为1,说明该位置可以种花,填上1,最后统计新填上的1的个数和n的关系。 代码如下: [cpp] class Solution { public: bool canPlaceFlowers(vector<int>& flowerbed, int n) { int m = flowerbed.size(); for (int i = 0; i < m; ++i) { if (flowerbed[i] == 0) { if (i – 1 >= 0 && flowerbed[i – 1] == 1)continue; if (i + 1 < m&&flowerbed[i + 1] == 1)continue; flowerbed[i] = 1; –n; } } return n <= 0; } }; [/cpp] 本代码提交AC,用时26MS。]]>

LeetCode House Robber III

LeetCode House Robber III The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the “root.” Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that “all houses in this place forms a binary tree”. It will automatically contact the police if two directly-linked houses were broken into on the same night. Determine the maximum amount of money the thief can rob tonight without alerting the police. Example 1:

     3
    / \
   2   3
    \   \
     3   1
Maximum amount of money the thief can rob = 3 + 3 + 1 = 7. Example 2:
     3
    / \
   4   5
  / \   \
 1   3   1
Maximum amount of money the thief can rob = 4 + 5 = 9. Credits: Special thanks to @dietpepsi for adding this problem and creating all test cases.
这次要偷的房子分布在一棵二叉树上。。。 规则是有边相连的两个节点不能同时被偷,问最多能偷到多少钱。 我开始想的和LeetCode House Robber类似,一个节点要么偷,要么不偷。不偷得到的钱是上一个节点偷或不偷的最大值;偷得到的钱是上一个节点不偷加上该节点的钱数。使用递归的方法求解。 代码如下: [cpp] class Solution { private: void dfs(TreeNode* root, int& norobsum, int& robsum) { int nrs = max(norobsum, robsum); int rs = norobsum + root->val; norobsum = nrs; robsum = rs; if (root->left)dfs(root->left, norobsum, robsum); if (root->right)dfs(root->right, norobsum, robsum); } public: int rob(TreeNode* root) { if (!root)return 0; int norobsum = 0, robsum = 0; dfs(root, norobsum, robsum); return max(norobsum, robsum); } }; [/cpp] 本代码提交WA,错误样例如下:
     1
    / \
   2   3
令m[i]=(u,v)表示截至目前偷i节点得到u钱,不偷得到v钱。则m[1]=(1,0),递归进入左孩子,m[2]=(2+0,max(1,0))=(2,1),递归进入右孩子,m[3]=(3+1,max(2,1))=(4,2)。导致算出来的结果是4。这是因为3号节点偷的时候,其实不是3+1,1号节点的状态不能简单等价于2号节点的状态。 正确的做法应该是这样的,对于节点i,先算到左右节点偷或者不偷的钱数,即m[l]=(lrs,lnrs)和m[r]=(rrs,rnrs)。那么i偷的话,则左右节点都不能偷了=lnrs+rnrs+i.val;如果i不偷的话,则左右节点都可以偷或者不偷=max(lnrs,lrs)+max(rnrs,rrs),所以m[i]=(lnrs+rnrs+i.val, max(lnrs,lrs)+max(rnrs,rrs))。 代码如下: [cpp] class Solution { private: void dfs(TreeNode* root, int& norobsum, int& robsum) { int lnrs = 0, lrs = 0, rnrs = 0, rrs = 0; if (root->left)dfs(root->left, lnrs, lrs); if (root->right)dfs(root->right, rnrs, rrs); norobsum = max(lnrs, lrs) + max(rnrs, rrs); robsum = lnrs + rnrs + root->val; } public: int rob(TreeNode* root) { if (!root)return 0; int norobsum = 0, robsum = 0; dfs(root, norobsum, robsum); return max(norobsum, robsum); } }; [/cpp] 本代码提交AC,用时16MS。]]>

LeetCode House Robber II

213. House Robber II213. House Robber II

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Example 1:

Input: [2,3,2]
Output: 3
Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2),
             because they are adjacent houses.

Example 2:

Input: [1,2,3,1] Output: 4 Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).              Total amount you can rob = 1 + 3 = 4.213. House Robber II

本题是LeetCode House Robber的扩展版,当首尾相连时,怎样偷到最多的钱。 因为首尾相连,所以如果偷了第一家,就不能偷最后一家;或者如果偷了最后一家,就不能偷第一家。所以我们可以把数组分成两个部分,一部分是去掉最后一家,求一个最大值;另一部分是去掉第一家,求一个最大值。最优结果就是这两个最大值的最大值。 代码如下:

class Solution {
public:
    int rob(vector<int>& nums)
    {
        if (nums.size() == 0)
            return 0;
        if (nums.size() == 1)
            return nums[0];
        int ans1 = 0, ans2 = 0;
        vector<vector<int> > dp1(nums.size() + 1, vector<int>(2, 0)), dp2(nums.size() + 1, vector<int>(2, 0));
        for (int i = 1; i < nums.size(); ++i) { // 不偷最后一家
            dp1[i][0] = max(dp1[i – 1][0], dp1[i – 1][1]);
            dp1[i][1] = dp1[i – 1][0] + nums[i – 1];
            ans1 = max(ans1, max(dp1[i][0], dp1[i][1]));
        }
        for (int i = 2; i <= nums.size(); ++i) { // 不偷第一家
            dp2[i][0] = max(dp2[i – 1][0], dp2[i – 1][1]);
            dp2[i][1] = dp2[i – 1][0] + nums[i – 1];
            ans2 = max(ans2, max(dp2[i][0], dp2[i][1]));
        }
        return max(ans1, ans2);
    }
};

本代码提交AC,用时3MS。
更漂亮的代码是:

class Solution {
private:
    int subrob(const vector<int>& nums, int left, int right)
    {
        int robsum = 0, norobsum = 0;
        for (int i = left; i <= right; ++i) {
            int nrs = max(robsum, norobsum);
            int rs = norobsum + nums[i];
            norobsum = nrs;
            robsum = rs;
        }
        return max(robsum, norobsum);
    }
public:
    int rob(vector<int>& nums)
    {
        int n = nums.size();
        if (n == 0)
            return 0;
        if (n == 1)
            return nums[0];
        return max(subrob(nums, 0, n – 2), subrob(nums, 1, n – 1));
    }
};

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

二刷。常规解法:

class Solution {
private:
	int rob_max(vector<int>& nums) {
		int n = nums.size();
		vector<int> dp(n, 0);
		dp[0] = nums[0];
		dp[1] = max(nums[0], nums[1]);
		int ans = max(dp[0], dp[1]);
		for (int i = 2; i < n; ++i) {
			dp[i] = max(nums[i] + dp[i - 2], dp[i - 1]);
			ans = max(ans, dp[i]);
		}
		return ans;
	}
public:
	int rob(vector<int>& nums) {
		int n = nums.size();
		if (n == 0)return 0;
		if (n == 1)return nums[0];
		if (n == 2)return max(nums[0], nums[1]);
		vector<int> money1(nums.begin(), nums.end() - 1), money2(nums.begin() + 1, nums.end());
		return max(rob_max(money1), rob_max(money2));
	}
};

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

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。