很简单的一道题,递归求解:对于二叉搜索树,左子树<根<右子树,由此可以判断两个节点分别位于两边还是同一边。如果在两边则该根为最近公共祖先,否则继续找下去
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root->val == p->val || root->val == q->val)
{
return root;
}
if ((root->val > p->val && root->val < q->val)
|| (root->val < p->val && root->val > q->val))
{
return root;
}
if (root->val > p->val && root->val > q->val)
{
return lowestCommonAncestor(root->left, p, q);
}
else
{
return lowestCommonAncestor(root->right, p, q);
}
}
};
本题相对于上题会稍微麻烦一些,因为没有二叉搜索树的特性。所以才去递归的时候需要从最底端开始,如果满足某根左边子树右边子树各有一个节点,则返回该根节点。否则说明两个节点必有一个是公共祖先。
class Solution {
public:
TreeNode* ans;
bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr) return false;
bool lson = dfs(root->left, p, q);
bool rson = dfs(root->right, p, q);
if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {
ans = root;
}
return lson || rson || (root->val == p->val || root->val == q->val);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root, p, q);
return ans;
}
};
另一种做法是记录每一个节点的父节点,然后对两个节点来找寻共有的根节点
class Solution {
public:
unordered_map<int, TreeNode*> fa;
unordered_map<int, bool> vis;
void dfs(TreeNode* root){
if (root->left != nullptr) {
fa[root->left->val] = root;
dfs(root->left);
}
if (root->right != nullptr) {
fa[root->right->val] = root;
dfs(root->right);
}
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
fa[root->val] = nullptr;
dfs(root);
while (p != nullptr) {
vis[p->val] = true;
p = fa[p->val];
}
while (q != nullptr) {
if (vis[q->val]) return q;
q = fa[q->val];
}
return nullptr;
}
};
本题比较有意思的地方在于单向链表不知道前面节点如何删除节点,做法是将当前节点赋值为下一个节点,删除下一个节点即可
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
if (node == NULL)
return;
if (node->next == NULL)
{
node = NULL;
return;
}
ListNode *tmp = node->next;
node->val = node->next->val;
node->next = node->next->next;
delete tmp;
return;
}
};
本题解法限制了不能用除法,因此可以转变思路:用两个数组分别存储当前位置的左边元素乘积和右边元素乘积,二者相乘即可。进一步可以简化:利用输出数组先存储左边元素,然后动态获取右边元素直接相乘赋值即可
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int length = nums.size();
vector<int> answer(length);
// answer[i] 表示索引 i 左侧所有元素的乘积
// 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1
answer[0] = 1;
for (int i = 1; i < length; i++) {
answer[i] = nums[i - 1] * answer[i - 1];
}
// R 为右侧所有元素的乘积
// 刚开始右边没有元素,所以 R = 1
int R = 1;
for (int i = length - 1; i >= 0; i--) {
// 对于索引 i,左边的乘积为 answer[i],右边的乘积为 R
answer[i] = answer[i] * R;
// R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上
R *= nums[i];
}
return answer;
}
};
使用队列保存窗口,变量的最前端(也就是 window.front())是此次遍历的最大值的下标,当我们遇到新的数时,将新的数和双项队列的末尾(也就是window.back())比较,如果末尾比新数小,则把末尾扔掉,直到该队列的末尾比新数大或者队列为空的时候才停止,做法有点像使用栈进行括号匹配。
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if (k == 0) return {};
vector<int> res;
deque<size_t> window;
/*Init K integers in the list*/
for (size_t i = 0; i < k; i++) {
while (!window.empty() && nums[i] > nums[window.back()]) {
window.pop_back();
}
window.push_back(i);
}
res.push_back(nums[window.front()]);
/*End of initialization*/
for (size_t i = k; i < nums.size(); i++) {
if (!window.empty() && window.front() <= i - k) {
window.pop_front();
}
while (!window.empty() && nums[i] > nums[window.back()]) {
window.pop_back();
}
window.push_back(i);
res.push_back(nums[window.front()]);
}
return res;
}
};
本题是典型的二分查找,但是由于已排序,除了二分查找外还可以通过对角线的原理来完成:从右上角或者左下角开始,按照大小规则移动行列,直至找到或者出界
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if(matrix.size() == 0||matrix[0].size() == 0)
{
return false;
}
int curx = matrix.size()-1,cury = 0;
while(curx >= 0 &&cury < matrix[0].size())
{
if(target > matrix[curx][cury])
{
cury++;
}
else if(target < matrix[curx][cury])
{
curx--;
}
else
{
return true;
}
}
return false;
}
};
本题可以采用分治算法,将表达式拆解为由符合分割开的各个部分,然后按顺序求不同的解。另一种做法是视为动态规划求解:用两个 list,一个保存了所有数字,一个保存了所有运算符。dp[i][j]表示第 i 到第 j 个数字(从 0 开始计数)范围内的表达式的所有解。
class Solution {
public:
vector<int> diffWaysToCompute(string input) {
int index = 0;
int num = 0;
while(index < input.size() && isdigit(input[index]))
num = num * 10 + input[index++] - '0';
if(index == input.size()){
hash[input] = {num};
return {num};
}
vector<int> ans;
for(int i = 0; i < input.size(); i++){
if(isOp(input[i])){
string s1 = input.substr(0,i);
string s2 = input.substr(i);
vector<int> result1, result2;
if(!hash.count(s1))
result1 = diffWaysToCompute(input.substr(0,i));
else
result1 = hash[s1];
if(!hash.count(s2))
result2 = diffWaysToCompute(input.substr(i+1));
else
result2 = hash[s2];
for(int r1 : result1){
for(int r2 : result2){
ans.push_back(calculate(r1,input[i],r2));
}
}
}
}
hash[input] = ans;
return ans;
}
bool isOp(const char& c){
return c == '+' || c == '-' || c == '*';
}
int calculate(const int& num1, const char& op, const int& num2){
if(op == '+')
return num1 + num2;
else if(op == '-')
return num1 - num2;
else
return num1 * num2;
}
private:
unordered_map<string,vector<int>> hash;
};