LeetCode 练习(一)
Flatten Binary Tree to Linked List
Given a binary tree, flatten it to a linked list in-place.
这道题用后序遍历解,因为题目给出的例子是以后序展平的:1)若左右子树为空,返回根节点本身;2)若左子树不为空,处理左子树;3)若右子树不为空,处理右子树,并将展平后的右子树根节点拼接在左子树最后节点上;4)将拼接后的首节点挂在根节点右子树上。在递归时,可以返回最右节点,以免之后重复查找。
#include <iostream>
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
private:
TreeNode *flattenRight(TreeNode *node) {
if (!node->left && !node->right) return (node);
if (node->left && !node->right) {
node->right = node->left;
node->left = NULL;
return (this->flattenRight(node->right));
}
if (!node->left && node->right) {
return (this->flattenRight(node->right));
}
if (node->left && node->right) {
TreeNode *right = this->flattenRight(node->left);
right->right = node->right;
node->right = node->left;
node->left = NULL;
return (this->flattenRight(right->right));
}
}
public:
void flatten(TreeNode *root) {
if (root) this->flattenRight(root);
}
};
Longest Consecutive Sequence
Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
题目要求在$O(n)$时间内求出给定集合里最常的连续整数子集。注意不是序列问题,所以子集的元素顺序可以打乱。对于乱序集合,几人要求$O(n)$,排序是不行的,因此考虑Hashtable。在Hashtable $H$中寻找包含元素$i$的连续元素集合,可以以$i$为中心,向递增和递减两个方向分别作探测,然后合并探测的长度。以递增方向为例,首先$i \in H$,然后考察$i + 1 \in H$是否成立,若成立则继续测试$i + 2$,以此类推直到$i + m \notin H$,则偶递增方向的长度是$m - 1$。由此若$i - n \notin H$可得出递减方向长度是$n - 1$,因此包含$i$的子集和的长度是$m + n - 1$。对$H$中每一个元素作如上操作,求得长度的最大值就是解。注意在上面的例子中,对于所有元素$k, k \in [i - n + 1, i + m - 1]$求出的长度都是$m + n - 1$,所以当找到一个连续子集后,可以从$H$中删除这个子集,这样保证每个元素仅被测试一次。
#include <vector>
#include <unordered_set>
class Solution {
private:
int ascending(std::unordered_set<int> &set, int val) {
int count = 0;
while (set.count(++val)) {
++count;
set.erase(val);
}
return (count);
}
int descending(std::unordered_set<int> &set, int val) {
int count = 0;
while (set.count(--val)) {
++count;
set.erase(val);
}
return (count);
}
public:
int longestConsecutive(std::vector<int> &nums) {
std::unordered_set<int> set;
for (size_t i = 0; i < nums.size(); ++i) set.insert(nums[i]);
int result = 0;
for (size_t i = 0; i < nums.size(); ++i) {
if (set.count(nums[i])) result = std::max(result,
1 + this->ascending(set, nums[i]) + this->descending(set, nums[i]));
}
return (result);
}
};
Maximum Subarray
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
和最大连续子序列问题差不多,但题目要求必须至少包含一个元素。
#include <climits>
#include <vector>
class Solution {
public:
int maxSubArray(int array[], int n) {
if (!array || !n) return (0);
int sum = INT_MIN, cnt = 0;
for (int i = 0; i < n; ++i) {
if (array[i] > 0) {
if (cnt < 0) cnt = array[i];
else cnt += array[i];
} else {
if ((cnt += array[i]) < 0) cnt = array[i];
}
sum = std::max(sum, cnt);
}
return (sum);
}
};
Binary Tree Maximum Path Sum
Given a binary tree, find the maximum path sum.
Path指树中任意两个节点间通过他们最小公共父节点的路径。对节点$n$,左子树节点到$n$的所有路径最大值,加上右子树节点到$n$的所有路径最大值,再加上$n$本身的值,就是节点$的最优解$。所有节点最优解的最大值就是本题的解。采用后序遍历递归,递归中返回到根节点最大路径。
#include <climits>
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
private:
int maxPathSum(TreeNode *node, int &sum) {
if (!node->left && !node->right) {
sum = std::max(sum, node->val);
return (node->val);
}
int lmax = 0, rmax = 0;
if (node->left) lmax = std::max(0, this->maxPathSum(node->left, sum));
if (node->right) rmax = std::max(0, this->maxPathSum(node->right, sum));
sum = std::max(sum, node->val + lmax + rmax);
return (node->val + std::max(lmax, rmax));
}
public:
int maxPathSum(TreeNode *root) {
if (!root) return (0);
int result = INT_MIN;
this->maxPathSum(root, result);
return (result);
}
};
Palindrome Partitioning II
Given a string s, partition s such that every substring of the partition is a palindrome. Return the minimum cuts needed for a palindrome partitioning of s.
尝试用动态规划方法解。对于只有一个字符的串$s$,最小切割数为0。考虑往$s$添加一个字符记为$a_{i}$,我们得到切割数是$c_{i-1} + 1$。然后向前看一个字符,如果后缀$a_{i-1}a_{i}$是回文,那么得到切割数$c_{i-2} + 1$。以此类推,直到考虑了所有后缀,我们得到以$a_{i}$结尾的字符串的最小切割数为所有回文后缀切割数的最小值。注意每次处理后缀,最后会考虑到整个字串的情况,如果整个字串是回文,那么最小切割数就是0。给出状态转移方程如下:
$$c_{i} =
\begin{cases}
\max_{k=1}^{i-1} c_{k} + 1, & \text{if } c_{k+1} \cdots c_{i} \text{ is palindrome} \\
0, & \text{if } c_{1} \cdots c_{i} \text{ is palindrome}
\end{cases}$$
#include <string>
#include <vector>
class Solution {
private:
bool isPalind(const char *str, int beg, int end) {
const char *a = str + beg;
const char *b = str + end - 1;
while (a < b) if (*a++ != *b--) return (false);
return (true);
}
public:
int minCut(const std::string &str) {
int len = str.length();
std::vector<int> cuts(len, 0);
for (int i = 1; i < len; ++i) {
cuts[i] = len;
for (int j = i; j > 0; --j) {
if (this->isPalind(str.data(), j, i + 1)) {
cuts[i] = std::min(cuts[i], cuts[j-1] + 1);
}
}
if (this->isPalind(str.data(), 0, i + 1)) cuts[i] = 0;
}
return (cuts.back());
}
};

浙公网安备 33010602011771号