文章目录
穿越网格图的安全路径

思路:题目要求找到一条安全路径,不难想到只要最短路存在即可。由于权值为0/1,考虑使用bfs,代码如下:
cpp
public:
bool findSafeWalk(vector<vector<int>>& grid, int health) {
int m = grid.size(); int n = grid[0].size();
vector<vector<int>> dis(m,vector<int>(n,INT_MAX));
dis[0][0] = grid[0][0];//初始化
deque<pair<int,int>> q; //双端队列
q.emplace_front(0,0);
while(!q.empty()){
auto[i,j] = q.front();
q.pop_front();
for(auto[dx,dy]:DIRS){
int x = i+dx; int y = j+dy;
if(x>=0 && x<m && y>=0 && y<n){
int cost = grid[x][y];
if(dis[i][j] + cost < dis[x][y]){
dis[x][y] = dis[i][j] + cost;
cost == 0 ? q.emplace_front(x,y) : q.emplace_back(x,y);
}
}
}
}
return dis[m-1][n-1] < health;
}
最小数目

思路:不难发现本题和上题一个道理,依旧使用bfs处理即可。
代码如下:
cpp
public:
int minimumObstacles(vector<vector<int>>& grid) {
int m = grid.size(); int n = grid[0].size();
vector<vector<int>> dis(m,vector<int>(n,INT_MAX));
dis[0][0] = grid[0][0];
deque<pair<int,int>> q;
q.emplace_front(0,0);
while(!q.empty()){
auto[i,j] = q.front();
q.pop_front();
for(auto[dx,dy] : DIRS){
int x = i+dx; int y = j+dy;
if(x >= 0 && x < m && y>=0 && y < n){
int cost = grid[x][y];
if(dis[i][j] + cost < dis[x][y]){
dis[x][y] = dis[i][j] + cost;
cost == 0 ? q.emplace_front(x,y) : q.emplace_back(x,y);
}
}
}
}
return dis[m-1][n-1];
}
顺便还可以基于此复习下dijkstra算法的基本实现,代码如下:
cpp
public:
vector<int> dijkstra(int start, int n, vector<vector<pair<int,int>>>& graph) {
// dis数组初始化无穷大
vector<int> dis(n, INT_MAX);
dis[start] = 0;
// 优先队列:pair<距离,节点>,C++默认大根堆,加greater变成小根堆
priority_queue<pair<int, int>, vector<pair<int,int>>, greater<pair<int,int>>> q;
q.emplace(0, start);
while(!q.empty()){
auto [d, u] = q.top();
q.pop();
// 如果堆里存的旧距离 > 当前已知最短距离,直接跳过
if(d > dis[u]) continue;
// 遍历u所有邻边
for(auto [v, w] : graph[u]){
if(dis[u] != INT_MAX && dis[u] + w < dis[v]){
dis[v] = dis[u] + w;
q.emplace(dis[v], v);
}
}
}
return dis;
}
地图分析

思路: 题上要求找到离最近的海洋的陆地到其最远距离,因此我们可以同时从多个陆地结点开始bfs,这时海洋就会被离他最近的陆地先波及到。随后怎么找最远的呢?之前都是遇到结点符合条件就结束bfs,这里我们就应该等处理完在返回。
代码如下:
cpp
public:
int maxDistance(vector<vector<int>>& grid) {
int m = grid.size();
int landcnt = 0,seacnt = 0;
vector<pair<int,int>> q;
for(int i = 0;i<m;i++){
for(int j = 0;j<m;j++){
if(grid[i][j] == 1){
grid[i][j] = -1;
q.emplace_back(i,j);
landcnt++;
}else{
seacnt++;
}
}
}
if(landcnt == 0 || seacnt == 0){
return -1;
}
for(int ans = 0;!q.empty();ans++){
auto cur = move(q);
for(auto&[i,j] : cur){
for(auto[dx,dy] : DIRS){
int x = i+dx; int y =j+dy;
if(x >= 0 && x < m && y>=0 && y<m && grid[x][y] == 0){
grid[x][y] = -1;
q.emplace_back(x,y);
}
}
}
if(q.empty()) return ans;
}
return -1;
}
平衡二叉树

思路:看到树的题自然尝试递归,于是我们可以每层检查当前是否为平衡二叉树,若不是则直接返回-1。代码如下:
cpp
int getheight(TreeNode* root){
if(root == nullptr){
return 0;
}
int left = getheight(root->left);
int right = getheight(root->right);
if(left == -1 || right == -1 || abs(left-right) > 1){
return -1;
}
return max(left,right)+1;
}
public:
bool isBalanced(TreeNode* root) {
return getheight(root) !=-1;
}
买卖股票最佳时机

思路:和上周的最大子数组和很像,不过这里不用算数组。
代码如下:
cpp
public:
int maxProfit(vector<int>& prices) {
int minprice = prices[0];
int ans = 0;
for(int x : prices){
ans = max(ans,x - minprice);
minprice = min(minprice,x);
}
return ans;
}
买卖股票最佳时机2

思路:将每一天的状态定义为持有股票和未持有股票,得到状态转移方程即可。
代码如下:
cpp
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
vector<vector<int>> f(n+1,vector<int>(2));
f[0][1] = INT_MIN;
for(int i = 0;i<n;i++){
f[i+1][0] = max(f[i][0],f[i][1]+prices[i]);
f[i+1][1] = max(f[i][1],f[i][0]-prices[i]);
}
return f[n][0];
}
只出现一次的数字

思路: 考虑到除目标元素外均出现两次,因此可以挨着异或,最后剩下的即为结果,代码如下:
cpp
public:
int singleNumber(vector<int>& nums) {
int ans = 0;
for(int x : nums){
ans ^= x;
}
return ans;
}
位1的个数

思路:同上题一样也是位运算,简单的想法是每次右移一位与1异或,当然我们还可以让n和n-1异或,这样的效果是去除n最靠右的1。于是代码如下:
cpp
public:
int hammingWeight(int n) {
int ans = 0;
while(n != 0){
n = n&(n-1);
ans++;
}
return ans;
}
多数元素2

思路:使用摩尔投票算法处理。初始选定两个候选人开始抵消,最后检验即可。代码如下:
cpp
public:
vector<int> majorityElement(vector<int>& nums) {
int n = nums.size();
vector<int> ans;
int e1 = 0;
int e2 = 0;
int hp1 = 0;
int hp2 = 0;
for(int x : nums){
if(hp1 > 0 && x == e1){
hp1++;
}else if(hp2 > 0 && x == e2){
hp2++;
}else if(hp1 == 0){
e1 = x;
hp1++;
}else if(hp2 == 0){
e2 = x;
hp2++;
}else{
hp1--;
hp2--;
}
}
int cnt1 = 0;
int cnt2 = 0;
for(int x : nums){
if(x == e1){
cnt1++;
}else if(x == e2){
cnt2++;
}
}
if(cnt1 > n/3){
ans.push_back(e1);
}
if(cnt2 > n/3){
ans.push_back(e2);
}
return ans;
}