墙与门
题目地址
知识点:广度优先遍历,最短路径
解题思路:最直观的解题思路是,从每一个房间分别广度优先遍历,寻找到最近的门。
但是更高效的解决方法是,从多个门同时广度遍历,就可以同时对整个图进行广度优先搜索。
#define INF 0x7fffffff
class Solution {
public:
void wallsAndGates(vector<vector<int>>& rooms) {
queue<vector<int>> q;
int m = rooms.size();
if (m < 1)
return;
int n = rooms[0].size();
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
if (rooms[i][j] == 0)
q.push({i, j});
while(q.size() > 0)
{
int size = q.size();
for (int i = 0; i < size; i++)
{
vector<int> ele = q.front();
q.pop();
int row = ele[0], col = ele[1];
if (isValid(row-1, col, m, n) && rooms[row-1][col] == INF)
{
rooms[row-1][col] = rooms[row][col] + 1;
q.push({row-1, col});
}
if (isValid(row+1, col, m, n) && rooms[row+1][col] == INF)
{
rooms[row+1][col] = rooms[row][col] + 1;
q.push({row+1, col});
}
if (isValid(row, col-1, m, n) && rooms[row][col-1] == INF)
{
rooms[row][col-1] = rooms[row][col] + 1;
q.push({row, col-1});
}
if (isValid(row, col+1, m, n) && rooms[row][col+1] == INF)
{
rooms[row][col+1] = rooms[row][col] + 1;
q.push({row, col+1});
}
}
}
}
bool isValid(int i, int j, int m, int n)
{
if (i < 0 || i >= m || j < 0 || j >= n)
return false;
return true;
}
};
寻找重复数
题目地址
解题思路:
- 排序,如果nums[i] = nums[i-1]返回
- set存储,如果set中已经存在,返回
- 非常tricky的解决思路,解法等同于环状链表找entry point
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int fast = nums[0];
int slow = nums[0];
do{
slow = nums[slow];
fast = nums[nums[fast]];
}while(fast != slow);
slow = nums[0];
while(slow != fast)
{
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
};
【打家劫舍】全总结
题目地址
知识点:树遍历,动态规划
打家劫舍基础版
解题思路:
- 递归思路 + 记忆化搜索
void helper(vector<int> nums, int pos)
{
if (pos >= nums.length)
return 0;
return std::max(helper(nums, pos+1), helper(nums, pos+2) + nums[i]);
//可以把计算结果存储在一个map中防止重复计算。
}
- 动态规划思路
\\状态转移方程
dp[0] = nums[0];
dp[1] = std::max(dp[0], dp[1]);
dp[i] = std::max(dp[i-1], dp[i-2] + nums[i]);
打家劫舍进阶版【环形】
解题思路:分两种情况讨论,一种是抢第一家,不抢最后一家;一种是不抢第一家,抢最后一家
//动态规划思路
int cond1 = dp(nums, 1, n-1);
int cond2 = dp(nums, 0, n-2);
return std::max(cond1, cond2);
int dp(vector<int> nums, int start, int end)
{
nums[start] = nums[start];
nums[start+1] = std:max(nums[start], nums[start+1]);
for (int i = start + 2; i <= end; i++)
{
dp[i] = std::max(dp[i-1], dp[i-2] + nums[i]);
}
return dp[end];
}
//递归思路
void helper(vector<int> nums, int start, int end)
{
if (start >= end)
return 0;
return std::max(helper(nums, start+1, end), helper(nums, start+2, end) + nums[i]);
//可以把计算结果存储在一个map中防止重复计算。
}
打家劫舍终极版【树形】
解题思路:
每一层递归的结果是:
爷爷节点 + 孙子节点 vs 儿子节点的最大值
using namespace std;
class Solution {
public:
map<TreeNode*, int> m;
int rob(TreeNode* root) {
return helper(root);
}
int helper(TreeNode* root)
{
if (root == nullptr)
return 0;
if (m.find(root) != m.end())
return m.find(root)->second;
if (root == nullptr)
return 0;
int child = 0;
int grandChild = 0;
if (root->left != nullptr)
{
child += rob(root->left);
grandChild = rob(root->left->left) + rob(root->left->right);
}
if (root->right != nullptr)
{
child += rob(root->right);
grandChild += rob(root->right->left) + rob(root->right->right);
}
int res = max(grandChild + root->val, child);
m[root] = res;
return res;
}
};