第1天 栈基本
1.1包含min函数的栈
剑指 Offer 30. 包含min函数的栈https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.min(); --> 返回 -2.
class MinStack {
public:
/** initialize your data structure here. */
stack<int> s1;
stack<int> s2;
MinStack() {
}
void push(int x) {
s1.push(x);
if(s2.empty() || s2.top() >= x) {
s2.push(x);
}
}
void pop() {
if(s1.empty()) return;
int temp = s1.top();
s1.pop();
if(s2.top() == temp) {
s2.pop();
}
}
int top() {
return s1.top();
}
int min() {
return s2.top();
}
};
class MinStack {
public:
/** initialize your data structure here. */
stack<int> s1;
stack<int> s2;
MinStack() {
}
void push(int x) {
s1.push(x);
if(s2.empty() || s2.top() >= x) {
s2.push(x);
}
}
void pop() {
if(s1.empty()) return;
int temp = s1.top();
s1.pop();
if(s2.top() == temp) {
s2.pop();
}
}
int top() {
return s1.top();
}
int min() {
return s2.top();
}
};
1.2 用两个栈实现队列
剑指 Offer 09. 用两个栈实现队列https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.min(); --> 返回 -2.
第2天 链表基本
2.1 从尾到头打印链表
剑指 Offer 06. 从尾到头打印链表https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/
class Solution {
public:
vector<int> result;
void recur(ListNode* cur) {
if(cur == NULL ) {
return;
}
recur(cur->next);
result.push_back(cur->val);
return;
}
vector<int> reversePrint(ListNode* head) {
recur(head);
return result;
}
};
也可以利用栈的先进后出的性质
2.2 反转链表
剑指 Offer 24. 反转链表https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre = NULL;
ListNode* cur = head;
while(cur) {
ListNode* temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};
剑指 Offer 35. 复杂链表的复制https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/
class Solution {
public:
Node* copyRandomList(Node* head) {
unordered_map<Node*, Node*> mp;
Node* cur = head;
while(cur) {
mp[cur] = new Node(cur->val);
cur = cur->next;
}
cur = head;
while(cur) {
mp[cur]->next = mp[cur->next];
mp[cur]->random = mp[cur->random];
cur = cur->next;
}
return mp[head];
}
};
第3天 字符串基本
3.1 替换空格
剑指 Offer 05. 替换空格https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/
请实现一个函数,把字符串 s
中的每个空格替换成"%20"。
示例 1:
输入:s = "We are happy."
输出:"We%20are%20happy."
class Solution {
public:
string replaceSpace(string s) {
int n = s.size();
int temp = n;
for(int i = 0; i < s.size(); i++) {
if(s[i] == ' ') {
temp += 2;
}
}
s.resize(temp);
int j = n - 1;
for(int i = temp - 1; i >= 0; i--) {
if(s[j] != ' ') {
s[i] = s[j--];
}
else {
s[i--] = '0';
s[i--] = '2';
s[i] = '%';
j--;
}
}
return s;
}
};
看答案有一种很巧妙地用法,只需要遍历一次
利用c++的引用
class Solution {
public:
string replaceSpace(string s) { //字符数组
string array; //存储结果
for(auto &c : s){ //遍历原字符串
if(c == ' '){
array.push_back('%');
array.push_back('2');
array.push_back('0');
}
else{
array.push_back(c);
}
}
return array;
}
};
3.3 左旋转字符串
剑指 Offer 58 - II. 左旋转字符串https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
class Solution {
public:
string reverseLeftWords(string s, int n) {
reverse(s.begin(), s.begin() + n);
reverse(s.begin() + n, s.end());
reverse(s.begin(), s.end());
return s;
}
};
第4天 查找算法 基本
4.1 数组中重复的数字
剑指 Offer 03. 数组中重复的数字https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
unordered_map<int, int> map;
for(int num : nums) {
map[num]++;
if(map.count(num) && map[num] > 1) {
return num;
}
}
return 0;
}
};
由于nums数组中的元素为(0-n-1),那么可以充分利用nums[i] - 1的大小来判断其是否出现两次,具体实现看代码
class Solution {
public:
//时间复杂度为O(n),空间复杂度为O(1)
int findRepeatNumber(vector<int>& nums) {
for(int i = 0; i < nums.size(); i++) {
nums[i] = nums[i] + 1;
}
int n = nums.size();
for(int i = 0; i < nums.size(); i++) {
int temp = (nums[i] - 1) % n;
if(nums[temp] >= n) return (nums[i] - 1) % n;
nums[temp] += n;
}
return 0;
}
};
4.2 在排序数组中查找数字
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0;
int r = nums.size() - 1;
while(l <= r) {
int mid = l + (r - l) / 2;
if(nums[mid] < target) {
l = mid + 1;
}
else {
r = mid - 1;
}
}
int left = l;
l = 0;
r = nums.size() - 1;
while(l <= r) {
int mid = l + (r - l) / 2;
if(nums[mid] <= target) {
l = mid + 1;
}
else {
r = mid - 1;
}
}
int right = r;
return right - left + 1;
}
};
4.3 在0-n-1中找缺失的数字
剑指 Offer 53 - II. 0~n-1中缺失的数字https://leetcode-cn.com/problems/que-shi-de-shu-zi-lcof/
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
示例 1:
输入: [0,1,3]
输出: 2
示例 2:
输入: [0,1,2,3,4,5,6,7,9]
输出: 8
class Solution {
public:
int missingNumber(vector<int>& nums) {
int l = 0;
int r = nums.size() - 1;
while(l <= r) {
int mid = l + (r - l) / 2;
if(nums[mid] == mid) {
l = mid + 1;
}
else {
r = mid - 1;
}
}
return r + 1;
}
};
第5天 查找
5.1 在二维数组中查找
剑指 Offer 04. 二维数组中的查找https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
if(matrix.size() == 0 || matrix[0].size() == 0) return false;
for(int i = 0; i < matrix.size(); i++) {
if(matrix[i][0] <= target) {
int l = 0;
int r = matrix[i].size() - 1;
while(l <= r) {
int mid = l + (r - l) / 2;
if(matrix[i][mid] == target) {
return true;
}
else if(matrix[i][mid] < target) {
l = mid + 1;
}
else {
r = mid - 1;
}
}
}
}
return false;
}
};
官方时间复杂度为O(n + m)
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return false;
}
int rows = matrix.length, columns = matrix[0].length;
int row = 0, column = columns - 1;
while (row < rows && column >= 0) {
int num = matrix[row][column];
if (num == target) {
return true;
} else if (num > target) {
column--;
} else {
row++;
}
}
return false;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/solution/mian-shi-ti-04-er-wei-shu-zu-zhong-de-cha-zhao-b-3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
5.2 旋转数组的最小数组
剑指 Offer 11. 旋转数组的最小数字https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0
class Solution {
public:
int minArray(vector<int>& numbers) {
int l = 0;
int r = numbers.size() - 1;
while(l < r) {
int mid = l + (r - l) / 2;
if(numbers[mid] < numbers[r]) {
r = mid;
}
else if(numbers[mid] > numbers[r]) {
l = mid + 1;
}
else {
r = r - 1;
}
}
return numbers[l];
}
};
5.3 第一个只出现一次的字符
面试题50. 第一个只出现一次的字符https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
示例 1:
输入:s = "abaccdeff"
输出:'b'
示例 2:
输入:s = ""
输出:' '
class Solution {
public:
char firstUniqChar(string s) {
unordered_map<int, int> mp;
for(int i = 0; i < s.size(); i++) {
mp[s[i]]++;
}
for(int i = 0; i < s.size(); i++) {
if(mp[s[i]] == 1) {
return s[i];
}
}
return ' ';
}
};
class Solution {
public:
char firstUniqChar(string s) {
unordered_map<char, int> position;
int n = s.size();
for (int i = 0; i < n; ++i) {
if (position.count(s[i])) {
position[s[i]] = -1;
}
else {
position[s[i]] = i;
}
}
int first = n;
for (auto [_, pos]: position) {
if (pos != -1 && pos < first) {
first = pos;
}
}
return first == n ? ' ' : s[first];
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/solution/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-by-3zqv5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
第6天 二叉树
6.1 从上到下打印出二叉树
面试题32 - I. 从上到下打印二叉树https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/
class Solution {
public:
vector<int> levelOrder(TreeNode* root) {
queue<TreeNode*> que;
vector<int> result;
if(!root) {
return result;
}
que.push(root);
while(!que.empty()) {
int len = que.size();
while(len--) {
auto t = que.front();
que.pop();
result.push_back(t->val);
if(t->left) {
que.push(t->left);
}
if(t->right) {
que.push(t->right);
}
}
}
return result;
}
};
6.2 从上到下打印出二叉树 II
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> que;
vector<vector<int>> result;
if(!root) {
return result;
}
que.push(root);
while(!que.empty()) {
int len = que.size();
vector<int> path(len);
while(len--) {
auto t = que.front();
que.pop();
path.push_back(t->val);
if(t->left) {
que.push(t->left);
}
if(t->right) {
que.push(t->right);
}
}
result.push_back(path);
}
return result;
}
};
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> que;
vector<vector<int>> result;
if(!root) {
return result;
}
que.push(root);
while(!que.empty()) {
int len = que.size();
vector<int> path(len);
for(int i = 0; i < len; i++) {
auto t = que.front();
que.pop();
int j = i;
if(result.size() % 2 != 0) {
j = len - i - 1;
}
path[j] = t->val;
if(t->left) {
que.push(t->left);
}
if(t->right) {
que.push(t->right);
}
}
result.push_back(path);
}
return result;
}
};
第7天 二叉树
7.1 树的子结构
剑指 Offer 26. 树的子结构https://leetcode-cn.com/problems/shu-de-zi-jie-gou-lcof/
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
例如:
给定的树 A:
3
/ \
4 5
/ \
1 2
给定的树 B:
4
/
1
返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。
class Solution {
public:
bool compare(TreeNode* A, TreeNode* B) {
if( A == NULL && B == NULL) return true;
if(A == NULL && B != NULL) return false;
if(A != NULL && B == NULL) return true;
if(A->val != B->val) return false;
return compare(A->left, B->left) && compare(A->right, B->right);
}
bool isSubStructure(TreeNode* A, TreeNode* B) {
if(A == NULL) return false;
if(B == NULL) return false;
return compare(A, B) || (isSubStructure(A->left, B) || isSubStructure(A->right, B));
}
};
7.2 二叉树的镜像
剑指 Offer 27. 二叉树的镜像https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof/
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
例如输入:
4
/ \
2 7
/ \ / \
1 3 6 9
镜像输出:
4
/ \
7 2
/ \ / \
9 6 3 1
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
if(root == NULL) return root;
swap(root->left, root->right);
mirrorTree(root->left);
mirrorTree(root->right);
return root;
}
};
7.3 对称的二叉树
剑指 Offer 28. 对称的二叉树https://leetcode-cn.com/problems/dui-cheng-de-er-cha-shu-lcof/
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/ \
2 2
/ \ / \
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/ \
2 2
\ \
3 3
class Solution {
public:
bool compare(TreeNode* lroot, TreeNode* rroot) {
if(lroot && !rroot) {
return false;
}
if(!lroot && rroot) {
return false;
}
if(!lroot && !rroot) {
return true;
}
if(lroot->val != rroot->val) {
return false;
}
bool t1 = compare(lroot->left, rroot->right);
bool t2 = compare(lroot->right, rroot->left);
return t1 && t2;
}
bool isSymmetric(TreeNode* root) {
if(!root) return true;
return compare(root->left, root->right);
}
};
第8天 动态规划
8.1 菲波那切数列
剑指 Offer 10- I. 斐波那契数列https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/
class Solution {
public:
int fib(int n) {
if(n < 2) return n;
vector<int> dp(3, 0);
dp[0] = 0;
dp[1] = 1;
for(int i = 2; i <= n; i++) {
dp[2] = (dp[0] + dp[1]) % 1000000007;
dp[0] = dp[1];
dp[1] = dp[2];
}
return dp[2];
}
};
8.2 青蛙跳台
剑指 Offer 10- II. 青蛙跳台阶问题https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/
class Solution {
public:
int numWays(int n) {
if(n < 2) return 1;
vector<int> dp(3, 0);
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i <= n; i++) {
dp[2] = (dp[0] + dp[1]) % 1000000007;
dp[0] = dp[1];
dp[1] = dp[2];
}
return dp[2];
}
};
8.3 股票最大利润
剑指 Offer 63. 股票的最大利润https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof/
假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
if( n == 0) {
return 0;
}
vector<vector<int>> dp(2, vector(n, 0));
dp[0][0] = - prices[0];
dp[1][0] = 0;
int mmax = 0;
for(int i = 1; i < prices.size(); i++) {
dp[0][i] = max(dp[0][i - 1] ,-prices[i]);
dp[1][i] = max(dp[1][i - 1], dp[0][i - 1] + prices[i]);
mmax = max(dp[1][i], mmax);
}
return mmax;
}
};
第9天 动态规划 中等
9.1 把数字翻译为字符串
剑指 Offer 46. 把数字翻译成字符串https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
class Solution {
public:
int translateNum(int num) {
string mys = to_string(num);
vector<int> dp(mys.size(), 0);
dp[0] = 1;
for(int i = 1; i < mys.size(); i++) {
if (mys[i - 1] == '0' || mys[i - 1] > '2' || (mys[i - 1] == '2' && mys[i] > '5')){
dp[i] = dp[i - 1];
}
else if(i > 1){
dp[i] = d[i - 1] + dp[i - 2] + 1;
}
else {
dp[i] = dp[i - 1] + 1;
}
}
return dp[mys.size() - 1];
}
};
class Solution {
public:
int translateNum(int num) {
string str = to_string(num);
vector<int> dp(str.size() + 1, 1);
dp[0] = 1;
for(int i = 1; i < str.size() + 1; i++) {
if(str[i - 1] >= '6') {
if(i - 2 >= 0 && str[i - 2] == '1') {
dp[i] = dp[i - 1] + dp[i - 2];
}
else if(i - 2 >= 0 && str[i - 2] == '0') {
dp[i] = dp[i - 1];
}
else dp[i] = dp[i - 1];
}
else if(str[i - 1] <= '5') {
if(i - 2 >= 0 && str[i - 2] <= '2' && str[i - 2] > '0') {
dp[i] = dp[i - 1] + dp[i - 2];
}
else if(i - 2 >= 0 && str[i - 2] == '0') {
dp[i] = dp[i - 1];
}
else dp[i] = dp[i - 1];
}
}
return dp[str.size()];
}
};
class Solution {
public:
int translateNum(int num) {
string mys = to_string(num);
if(mys.size() == 1) return 1;
vector<int> dp(3, 0);
dp[0] = 1;
dp[1] = 1;
for(int i = 1; i < mys.size(); i++) {
if (mys[i - 1] == '0' || mys[i - 1] > '2' || (mys[i - 1] == '2' && mys[i] > '5')){
dp[2] = dp[1];
}
else if(i > 1){
dp[2] = dp[0] + dp[1];
}
else {
dp[2] = dp[1] + 1;
}
dp[0] = dp[1];
dp[1] = dp[2];
}
return dp[2];
}
};
官方代码:
class Solution {
public:
int translateNum(int num) {
string src = to_string(num);
int p = 0, q = 0, r = 1;
for (int i = 0; i < src.size(); ++i) {
p = q;
q = r;
r = 0;
r += q;
if (i == 0) {
continue;
}
auto pre = src.substr(i - 1, 2);
if (pre <= "25" && pre >= "10") {
r += p;
}
}
return r;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/solution/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-by-leetcode-sol/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
9.2 最长含不重复字符的子字符串
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> map;;
int l = 0; int r = 0;
int len = 0;
while(r < s.size()) {
map[s[r]]++;
while(map.count(s[r]) && map[s[r]] > 1) {
map[s[l]]--;
l++;
}
if(map[s[r]] == 1) {
len = max(len, r - l + 1);
}
r++;
}
return len;
}
};
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() < 2) return s.size();
vector<int> dp(s.size(), 1);
unordered_map<char, int> record;
int mmax = 1;
record[s[0]] = 0;
for(int i = 1; i < s.size(); i++) {
if(!record.count(s[i])) {
dp[i] = dp[i - 1] + 1;
}
else {
int j = record[s[i]];
if(dp[i - 1] >= i - j) {
dp[i] = i - j;
}
else {
dp[i] = dp[i - 1] + 1;
}
}
mmax = max(mmax, dp[i]);
record[s[i]] = i;
}
return mmax;
}
};
20220506-复习
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> mp;
if(s.size() == 0) {
return 0;
}
int l = 0;
int r = 0;
int count = 1;
while(r < s.size()) {
if(!mp.count(s[r]) || mp[s[r]] == 0) {
mp[s[r]]++;
}
else {
count = max(count, r - l );
while(l < r && (s[l] != s[r])) {
mp[s[l]] = 0;
l++;
}
mp[s[l++]] = 0;
mp[s[r]]++;
}
r++;
}
count = max(count, r - l );
return count;
}
};
第 15 天 回溯
15.1 机器人运动的范围
剑指 Offer 13. 机器人的运动范围https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
示例 1:
输入:m = 2, n = 3, k = 1
输出:3
示例 2:
输入:m = 3, n = 1, k = 0
输出:1
class Solution {
public:
int addNum(int x, int y) {
int sum = 0;
while(x != 0) {
sum += x % 10;
x = x / 10;
}
while(y != 0) {
sum += y % 10;
y = y / 10;
}
return sum;
}
const int dist[4][2] = {
{-1,0}, {1, 0}, {0, -1}, {0, 1}};
int movingCount(int m, int n, int k) {
int nums = 1;
vector<vector<int>> visited(m, vector(n, 0));
visited[0][0] = 1;
queue<pair<int, int>> que;
que.push({0,0});
while(!que.empty()) {
int size = que.size();
while(size--) {
auto [i, j] = que.front();
que.pop();
for(int t = 0; t < 4; t++) {
int dx = i + dist[t][0];
int dy = j + dist[t][1];
if(dx >= 0 && dx < m && dy >=0 && dy < n && visited[dx][dy] == 0 ) {
if(addNum(dx, dy) <= k) {
nums++;
visited[dx][dy] = 1;
que.push({dx, dy});
}
}
}
}
}
return nums;
}
};
class Solution {
public:
int addNum(int x, int y) {
int sum = 0;
while(x != 0) {
sum += x % 10;
x = x / 10;
}
while(y != 0) {
sum += y % 10;
y = y / 10;
}
return sum;
}
const int dist[4][2] = {
{-1,0}, {1, 0}, {0, -1}, {0, 1}};
int nums = 0;
void dfs(int m, int n, int t, int i, int j, vector<vector<int>> &visited) {
if(i == m || j == n) {
return;
}
for(int k = 0; k < 4; k++) {
int dx = i + dist[k][0];
int dy = j + dist[k][1];
if(dx >= 0 && dx < m && dy >=0 && dy < n && visited[dx][dy] == 0 ) {
if(addNum(dx, dy) <= t) {
nums++;
visited[dx][dy] = 1;
dfs(m, n, t, dx, dy, visited);
}
}
}
}
int movingCount(int m, int n, int k) {
vector<vector<int>> visited(m, vector(n, 0));
if(addNum(0, 0) <= k) {
visited[0][0] = 1;
nums++;
dfs( m, n, k, 0, 0, visited);
}
return nums;
}
};
15.2 二叉树中和为某一值的路径
给你二叉树的根节点 root
和一个整数目标和 targetSum
,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
int sum = 0;
void dfs(TreeNode* root, int target) {
if(root == NULL) {
return;
}
sum += root->val;
path.push_back(root->val);
if(sum == target && !root->left && !root->right) {
result.push_back(path);
sum -= root->val;
path.pop_back();
return;
}
dfs(root->left, target);
dfs(root->right, target);
sum -= root->val;
path.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int target) {
dfs(root, target);
return result;
}
};
15.3 二叉搜索树的第k大节点
剑指 Offer 54. 二叉搜索树的第k大节点https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-di-kda-jie-dian-lcof/
class Solution {
public:
int result = 0;
void midSerach(TreeNode* root, int &k) {
if(root == NULL) {
return;
}
midSerach(root->right, k);
k--;
if(k == 0) {
result = root->val;
return;
}
midSerach(root->left, k);
return;
}
int kthLargest(TreeNode* root, int k) {
midSerach(root, k);
return result;
}
};
class Solution {
public:
int kthLargest(TreeNode* root, int k) {
stack<TreeNode*> st;
TreeNode *cur = root;
while(cur != NULL || !st.empty()) {
if(cur != NULL) {
st.push(cur);
cur = cur->right;
}
else {
auto t = st.top();
st.pop();
k--;
if(k == 0) {
return t->val;
}
if(t->left) {
cur = t->left;
}
}
}
return 0;
}
};
20220610
class Solution {
public:
int result = INT32_MAX;
void midbank(TreeNode* root, int& k) {
if(root == NULL) {
return;
}
midbank(root->right, k);
k--;
if(k == 0) {
result = root->val;
}
if(result != INT32_MAX) {
return;
}
midbank(root->left, k);
}
int kthLargest(TreeNode* root, int k) {
midbank(root, k);
return result;
}
};
15.4 二插收缩树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
class Solution {
public:
Node * pre = NULL;
Node * end;
Node * head;
void midSearch(Node* root) {
if(root == NULL) {
return;
}
Node * temp = root->right;
midSearch(root->left);
if(pre == NULL) {
pre = root;
head = root;
}
else {
pre->right = root;
root->left = pre;
pre = root;
}
midSearch(temp);
}
Node* treeToDoublyList(Node* root) {
if(root == NULL) return head;
midSearch(root);
head->left = pre;
pre->right = head;
return head;
}
};
第16天 数组
16.1 把数组排成最小的数
剑指 Offer 45. 把数组排成最小的数https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/
输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例 1:
输入: [10,2]
输出: "102"
示例 2:
输入: [3,30,34,5,9]
输出: "3033459"
class Solution {
public:
void quicksort(vector<int>& nums, int l, int r) {
if(l >= r) {
return;
}
int temp = nums[l];
int right = r;
int i = l;
while(i < r) {
while(i < r && (to_string(nums[r]) + to_string(temp) > to_string(temp) + to_string(nums[r]))) {
r--;
}
if(i < r)
nums[i++] = nums[r];
while(i < r && (to_string(nums[i]) + to_string(temp) <= to_string(temp) + to_string(nums[i]))) {
i++;
}
if(i < r)
nums[r--] = nums[i];
}
nums[i] = temp;
quicksort(nums, i + 1, right);
quicksort(nums, l, i - 1);
}
string minNumber(vector<int>& nums) {
string s;
quicksort(nums, 0, nums.size() - 1);
for(int i = 0; i < nums.size(); i++) {
s += to_string(nums[i]);
}
return s;
}
};
class Solution {
public:
static bool mcompare(const string& x, const string& y) {
return x + y < y + x;
}
string minNumber(vector<int>& nums) {
vector<string> str;
for(int i = 0; i < nums.size(); i++) {
str.push_back(to_string(nums[i]));
}
sort(str.begin(), str.end(), mcompare);
string res;
for(int i = 0; i < str.size(); i++) {
res += str[i];
}
return res;
}
};
16.2 扑克牌中的顺子
剑指 Offer 61. 扑克牌中的顺子https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof/
从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
示例 1:
输入: [1,2,3,4,5]
输出: True
示例 2:
输入: [0,0,1,2,5]
输出: True
class Solution {
public:
void mergeSort(vector<int>& nums, vector<int>& temp, int l, int r) {
if(l >= r) {
return;
}
int mid = l + (r - l) / 2;
mergeSort(nums, temp, l, mid);
mergeSort(nums, temp, mid + 1, r);
mysort(nums, temp, l, r);
return;
}
void mysort(vector<int>& nums, vector<int>& temp, int l, int r) {
int mid = l + (r - l) / 2;
int t = mid + 1;
for(int i = l; i <= r; i++) {
if(t > r ) {
temp[i] = nums[l++];
}
else if(l > mid) {
temp[i] = nums[t++];
}
else if(nums[l] < nums[t]) {
temp[i] = nums[l++];
}
else if(nums[l] >= nums[t]) {
temp[i] = nums[t++];
}
}
nums = temp;
}
bool isStraight(vector<int>& nums) {
vector<int> temp(nums);
mergeSort(nums, temp, 0, nums.size() - 1);
int count = 0;
for(int i = 0; i < nums.size(); i++) {
if(nums[i] == 0) {
count++;
}
if(i > 0 && nums[i] != nums[i - 1] + 1 && nums[i - 1] != 0) {
int t = nums[i] - nums[i - 1] - 1;
if(count < t || nums[i] == nums[i - 1]) {
return false;
}
count = count - t;
}
}
return true;
}
};
class Solution {
public:
bool isStraight(vector<int>& nums) {
sort(nums.begin(), nums.end());
int count = 0;
for(int i = 0; i < nums.size(); i++) {
if(nums[i] == 0) count++;
if(i > 0 && nums[i - 1] != 0) {
int arr = nums[i] - nums[i - 1];
if(arr > 1) {
count = count + 1 - arr;
}
else if(arr == 0) return false;
}
if(count < 0) return false;
}
return true;
}
};
第17天
17.1 最小的k个数
剑指 Offer 40. 最小的k个数https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/
输入整数数组 arr
,找出其中最小的 k
个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
priority_queue<int, vector<int>, less<int>> que;
int i = 0;
for(; i < k; i++) {
que.push(arr[i]);
}
for(; i < arr.size(); i++) {
que.push(arr[i]);
que.pop();
}
vector<int> result;
while(!que.empty()) {
result.push_back(que.top());
que.pop();
}
return result;
}
};
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int> vec(k, 0);
sort(arr.begin(), arr.end());
for (int i = 0; i < k; ++i) {
vec[i] = arr[i];
}
return vec;
}
};
17.2 数据流的中位数
剑指 Offer 41. 数据流中的中位数https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof/
class MedianFinder {
public:
class mycompare {
public:
bool operator()(const int& a, const int &b) {
return a > b;
}
};
/** initialize your data structure here. */
priority_queue<int, vector<int>> myqB;
priority_queue<int, vector<int>, mycompare> myqA;
MedianFinder() {
}
void addNum(int num) {
if(myqB.size() == myqA.size()) {
myqB.push(num);
myqA.push(myqB.top());
myqB.pop();
}
else {
myqA.push(num);
myqB.push(myqA.top());
myqA.pop();
}
}
double findMedian() {
double t;
if((myqB.size() + myqA.size()) % 2 ==0) {
t = double((myqA.top() + myqB.top())) / 2;
}
else t = myqA.top();
return t;
}
};
第18天 二叉树
18.1平衡二叉树
剑指 Offer 55 - II. 平衡二叉树https://leetcode-cn.com/problems/ping-heng-er-cha-shu-lcof/
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false 。
class Solution {
public:
int recur(TreeNode *root) {
if(root == NULL) return 0;
int left = recur(root->left);
int right = recur(root->right);
if(left == -1 || right == -1) return -1;
if(abs(left - right) > 1) return -1;
return max(left, right) + 1;
}
bool isBalanced(TreeNode* root) {
int t = recur(root);
if(t != -1) return true;
return false;
}
};
18.2 二叉树的深度
剑指 Offer 55 - I. 二叉树的深度https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
class Solution {
public:
int deep(TreeNode* root,int count){
if(root == NULL) {return count;}
count++;
int count1 = deep(root->left,count);
int count2 = deep(root->right,count);
return count1>count2?count1:count2;
}
int maxDepth(TreeNode* root) {
int count = 0;
count = deep(root,count);
return count;
}
};
第19天 数组
19.1、求 1+2+...+n
剑指 Offer 64. 求1+2+…+nhttps://leetcode-cn.com/problems/qiu-12n-lcof/
求 1+2+...+n
,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
示例 1:
输入: n = 3
输出: 6
示例 2:
输入: n = 9
输出: 45
class Solution {
public:
int sumNums(int n) {
n && (n += sumNums(n - 1));
return n;
}
};
19.2 二叉树的最近公共祖先
class Solution {
public:
TreeNode* recur(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL || root == p || root == q) {
return root;
}
TreeNode* left = recur(root->left, p, q);
TreeNode* right = recur(root->right, p, q);
if(left == NULL && right == NULL) {
return NULL;
}
if(left != NULL && right == NULL) {
return left;
}
if(left == NULL && right != NULL) {
return right;
}
return root;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
TreeNode* result = recur(root, p, q);
return result;
}
};
第20天
20.1 重建二叉树
剑指 Offer 07. 重建二叉树https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
class Solution {
public:
TreeNode* mbuildTree(vector<int>& preorder, vector<int>& inorder, int pl, int pr, int il, int ir) {
if(pl > pr || il > ir) {
return NULL;
}
int head = preorder[pl];
TreeNode* root = new TreeNode(head);
int i = il;
for(; i <= ir; i++) {
if(inorder[i] == head) {
break;
}
}
int t = i - il;
root->left = mbuildTree(preorder, inorder, pl + 1, pl + t, il, il + t - 1);
root->right = mbuildTree(preorder, inorder, pl + t + 1, pr, il + t + 1, ir);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return mbuildTree(preorder, inorder, 0, preorder.size() - 1, 0, preorder.size() - 1);
}
};
20.2 二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true
,否则返回 false
。假设输入的数组的任意两个数字都互不相同。
class Solution {
public:
bool verifyPostorder(vector<int>& postorder) {
return recur(postorder, 0, postorder.size() - 1);
}
bool recur(vector<int>& postorder, int i, int j) {
if(i > j) return true;
int p = i;
while(postorder[p] < postorder[j]) {
p++;
}
int m = p;
while(postorder[p] > postorder[j]) {
p++;
}
return j == p && recur(postorder, i, m - 1) && recur(postorder, m, p - 1);
}
};
20.3 超级次方
372. 超级次方https://leetcode-cn.com/problems/super-pow/
你的任务是计算 ab
对 1337
取模,a
是一个正整数,b
是一个非常大的正整数且会以数组形式给出。
class Solution {
public:
int mod = 1337;
int pow(int x, int n) {
int res = 1;
while(n) {
if(n % 2 ) {
res = (long)res * x % mod;
}
x = (long)x * x % mod;
n = n / 2;
}
return res;
}
int superPow(int a, vector<int>& b) {
int result = 1;
a = a % mod;
for(int i = 0; i < b.size(); i++) {
result = (long)pow(result, 10) * pow(a, b[i]) % mod;
}
return result;
}
};
20.4 数值的整数次方
剑指 Offer 16. 数值的整数次方https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。
class Solution {
public:
double pow(double x, int n) {
double res = 1.0;
while(n) {
if(n % 2) {
res = res * x;
}
x = x * x;
n = n / 2;
}
return res;
}
double myPow(double x, int n) {
if(n < 0) {
x = 1.0 / x;
}
return pow(x, n);
}
};
第21天 位运算
21.1 位运算
剑指 Offer 15. 二进制中1的个数https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof/
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为 汉明重量).)。
class Solution {
public:
int hammingWeight(uint32_t n) {
int count = 0;
for(int i = 0; i < 32; i++) {
if(n & 1) {
count++;
}
n = n >> 1;
}
return count;
}
};
21.2 不用加减乘除做加法
剑指 Offer 65. 不用加减乘除做加法https://leetcode-cn.com/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof/
class Solution {
public:
int add(int a, int b) {
while(b) {
int t = a ^ b;
b = (unsigned)(a & b) << 1;
a = t;
}
return a;
}
};
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
第22天 数组
22.1 数组中数字出现的次数
一个整型数组 nums
里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int t = nums[0];
for(int i = 1; i < nums.size(); i++) {
t ^= nums[i];
}
int div = 1;
while(1) {
if(div & t ) break;
div <<= 1;
}
int t1 = 0;
int t2 = 0;
for(int i = 0; i < nums.size(); i++) {
if(nums[i] & div) {
t1 ^= nums[i];
}
else t2 ^= nums[i];
}
return vector<int>{t1, t2};
}
};
在一个数组 nums
中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int a[31] = {0};
for(int i = 0; i < nums.size(); i++) {
int t = 1;
for(int j = 0; j < 31; j++) {
if((t & nums[i]) > 0) a[j]++;
t = t << 1;
}
}
int result = 0;
int t = 1;
for(int j = 0; j < 31; j++) {
if(a[j] % 3 != 0) {
result |= t << j;
}
}
return result;
}
};
第23天 数学 简单
23.1 数组中数字出现的次数
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int t = nums[0];
for(int i = 1; i < nums.size(); i++) {
t ^= nums[i];
}
int div = 1;
while(1) {
if(div & t ) break;
div <<= 1;
}
int t1 = 0;
int t2 = 0;
for(int i = 0; i < nums.size(); i++) {
if(nums[i] & div) {
t1 ^= nums[i];
}
else t2 ^= nums[i];
}
return vector<int>{t1, t2};
}
};
23.2 数组中出现次数超过一半的数字
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int ,int> record;
for(int i = 0; i < nums.size(); i++) {
record[nums[i]]++;
}
int mMax = 0;
int mCount = 0;
for(int i = 0; i < nums.size(); i++) {
if(record[nums[i]] > mCount) {
mCount = record[nums[i]];
mMax = nums[i];
}
}
return mMax;
}
};
23.3 构建乘积数组
剑指 Offer 66. 构建乘积数组https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof/
class Solution {
public:
vector<int> constructArr(vector<int>& a) {
int len = a.size();
if(len == 0) return {};
vector<int> b(len, 1);
b[0] = 1;
int tmp = 1;
for(int i = 1; i < len; i++) {
b[i] = b[i - 1] * a[i - 1];
}
for(int i = len - 2; i >= 0; i--) {
tmp *= a[i + 1];
b[i] *= tmp;
}
return b;
}
};
第24天 数学 中等
24.1 数组中出现次数超过一半的数字
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int ,int> record;
for(int i = 0; i < nums.size(); i++) {
record[nums[i]]++;
}
int mMax = 0;
int mCount = 0;
for(int i = 0; i < nums.size(); i++) {
if(record[nums[i]] > mCount) {
mCount = record[nums[i]];
mMax = nums[i];
}
}
return mMax;
}
};
24.2 剑指 Offer 62. 圆圈中最后剩下的数字剑指 Offer 62. 圆圈中最后剩下的数字https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
class Solution {
public:
int lastRemaining(int n, int m) {
int cqr = 0;
int bsr = 0;
int t = 0;
vector<bool> record(n ,true);
while(cqr < n - 1) {
if(record[bsr] == true) {
t++;
}
if(t == m && record[bsr] == true) {
t = 0;
record[bsr] = false;
cqr++;
}
bsr++;
if(bsr == n) {
bsr = 0;
}
}
for(int i = 0; i < record.size(); i++) {
if(record[i] == true) {
return i;
}
}
return 0;
}
};
class Solution {
public:
int lastRemaining(int n, int m) {
int f = 0;
for (int i = 2; i != n + 1; ++i) {
f = (m + f) % i;
}
return f;
}
};
第25天 模拟
25.1 栈的压入,弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
剑指 Offer 31. 栈的压入、弹出序列https://leetcode-cn.com/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof/
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
int n = pushed.size();
int m = popped.size();
stack<int> st;
int j = 0;
for(int i = 0; i < n; i++) {
if(pushed[i] != popped[j]) {
st.push(pushed[i]);
}
if(pushed[i] == popped[j]) {
j++;
}
while(j < m && !st.empty() && st.top() == popped[j]) {
st.pop();
j++;
}
}
if(j == n) {
return true;
}
return false;
}
};
25.2 顺时针打印矩阵
剑指 Offer 29. 顺时针打印矩阵https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> result;
if(matrix.size() == 0) return result;
int j = 0;
int i = 0;
int endi = matrix.size() - 1;
int endj = matrix[0].size() - 1;
while(i <= endi && j <= endj) {
for(int k = j; k <= endj; k++) {
result.push_back(matrix[i][k]);
}
for(int k = i + 1; k <= endi; k++) {
result.push_back(matrix[k][endj]);
}
for(int k = endj - 1; k >= j; k--) {
if(endi != i)
result.push_back(matrix[endi][k]);
}
for(int k = endi - 1; k > i; k--) {
if(endj != j)
result.push_back(matrix[k][j]);
}
endi--;
endj--;
i++;
j++;
}
return result;
}
};
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
第26天 字符串 答案都不想看
26.1 表示数值的字符串
剑指 Offer 20. 表示数值的字符串https://leetcode-cn.com/problems/biao-shi-shu-zhi-de-zi-fu-chuan-lcof/
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
数值(按顺序)可以分成以下几个部分:
若干空格
一个 小数 或者 整数
(可选)一个 'e' 或 'E' ,后面跟着一个 整数
若干空格
小数(按顺序)可以分成以下几个部分:
(可选)一个符号字符('+' 或 '-')
下述格式之一:
至少一位数字,后面跟着一个点 '.'
至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
一个点 '.' ,后面跟着至少一位数字
整数(按顺序)可以分成以下几个部分:
(可选)一个符号字符('+' 或 '-')
至少一位数字
class Solution {
public:
enum State {
STATE_INITIAL,
STATE_INT_SIGN,
STATE_INTEGER,
STATE_POINT,
STATE_POINT_WITHOUT_INT,
STATE_FRACTION,
STATE_EXP,
STATE_EXP_SIGN,
STATE_EXP_NUMBER,
STATE_END
};
enum CharType {
CHAR_NUMBER,
CHAR_EXP,
CHAR_POINT,
CHAR_SIGN,
CHAR_SPACE,
CHAR_ILLEGAL
};
CharType toCharType(char ch) {
if (ch >= '0' && ch <= '9') {
return CHAR_NUMBER;
} else if (ch == 'e' || ch == 'E') {
return CHAR_EXP;
} else if (ch == '.') {
return CHAR_POINT;
} else if (ch == '+' || ch == '-') {
return CHAR_SIGN;
} else if (ch == ' ') {
return CHAR_SPACE;
} else {
return CHAR_ILLEGAL;
}
}
bool isNumber(string s) {
unordered_map<State, unordered_map<CharType, State>> transfer{
{
STATE_INITIAL, {
{CHAR_SPACE, STATE_INITIAL},
{CHAR_NUMBER, STATE_INTEGER},
{CHAR_POINT, STATE_POINT_WITHOUT_INT},
{CHAR_SIGN, STATE_INT_SIGN}
}
}, {
STATE_INT_SIGN, {
{CHAR_NUMBER, STATE_INTEGER},
{CHAR_POINT, STATE_POINT_WITHOUT_INT}
}
}, {
STATE_INTEGER, {
{CHAR_NUMBER, STATE_INTEGER},
{CHAR_EXP, STATE_EXP},
{CHAR_POINT, STATE_POINT},
{CHAR_SPACE, STATE_END}
}
}, {
STATE_POINT, {
{CHAR_NUMBER, STATE_FRACTION},
{CHAR_EXP, STATE_EXP},
{CHAR_SPACE, STATE_END}
}
}, {
STATE_POINT_WITHOUT_INT, {
{CHAR_NUMBER, STATE_FRACTION}
}
}, {
STATE_FRACTION,
{
{CHAR_NUMBER, STATE_FRACTION},
{CHAR_EXP, STATE_EXP},
{CHAR_SPACE, STATE_END}
}
}, {
STATE_EXP,
{
{CHAR_NUMBER, STATE_EXP_NUMBER},
{CHAR_SIGN, STATE_EXP_SIGN}
}
}, {
STATE_EXP_SIGN, {
{CHAR_NUMBER, STATE_EXP_NUMBER}
}
}, {
STATE_EXP_NUMBER, {
{CHAR_NUMBER, STATE_EXP_NUMBER},
{CHAR_SPACE, STATE_END}
}
}, {
STATE_END, {
{CHAR_SPACE, STATE_END}
}
}
};
int len = s.length();
State st = STATE_INITIAL;
for (int i = 0; i < len; i++) {
CharType typ = toCharType(s[i]);
if (transfer[st].find(typ) == transfer[st].end()) {
return false;
} else {
st = transfer[st][typ];
}
}
return st == STATE_INTEGER || st == STATE_POINT || st == STATE_FRACTION || st == STATE_EXP_NUMBER || st == STATE_END;
}
};
26.2 把字符串转换成整数
写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
class Solution {
public:
int strToInt(string str) {
int i = 0;
for(; i <str.size(); i++) {
if(str[i] != ' ') {
break;
}
}
str = str.substr(i, str.size() - i);
if(str.size() == 0 || (str[0] != '+' && str[0] != '-' && (str[0] < '0' || str[0] > '9'))) return 0;
string mys;
mys += str[0];
for(int i = 1; i < str.size(); i++) {
if(str[i] < '0' || str[i] > '9' ) break;
mys += str[i];
}
int sum = 0;
int t = 1;
int bundy = 2147483647 / 10;
for(int i = 0; i < mys.size(); i++) {
if(abs(sum) > bundy || (abs(sum) == bundy && (mys[i] - '0') > 7)) {
if(t == 1) {
return 2147483647*t;
}
else return 2147483648*t;
}
sum = sum * 10;
if(mys[i] == '+') t = 1;
else if(mys[i] == '-') t = - 1;
else {
sum += (mys[i] - '0')*t;
}
}
return sum;
}
};
第27天 单向 队列
27.1 滑动窗口的最大值
剑指 Offer 59 - I. 滑动窗口的最大值https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/
给定一个数组 nums
和滑动窗口的大小 k
,请找出所有滑动窗口里的最大值。
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
滑动窗口+单调队列实现
class Solution {
public:
class myqueue {
public:
deque<int> q;
void push(int val) {
while(!q.empty() && q.back() < val) {
q.pop_back();
}
q.push_back(val);
}
void pop(int val) {
if(!q.empty() && q.front() == val) {
q.pop_front();
}
}
int peek() {
return q.front();
}
};
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> result;
if(k == 0) return result;
myqueue deq;
int i = 0;
for(; i < k; i++) {
deq.push(nums[i]);
}
for(; i < nums.size(); i++) {
result.push_back(deq.peek());
deq.pop(nums[i - k]);
deq.push(nums[i]);
}
result.push_back(deq.peek());
return result;
}
};
27.2 队列的最大值
剑指 Offer 59 - II. 队列的最大值https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof/
请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。
若队列为空,pop_front 和 max_value 需要返回 -1
示例 1:
输入:
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]
示例 2:
输入:
["MaxQueue","pop_front","max_value"]
[[],[],[]]
输出: [null,-1,-1]
//超时
class MaxQueue {
public:
unordered_map<int, int> map;
queue<int> q;
priority_queue<int> p;
MaxQueue() {
}
int max_value() {
if(p.empty()) return -1;
while(map[p.top()] == 0) {
p.pop();
}
int temp = p.top();
return temp;
}
void push_back(int value) {
map[value]++;
q.push(value);
p.push(value);
}
int pop_front() {
if(q.empty()) return -1;
map[q.front()]--;
int temp = q.front();
q.pop();
return temp;
}
};
//运行成功
class MaxQueue {
public:
deque<int> deq;
queue<int> q;
MaxQueue() {
}
int max_value() {
if(deq.empty()) return -1;
return deq.front();
}
void push_back(int value) {
q.push(value);
while(!deq.empty() && deq.back() < value) {
deq.pop_back();
}
deq.push_back(value);
}
int pop_front() {
if(q.empty()) return -1;
if(!deq.empty() && q.front() == deq.front()) {
deq.pop_front();
}
int temp = q.front();
q.pop();
return temp;
}
};
第22天 数组
22.1 数组中数字出现的次数 II
在一个数组 nums
中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
示例 1:
输入:nums = [3,4,3,3]
输出:4
示例 2:
输入:nums = [9,1,7,9,7,9,7]
输出:1
class Solution {
public:
int singleNumber(vector<int>& nums) {
int a[31] = {0};
for(int i = 0; i < nums.size(); i++) {
int t = 1;
for(int j = 0; j < 31; j++) {
if((t & nums[i]) > 0) a[j]++;
t = t << 1;
}
}
int result = 0;
int t = 1;
for(int j = 0; j < 31; j++) {
if(a[j] % 3 != 0) {
result |= t << j;
}
}
return result;
}
};
22.2 数组中数字出现的次数
一个整型数组 nums
里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int t = nums[0];
for(int i = 1; i < nums.size(); i++) {
t ^= nums[i];
}
int div = 1;
while(1) {
if(div & t ) break;
div <<= 1;
}
int t1 = 0;
int t2 = 0;
for(int i = 0; i < nums.size(); i++) {
if(nums[i] & div) {
t1 ^= nums[i];
}
else t2 ^= nums[i];
}
return vector<int>{t1, t2};
}
};
第28天
28.1 剑指 Offer 38. 字符串的排列
剑指 Offer 38. 字符串的排列https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof/
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入:s = "abc"
输出:["abc","acb","bac","bca","cab","cba"]
class Solution {
public:
vector<string> result;
string path;
void banktrack(string s, vector<int>& position) {
if(path.size() == s.size()) {
result.push_back(path);
return;
}
for(int i = 0; i < s.size(); i++) {
if(i > 0 && s[i] == s[i - 1] && position[i - 1] == 0) continue;
if(position[i] == 0) {
path.push_back(s[i]);
position[i] = 1;
banktrack(s, position);
path.pop_back();
position[i] = 0;
}
}
}
vector<string> permutation(string s) {
sort(s.begin(), s.end());
vector<int> position(s.size(), 0);
banktrack(s, position);
return result;
}
};
28.2 Offer 37. 序列化二叉树
剑指 Offer 37. 序列化二叉树https://leetcode-cn.com/problems/xu-lie-hua-er-cha-shu-lcof/
请实现两个函数,分别用来序列化和反序列化二叉树。
你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
提示:输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。
输入:root = [1,2,3,null,null,4,5]
输出:[1,2,3,null,null,4,5]
用的广度优先搜索 也就是层序遍历 两者都是 树到数组 以及 数组到树
class Codec {
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
queue<TreeNode* > que;
string s;
if(root == NULL) return s;
que.push(root);
while(!que.empty()) {
auto t = que.front();
que.pop();
if(t == NULL) {
s += "None,";
}
else {
s += to_string(t->val) + ",";
}
if(t != NULL) {
que.push(t->left);
que.push(t->right);
}
}
return s;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
if(data.size() == 0) return NULL;
vector<string> str;
string mystr;
for(auto ch :data) {
if(ch == ',') {
str.push_back(mystr);
mystr.clear();
}
else {
mystr.push_back(ch);
}
}
TreeNode* root = new TreeNode(atoi(str[0].c_str()));
queue<TreeNode*> que;
que.push(root);
for(int i = 1; i < str.size(); i += 2) {
TreeNode* root = que.front();
que.pop();
int j = i;
if(str[j] != "None") {
TreeNode* temp = new TreeNode(atoi(str[j].c_str()));
root->left = temp;
que.push(temp);
}
if(str[j + 1] != "None") {
TreeNode* temp = new TreeNode(atoi(str[j + 1].c_str()));
root->right = temp;
que.push(temp);
}
}
return root;
}
};
第29天(很难受的一天)
29.1 剑指 Offer 60. n个骰子的点数
数论总结题:【算法竞赛模板】质因子、质数、约数、余数、快速幂(数论大全)_不负AC不负卿的博客-CSDN博客
剑指 Offer 60. n个骰子的点数https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof/
把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。
示例 1:
输入: 1
输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]
示例 2:
输入: 2
输出: [0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]
class Solution {
public:
vector<double> dicesProbability(int n) {
vector<double> dp(6, 1.0 / 6.0);
for (int i = 2; i <= n; i++) {
vector<double> tmp(5 * i + 1, 0);
for (int j = 0; j < dp.size(); j++) {
for (int k = 0; k < 6; k++) {
tmp[j + k] += dp[j] / 6.0;
}
}
dp = tmp;
}
return dp;
}
};
剑指 Offer 49. 丑数 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/chou-shu-lcof/
29.2 丑数 - 力扣(LeetCode) (leetcode-cn.com)
我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
示例:
输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
class Solution {
public:
int nthUglyNumber(int n) {
vector<int> factors = {2, 3, 5};
unordered_set<long> seen;
priority_queue<long, vector<long>, greater<long>> heap;
seen.insert(1L);
heap.push(1L);
int ugly = 0;
for (int i = 0; i < n; i++) {
long curr = heap.top();
heap.pop();
ugly = (int)curr;
for (int factor : factors) {
long next = curr * factor;
if (!seen.count(next)) {
seen.insert(next);
heap.push(next);
}
}
}
return ugly;
}
};
面试题19. 正则表达式匹配https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof/
29.3 面试题19. 正则表达式匹配
请实现一个函数用来匹配包含'. '和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但与"aa.a"和"ab*a"均不匹配。
示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:
s = "aa"
p = "a*"
输出: true
解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:
输入:
s = "ab"
p = ".*"
输出: true
解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:
输入:
s = "aab"
p = "c*a*b"
输出: true
解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
示例 5:
输入:
s = "mississippi"
p = "mis*is*p*."
输出: false
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母以及字符 . 和 *,无连续的 '*'。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.size();
int n = p.size();
auto matches = [&](int i, int j) {
if (i == 0) {
return false;
}
if (p[j - 1] == '.') {
return true;
}
return s[i - 1] == p[j - 1];
};
vector<vector<int>> f(m + 1, vector<int>(n + 1));
f[0][0] = true;
for (int i = 0; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p[j - 1] == '*') {
f[i][j] |= f[i][j - 2];
if (matches(i, j - 1)) {
f[i][j] |= f[i - 1][j];
}
}
else {
if (matches(i, j)) {
f[i][j] |= f[i - 1][j - 1];
}
}
}
}
return f[m][n];
}
};
第30天
30.1 剑指 Offer 17. 打印从1到最大的n位数
剑指 Offer 17. 打印从1到最大的n位数https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/
输入数字 n
,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
示例 1:
输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
class Solution {
public:
vector<int> printNumbers(int n) {
vector<int> result;
int j = 0;
int i = 1;
while(j <= n) {
result.push_back(i);
int temp = i;
j = 0;
while(temp) {
j++;
temp = temp / 10;
}
i++;
}
result.pop_back();
return result;
}
};
官方代码思路
class Solution {
public:
vector<int> printNumbers(int n) {
vector<int> result;
int temp = pow(10, n) - 1;
for(int i = 0; i < temp; i++) {
result.push_back(i + 1);
}
return result;
}
};
30.2 数组中的逆序对(归并排序思想)
剑指 Offer 51. 数组中的逆序对https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
代码 官方的归排序(分治的思想)可以好好学习
class Solution {
public:
int reversePairs(vector<int>& nums) {
if(nums.size() < 2) return 0;
vector<int> temp(nums);
int count = recur(nums, temp, 0, nums.size() - 1);
return count;
}
int recur(vector<int>& nums, vector<int>& temp, int left, int right) {
if(left == right) {
return 0;
}
int mid = left + (right - left) / 2;
int mleft = recur(nums, temp, left, mid);
int mright = recur(nums, temp, mid + 1, right);
if (nums[mid] <= nums[mid + 1]) {
return mleft + mright;
}
int mcount = count(nums, temp, left, mid, right);
return mcount + mleft + mright;
}
int count(vector<int>& nums, vector<int>& temp, int left, int mid, int right) {
for (int i = left; i <= right; i++) {
temp[i] = nums[i];
}
int count = 0;
int i = left;
int j = mid + 1;
for(int k = left; k <= right; k++) {
if(i == mid + 1) {
nums[k] = temp[j];
j++;
}
else if(j == right + 1) {
nums[k] = temp[i];
i++;
}
else if(temp[i] <= temp[j]) {
nums[k] = temp[i];
i++;
}
else {
nums[k] = temp[j];
count += mid - i + 1;
j++;
}
}
return count;
}
};
第31天(考察数学,不具有普遍性,不具有很难受的一天)
数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
请写一个函数,求任意第n位对应的数字。
示例 1:
输入:n = 3
输出:3
示例 2:
输入:n = 11
输出:0
暴力解法 超时
class Solution {
public:
int findNthDigit(int n) {
string s;
for(int i = 0; i <= n; i++) {
s += to_string(i);
}
return (s[n] - '0');
}
};
输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:
输入:n = 12
输出:5
示例 2:
输入:n = 13
输出:6
剑指 Offer 14- II. 剪绳子 IIhttps://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m - 1] 。请问 k[0]*k[1]*...*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36