Monthly Archives: June 2017

LeetCode Maximum Product of Three Numbers

LeetCode Maximum Product of Three Numbers Given an integer array, find three numbers whose product is maximum and output the maximum product. Example 1:

Input: [1,2,3]
Output: 6
Example 2:
Input: [1,2,3,4]
Output: 24
Note:
  1. The length of the given array will be in range [3,104] and all elements are in the range [-1000, 1000].
  2. Multiplication of any three numbers in the input won’t exceed the range of 32-bit signed integer.

给定一个整数数组,选出三个数,使得乘积最大。 整数数组中可能有负数,所以我们先对数组从小到大排序。如果最小值都大于0,说明没有负数,则三数乘积最大就是最大的前3个数的乘积。 如果有负数,且至少有两个负数,则还需要判断一下最小的两个负数乘以最大的正数的乘积,这个数和前一种情况的大小关系。 代码如下: [cpp] class Solution { public: int maximumProduct(vector<int>& nums) { int n = nums.size(); sort(nums.begin(), nums.end()); int ans1 = nums[n – 1] * nums[n – 2] * nums[n – 3], ans2 = 0; if (nums[0] > 0)return ans1; if (nums[0] < 0 && nums[1] < 0)ans2 = nums[0] * nums[1] * nums[n – 1]; return max(ans1, ans2); } }; [/cpp] 本代码提交AC,用时73MS。]]>

LeetCode Basic Calculator II

LeetCode Basic Calculator II Implement a basic calculator to evaluate a simple expression string. The expression string contains only non-negative integers, +, -, *, / operators and empty spaces . The integer division should truncate toward zero. You may assume that the given expression is always valid. Some examples:

"3+2*2" = 7
" 3/2 " = 1
" 3+5 / 2 " = 5
Note: Do not use the eval built-in library function.
本题是LeetCode Basic Calculator的简化版,去掉了括号,增加了乘除法。但是算法都是一模一样的,先把中缀转换为后缀,然后用栈求值。 代码如下: [cpp] // 优先级 unordered_map<string, int> priority = { {"+", 1},{"-", 1},{"*", 2},{"/", 2} }; class Solution { private: void push(stack<string> &numbers, stack<string> &opers, const string& numOrop) { if (isdigit(numOrop[0])) { numbers.push(numOrop); } else { if (numOrop == ")") { while (opers.top() != "(") { numbers.push(opers.top()); opers.pop(); } opers.pop(); } else if (numOrop == "(") { opers.push(numOrop); } else if (opers.empty() || opers.top() == "(") { opers.push(numOrop); } else if (priority[numOrop] > priority[opers.top()]) { opers.push(numOrop); } else { while (!opers.empty() && opers.top() != "(" && priority[numOrop] <= priority[opers.top()]) { numbers.push(opers.top()); opers.pop(); } opers.push(numOrop); } } } // 中缀转后缀表达式 list<string> in2post(const string& s) { stack<string> numbers, opers; int start = 0, end = 1, n = s.size(); while (start < n) { while (start < n&&s[start] == ‘ ‘)++start; if (start >= n)break; if (isdigit(s[start])) { end = start + 1; while (end < n&&isdigit(s[end]))++end; string num = s.substr(start, end – start); push(numbers, opers, num); start = end; } else { string op = string(1, s[start]); push(numbers, opers, op); ++start; } } while (!opers.empty()) { numbers.push(opers.top()); opers.pop(); } list<string> ans; while(!numbers.empty()) { ans.push_front(numbers.top()); numbers.pop(); } return ans; } // 求值后缀表达式的值 int eval(list<string>& post) { int ans = 0; stack<int> numbers; for (const auto& s : post) { if (priority.find(s) != priority.end()) { int num2 = numbers.top(); numbers.pop(); int num1 = numbers.top(); numbers.pop(); if (s == "+")numbers.push(num1 + num2); else if (s == "-")numbers.push(num1 – num2); else if (s == "*")numbers.push(num1*num2); else numbers.push(num1 / num2); } else numbers.push(stoi(s)); } return numbers.top(); } public: int calculate(string s) { list<string> ans = in2post(s); return eval(ans); } }; [/cpp] 本代码提交AC,用时85MS。]]>

LeetCode Basic Calculator

224. Basic Calculator 224. Basic Calculator

Implement a basic calculator to evaluate a simple expression string.

The expression string may contain open ( and closing parentheses ), the plus + or minus sign -non-negative integers and empty spaces .

Example 1:

Input: "1 + 1"
Output: 2

Example 2:

Input: " 2-1 + 2 "
Output: 3

Example 3:

Input: "(1+(4+5+2)-3)+(6+8)"
Output: 23

Note:

  • You may assume that the given expression is always valid.
  • Do not use the eval built-in library function.

给定一个字符串表达式,要求求解该表达式的值。 使用栈解决。我们通常看到的表达式称为中缀表达式,需要把它转换为后缀表达式,比如1+((2+3)×4)-5转换为1 2 3 + 4 × + 5 -。我们可以很容易用栈求解后缀表达式,只需要遍历后缀表达式,把遇到的操作数压栈,只要遇到运算符,就从栈中弹出两个操作数,进行运算,再把运算结果压栈。最后栈中只能得到一个值,就是整个表达式的值。 所以问题的关键就是怎样把中缀表达式转换为后缀表达式。 使用两个栈,一个栈保存操作数numbers,另一个栈保存运算符opers。遍历原字符串,按如下规则进行压栈和弹栈:

  • 如果是操作数,直接压入numbers
  • 如果是操作符op:
    1. 如果op为左括号“(”,则直接把op压入opers
    2. 如果op为右括号“)”,则把opers的运算符不断弹栈并压入numbers,直到栈顶为左括号“(”,此时将这一对括号丢弃
    3. 如果opers为空,或者opers栈顶为左括号“(”,则直接把op压入opers
    4. 此时,栈顶肯定不可能是括号了,如果op的优先级高于opers栈顶的优先级,则直接把op压入opers
    5. 否则,把opers栈顶的运算符不断弹栈并压入numbers,直到栈顶为左括号,或者op的优先级高于opers栈顶的优先级。把op压入opers

如果是操作符op,下面的1~5的判断规则是有先后顺序的,需要先判断是否为括号,再判断是否是一般的运算符。 运算符的优先级是,+-优先级相同,*/优先级相同,且+-的优先级低于*/。 得到中缀表达式的后缀表达式之后,再用开头提到的栈求解。后缀表达式的求值就非常简单了。 完整代码如下:

// 优先级
unordered_map<string, int> priority = { { "+", 1 }, { "-", 1 }, { "*", 2 }, { "/", 2 } };
class Solution {
private:
    void push(stack<string>& numbers, stack<string>& opers, const string& numOrop)
    {
        if (isdigit(numOrop[0])) {
            numbers.push(numOrop);
        }
        else {
            if (numOrop == ")") {
                while (opers.top() != "(") {
                    numbers.push(opers.top());
                    opers.pop();
                }
                opers.pop();
            }
            else if (numOrop == "(") {
                opers.push(numOrop);
            }
            else if (opers.empty() || opers.top() == "(") {
                opers.push(numOrop);
            }
            else if (priority[numOrop] > priority[opers.top()]) {
                opers.push(numOrop);
            }
            else {
                while (!opers.empty() && opers.top() != "(" && priority[numOrop] <= priority[opers.top()]) {
                    numbers.push(opers.top());
                    opers.pop();
                }
                opers.push(numOrop);
            }
        }
    }
    // 中缀转后缀表达式
    list<string> in2post(const string& s)
    {
        stack<string> numbers, opers;
        int start = 0, end = 1, n = s.size();
        while (start < n) {
            while (start < n && s[start] == ‘ ‘)
                ++start;
            if (start >= n)
                break;
            if (isdigit(s[start])) {
                end = start + 1;
                while (end < n && isdigit(s[end]))
                    ++end;
                string num = s.substr(start, end – start);
                push(numbers, opers, num);
                start = end;
            }
            else {
                string op = string(1, s[start]);
                push(numbers, opers, op);
                ++start;
            }
        }
        while (!opers.empty()) {
            numbers.push(opers.top());
            opers.pop();
        }
        list<string> ans;
        while (!numbers.empty()) {
            ans.push_front(numbers.top());
            numbers.pop();
        }
        return ans;
    }
    // 求值后缀表达式的值
    int eval(list<string>& post)
    {
        int ans = 0;
        stack<int> numbers;
        for (const auto& s : post) {
            if (priority.find(s) != priority.end()) {
                int num2 = numbers.top();
                numbers.pop();
                int num1 = numbers.top();
                numbers.pop();
                if (s == "+")
                    numbers.push(num1 + num2);
                else if (s == "-")
                    numbers.push(num1 – num2);
                else if (s == "*")
                    numbers.push(num1 * num2);
                else
                    numbers.push(num1 / num2);
            }
            else
                numbers.push(stoi(s));
        }
        return numbers.top();
    }
public:
    int calculate(string s)
    {
        list<string> ans = in2post(s);
        return eval(ans);
    }
};

本代码提交AC,用时92MS。
参考:http://blog.csdn.net/antineutrino/article/details/6763722

二刷。push函数实际上只有3个分支就可以了,上面的过于复杂,看下面:

unordered_map<string, int> priority = { {"+",1},{"-",1},{"*",2},{"/",2} };

class Solution {
private:
	bool IsDigit(char c) {
		return c >= '0'&&c <= '9';
	}

	vector<string> ParseString(const string &s) {
		vector<string> vec;
		int n = s.size();
		int i = 0, j = 0;
		while (i < n) {
			while (i < n&&s[i] == ' ')++i;
			if (i >= n)break;

			if (!IsDigit(s[i])) {
				vec.push_back(string(1, s[i]));
				++i;
			}
			else {
				j = i + 1;
				while (j < n&&IsDigit(s[j]))++j;
				vec.push_back(s.substr(i, j - i));
				i = j;
			}
		}
		return vec;
	}

	list<string> In2Post(const vector<string> &vec) {
		stack<string> numbers, opers;
		for (int i = 0; i < vec.size(); ++i) {
			if (IsDigit(vec[i][0])) {
				numbers.push(vec[i]);
			}
			else {
				if (vec[i] == ")") { // 右括号
					while (opers.top() != "(") {
						numbers.push(opers.top());
						opers.pop();
					}
					opers.pop();
				}
				else if (vec[i] == "(") { // 左括号
					opers.push(vec[i]);
				}
				else { // 操作符
					while (!opers.empty() && opers.top() != "("&&priority[vec[i]] <= priority[opers.top()]) {
						numbers.push(opers.top());
						opers.pop();
					}
					opers.push(vec[i]);
				}
			}
		}
		
		while (!opers.empty()) {
			numbers.push(opers.top());
			opers.pop();
		}
		list<string> lst;
		while (!numbers.empty()) {
			lst.push_front(numbers.top());
			numbers.pop();
		}
		return lst;
	}

	int Evaluate(const list<string> &lst) {
		stack<string> stk;
		for (list<string>::const_iterator it = lst.begin(); it != lst.end(); ++it) {
			if (IsDigit((*it)[0])) {
				stk.push(*it);
			}
			else {
				int b = atoi(stk.top().c_str());
				stk.pop();
				int a= atoi(stk.top().c_str());
				stk.pop();
				if (*it == "+") {
					stk.push(to_string(a + b));
				}
				else if (*it == "-") {
					stk.push(to_string(a - b));
				}
			}
		}
		return atoi(stk.top().c_str());
	}

public:
	int calculate(string s) {

		vector<string> vec = ParseString(s);
		list<string> lst = In2Post(vec);
		return Evaluate(lst);
	}
};

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

LeetCode Mini Parser

LeetCode Mini Parser Given a nested list of integers represented as a string, implement a parser to deserialize it. Each element is either an integer, or a list — whose elements may also be integers or other lists. Note: You may assume that the string is well-formed:

  • String is non-empty.
  • String does not contain white spaces.
  • String contains only digits 0-9, [, - ,, ].
Example 1:
Given s = "324",
You should return a NestedInteger object which contains a single integer 324.
Example 2:
Given s = "[123,[456,[789]]]",
Return a NestedInteger object containing a nested list with 2 elements:
1. An integer containing value 123.
2. A nested list containing two elements:
    i.  An integer containing value 456.
    ii. A nested list with one element:
         a. An integer containing value 789.

给定一个嵌套的字符串,要求把它解析成一个NestedInteger。 解法1,使用栈。遇到左括号时,增加一个空的NestedInteger实例,压栈。遇到逗号时,把前面的数add到栈顶的NestedInteger中。遇到右括号时,把栈顶的NestedInteger弹栈,并add到新的栈顶(相当于前一个)NestedInteger中。最后栈顶只有一个元素,返回该元素即可。 代码如下: [cpp] class Solution { public: NestedInteger deserialize(string s) { auto isnumber = [](char c) {return c == ‘-‘ || isdigit(c); }; stack<NestedInteger> stk; stk.push(NestedInteger()); for (auto it = s.begin(); it != s.end();) { if (isnumber(*it)) { auto it2 = find_if_not(it, s.end(), isnumber); int v = stoi(string(it, it2)); stk.top().add(NestedInteger(v)); it = it2; } else { if (*it == ‘[‘) { stk.push(NestedInteger()); } else if (*it == ‘]’) { NestedInteger tmp = stk.top(); stk.pop(); stk.top().add(tmp); } ++it; } } return stk.top().getList().front(); } }; [/cpp] 本代码提交AC,用时19MS。 解法2,递归法。如果当前的字符串是一个裸的整数的话,类似于样例1,则直接返回以该数为参数的NestedInteger;否则剥掉左括号[,递归反序列化,把递归的结果add到当前的NestedInteger中。 代码如下: [cpp] class Solution { private: NestedInteger deserialize(istringstream &in) { int number; if (in >> number) return NestedInteger(number); in.clear(); in.get(); NestedInteger list; while (in.peek() != ‘]’) { list.add(deserialize(in)); if (in.peek() == ‘,’)in.get(); } in.get(); return list; } public: NestedInteger deserialize(string s) { istringstream in(s); return deserialize(in); } }; [/cpp] 本代码提交AC,用时19MS。 参考1,栈:https://discuss.leetcode.com/topic/54904/c-non-recursive-one-pass-solution-using-stack-a-possible-implementation-of-nestedinteger 参考2,递归:https://discuss.leetcode.com/topic/54258/python-c-solutions/10]]>

LeetCode Unique Substrings in Wraparound String

LeetCode Unique Substrings in Wraparound String Consider the string s to be the infinite wraparound string of “abcdefghijklmnopqrstuvwxyz”, so s will look like this: “…zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd….”. Now we have another string p. Your job is to find out how many unique non-empty substrings of p are present in s. In particular, your input is the string p and you need to output the number of different non-empty substrings of p in the string s. Note: p consists of only lowercase English letters and the size of p might be over 10000. Example 1:

Input: "a"
Output: 1
Explanation: Only the substring "a" of string "a" is in the string s.
Example 2:
Input: "cac"
Output: 2
Explanation: There are two substrings "a", "c" of string "cac" in the string s.
Example 3:
Input: "zab"
Output: 6
Explanation: There are six substrings "z", "a", "b", "za", "ab", "zab" of string "zab" in the string s.

给定一个a-z的无限循环字符串s,比如…zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd….。再给定一个字符串p,问p有多少个子串是在s中的。 在s中的子串需要满足一定的条件,比如单个字符可以,还有就是连续的字符串,即abcd…之类的。 注意第二个样例中,p有两个相同的子串c,但是结果中只统计一次,所以比如p中有多个以同一个字符结尾的子串,我们只需要统计最长的那个就好了。比如P=”abcdefgxxxxcdefgyyy”。以g结尾的连续子串有两个,分别是abcdefg和cdefg,但是我们只需要保留前者就好了,因为前者最长,它的所有子串已经包含后者的所有子串了。而子串的长度就是以g为结尾且在s中的子串的长度,比如这里就是7。 所以我们只需要统计以每个字符结尾的最长连续子串的长度,然后把所有长度加起来,就是最终结果。 注意abcdefg以g结尾的长度是7,也就是abcdefg有7个子串是在s中的。abcdefg也包含abcdef,以f结尾的长度是6,也就是abcdef有6个子串在s中。 代码如下: [cpp] class Solution { public: int findSubstringInWraproundString(string p) { vector<int> count(26, 0); int len = 0; for (int i = 0; i < p.size(); ++i) { if (i > 0 && (p[i] – p[i – 1] == 1 || p[i] – p[i – 1] == -25))++len; else len = 1; count[p[i] – ‘a’] = max(count[p[i] – ‘a’], len); } int ans = 0; for (int i = 0; i < 26; ++i)ans += count[i]; return ans; } }; [/cpp] 本代码提交AC,用时9MS。]]>

LeetCode Maximal Square

221. Maximal Square

Given a 2D binary matrix filled with 0’s and 1’s, find the largest square containing only 1’s and return its area.

Example:

Input: 

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

Output: 4

给定一个0,1矩阵,问矩阵中最大的全是1的正方形的面积是多少。 使用DP求解,假设dp[i][j]表示以点(i,j)为右下角的正方形的最大边长,则有dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1。
对于点(i,j),我们已经知道以该点的左边、上边和左上角的点为正方形右下角的点能得到的最大的正方形的边长。最好的情况是,如果这三个点能构成的最大正方形的边长相等,则加上点(i,j)之后,边长会扩大1。如下图红色的1,他的左边、上边和左上角的点为正方形右下角的点能得到的最大的正方形的边长都是2,所以加上该红色1之后,最大的边长变成了3。

0 0 0 0 0
0 1 1 1 0
0 1 1 1 0
0 1 1 1 0
0 0 0 0 0

再比如红色1的左边那个点的边长只有1,则红色1最多只能扩展成边长为1+1的正方形。所以这个递推公式是合理的:dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1。

0 0 0 0 0
0 1 1 1 0
0 1 1 1 0
0 0 1 1 0
0 0 0 0 0

有递推公式就好办了,直接O(n^2)DP,代码如下:

class Solution {
public:
    int maximalSquare(vector<vector<char> >& matrix)
    {
        if (matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size(), n = matrix[0].size();
        vector<vector<int> > dp(m, vector<int>(n, 0));
        int maxLen = 0;
        for (size_t i = 0; i < m; ++i) {
            dp[i][0] = (matrix[i][0] == ‘1’ ? 1 : 0);
            maxLen = max(maxLen, dp[i][0]);
        }
        for (size_t j = 0; j < n; ++j) {
            dp[0][j] = (matrix[0][j] == ‘1’ ? 1 : 0);
            maxLen = max(maxLen, dp[0][j]);
        }
        for (size_t i = 1; i < m; ++i) {
            for (size_t j = 1; j < n; ++j) {
                if (matrix[i][j] == ‘1’) {
                    dp[i][j] = min(min(dp[i][j – 1], dp[i – 1][j]), dp[i – 1][j – 1]) + 1;
                    maxLen = max(maxLen, dp[i][j]);
                }
            }
        }
        return maxLen * maxLen;
    }
};

本代码提交AC,用时6MS。
因为dp[i][j]实际上只和之前的三个值有关,所以可以节省空间。代码如下:

class Solution {
public:
    int maximalSquare(vector<vector<char> >& matrix)
    {
        if (matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size(), n = matrix[0].size();
        vector<int> dp(n + 1, 0);
        int maxLen = 0, last_topleft = 0; // dp[i][j]的左上角那个值
        for (size_t i = 1; i <= m; ++i) {
            for (size_t j = 1; j <= n; ++j) {
                int tmp = dp[j];
                if (matrix[i – 1][j – 1] == ‘1’) {
                    dp[j] = min(min(dp[j], dp[j – 1]), last_topleft) + 1;
                    maxLen = max(maxLen, dp[j]);
                }
                else {
                    dp[j] = 0;
                }
                last_topleft = tmp;
            }
        }
        return maxLen * maxLen;
    }
};

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

LeetCode Gas Station

134. Gas Station

There are N gas stations along a circular route, where the amount of gas at station i is gas[i].

You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.

Return the starting gas station’s index if you can travel around the circuit once in the clockwise direction, otherwise return -1.

Note:

  • If there exists a solution, it is guaranteed to be unique.
  • Both input arrays are non-empty and have the same length.
  • Each element in the input arrays is a non-negative integer.

Example 1:

Input: 
gas  = [1,2,3,4,5]
cost = [3,4,5,1,2]

Output: 3

Explanation:
Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 4. Your tank = 4 - 1 + 5 = 8
Travel to station 0. Your tank = 8 - 2 + 1 = 7
Travel to station 1. Your tank = 7 - 3 + 2 = 6
Travel to station 2. Your tank = 6 - 4 + 3 = 5
Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3.
Therefore, return 3 as the starting index.

Example 2:

Input: 
gas  = [2,3,4]
cost = [3,4,3]

Output: -1

Explanation:
You can't start at station 0 or 1, as there is not enough gas to travel to the next station.
Let's start at station 2 and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 0. Your tank = 4 - 3 + 2 = 3
Travel to station 1. Your tank = 3 - 3 + 3 = 3
You cannot travel back to station 2, as it requires 4 unit of gas but you only have 3.
Therefore, you can't travel around the circuit once no matter where you start.

给定一个圆环,环上有n个加油站,每个加油站有gas[i]升油,一辆车从第i个加油站走到第i+1个加油站需要耗费cost[i]升油。问该车能否绕行圆环一周,如果能给出起点。

  1. 对于某个点i,如果gas[i]-cost[i]>=0,则车能从i走到i+1。
  2. 如果从A出发,无法到达B(但能到达B-1),则所有在A、B之间的起点都无法到达B。反证法,想象一下,如果A,B之间有一起点C能到达B,则说明C到B之间总的gas大于中的cost,又因为C在A,B之间,A能到达C,说明A到C之间中的gas大于cost。那么,既然A能到C,C能到B,则A能到B,和前提假设矛盾,所以原命题成立。
  3. 如果圆环上中的gas大于总的cost,则一定有一个解。
  4. 假设解的起点为i,则从i肯定能到达环上的任意一点。

基于以上的讨论,本题的解法是这样的:

  1. 从0开始走,如果能到达i,但无法到达i+1,则所有0~i的点都不是起点,因为根据讨论2,0~i的点都无法到达i+1,而根据讨论4,0~i的点不可能是解。
  2. 所以尝试起点为i+1,继续往前走。
  3. 最后,如果满足3,因为其他所有点都不可能是正确答案,且根据题目,解是唯一的,所以上述过程找到的起点就是正确解。

完整代码如下:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost)
    {
        int gasSum = 0, costSum = 0, tank = 0, start = 0;
        for (int i = 0; i < gas.size(); ++i) {
            gasSum += gas[i];
            costSum += cost[i];
            tank += (gas[i] – cost[i]);
            if (tank < 0) {
                start = i + 1;
                tank = 0;
            }
        }
        if (gasSum < costSum)
            return -1;
        else
            return start;
    }
};

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

LeetCode Word Break

139. Word Break

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

Note:

  • The same word in the dictionary may be reused multiple times in the segmentation.
  • You may assume the dictionary does not contain duplicate words.

Example 1:

Input: s = "leetcode", wordDict = ["leet", "code"]
Output: true
Explanation: Return true because "leetcode" can be segmented as "leet code".

Example 2:

Input: s = "applepenapple", wordDict = ["apple", "pen"]
Output: true
Explanation: Return true because "applepenapple" can be segmented as "apple pen apple".
             Note that you are allowed to reuse a dictionary word.

Example 3:

Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
Output: false

给定一个词典和一个字符串,问字符串能否拆分成若干个词典中有的词。比如样例中词典中有leet和code,则给定的字符串leetcode就能拆分成leet和code,他们都在词典中。
使用DP思路。假设dp[j]表示字符串下标j之前的字符串能否拆分成词典中的词的组合。如果要求dp[i],则我们可以看看i之前的所有j,如果有dp[j]是true的,且[j,i)的子串在dict中,说明[0,i)也能被拆分成词典中的词,所以dp[i]=true。最后我们只需要返回dp[n]即可。
对于s=”leetcode”,dp=1,0,0,0,1,0,0,0,1,所以dp[n]=1。
代码如下:

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict)
    {
        unordered_set<string> dict(wordDict.begin(), wordDict.end());
        int n = s.size();
        vector<int> dp(n + 1, 0);
        dp[0] = 1;
        for (int i = 1; i <= n; ++i) {
            for (int j = i – 1; j >= 0; –j) {
                if (dp[j] && dict.find(s.substr(j, i – j)) != dict.end()) {
                    dp[i] = 1;
                    break;
                }
            }
        }
        return dp[n];
    }
};

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

LeetCode Task Scheduler

LeetCode Task Scheduler Given a char array representing tasks CPU need to do. It contains capital letters A to Z where different letters represent different tasks.Tasks could be done without original order. Each task could be done in one interval. For each interval, CPU could finish one task or just be idle. However, there is a non-negative cooling interval n that means between two same tasks, there must be at least n intervals that CPU are doing different tasks or just be idle. You need to return the least number of intervals the CPU will take to finish all the given tasks. Example 1:

Input: tasks = ['A','A','A','B','B','B'], n = 2
Output: 8
Explanation: A -> B -> idle -> A -> B -> idle -> A -> B.
Note:
  1. The number of tasks is in the range [1, 10000].

CPU需要处理一系列任务,限制条件是两个相同的任务被处理的时间至少需要间隔n时刻,问CPU最少需要多长时间能处理完所有任务。 比赛没做出来,参考讨论区。 根据题意,两个任务被处理至少需要间隔n时刻,所以我们可以认为CPU处理一批任务的循环周期是n+1,比如0时刻处理了任务’A’,则至少要到n+1时刻才能再次处理任务’A’,中间间隔了n时刻。 假设数量最多的任务的数量是k,则我们至少需要k个周期才能把这个任务处理完。为了让CPU处理的空闲时间更少,我们在一个周期内尽量让CPU处理的任务更丰富。所以想象一下,我们有k个桶,相当于k个周期,每个周期,我们把频率最高的任务拿出来,分发到这最多k个桶中。如果所有不同任务都分发完了还没有填满一个桶,则说明该桶内(周期内)CPU需要空闲等待。 比如样例中,最高频的任务是A和B,都是3,所以我们至少需要3个桶。每个桶的容量是n+1=3,相当于相同任务的距离是3。每次我们把A和B扔到不同的桶中,前两个桶各有一个空闲等待,第三个桶因为结束了,所以不需等待。 因为每次都需要取出最高频的任务去分发,所以用一个优先队列来实时更新频率排名。 完整代码如下: [cpp] class Solution { public: int leastInterval(vector<char>& tasks, int n) { map<char, int> count; for (const auto& c : tasks)++count[c]; priority_queue<pair<int, char>> pq; for (const auto& p : count)pq.push({ p.second,p.first }); int cycle = n + 1, time = 0; while (!pq.empty()) { vector<pair<int, char>> tmp; int tsk = 0; for (int i = 0; i < cycle; ++i) { if (!pq.empty()) { tmp.push_back(pq.top()); pq.pop(); ++tsk; } } for (auto& t : tmp) { if (–t.first) { pq.push(t); } } time += pq.empty() ? tsk : cycle; } return time; } }; [/cpp] 本代码提交AC,用时95MS。]]>

LeetCode Minimum Factorization

LeetCode Minimum Factorization Given a positive integer a, find the smallest positive integer b whose multiplication of each digit equals to a. If there is no answer or the answer is not fit in 32-bit signed integer, then return 0. Example 1 Input:

48
Output:
68
Example 2 Input:
15
Output:
35

给定一个数a,要求找一个最小的数b,使得b的各位数字相乘的结果等于a。 很有意思的一个题,考察数学,当时没做出来,参考了这个题。 首先,如果a小于10的话,那么最小的b就是a了,否则b就要变成十位数或者百位数。比如a=8,则最小的b就是8,当然b也可以是十位数比如24或者42,但是都大于个位数8自己。 当a大于等于10时,我们需要找a的因子,为了是b最小,则我们希望b的位数越少越好。所以我们要找b的因子应该越大越好。所以我们从最大的因子9开始找起,从9一直找到2,把a的所有因子都找出来。比如48从大到小的因子是8和6,则最终结果就是把因子从小到大组成一个数,即68。 这里有一个问题,48的因子还可以是4和2呀,为什么没有了呢。因为我们从9→2开始找因子的过程中,是用a除以因子得到的商来不断的找。上面48找到8和6的因子之后,商就等于1了,不需要再找因子了,所以结束。 如果在找因子的过程中,发现商变成了一个质数,因为大于10的质数不可能被分解,所以无解,返回0。 代码如下: [cpp] class Solution { public: int smallestFactorization(int a) { if (a < 10)return a; vector<int> factors; for (int i = 9; i >= 2; –i) { while (a%i == 0) { factors.push_back(i); a /= i; } } if (a != 1)return 0; // caution long long ans = 0; for (int i = factors.size() – 1; i >= 0; –i) { ans = ans * 10 + factors[i]; } return ans > INT_MAX ? 0 : ans; } }; [/cpp] 本代码提交AC,用时3MS。]]>