第一题:分配捐赠
思路:
代码实现:
class Solution {
public:
pair<int, int> solve(vector<int> pMoney, int donate, int n) {
sort(pMoney.begin(), pMoney.end());
int left = 0, right = 0; //左闭右闭
int maxCount = INT_MIN;
int remain = donate;
while(left <= right) {
while(donate >= 0 && right < n - 1) {
if(right - left + 1 > maxCount) {
maxCount = right - left + 1;
remain = donate;
}
++right;
donate -= ((pMoney[right] - pMoney[right - 1]) * (right - left));
}
while(donate < 0 && left <= right) {
++left;
donate += (pMoney[right] - pMoney[left]);
}
}
return {maxCount, remain};
}
};
int main() {
vector<int> pMoney = {5, 1, 20};
int n = 3;
int donate = 2;
auto ret = Solution().solve(pMoney, donate, n);
return 0;
}
第三题:最大面积黑像素
思路:要求最多两次改动后的相互连通的最大黑色像素区域面积,而黑色像素区域的面积的不同的,所以可以遍历整个二维数组的过程中,对不同的黑色像素区域进行编号。由于0和1已经被使用了,那么像素颜色的编号我们就从2
开始,当遍历到新的元素时,黑色像素区域的编号加1。并且在遍历过程中,将每个黑色像素区域的面积也统计出来了,保存在 unordered_map 中(key=黑色像素区域编号
;value=黑色像素区域的面积
)。
那么我们遍历二维数组中的所有元素,只有当像素是白色(即元素的值为:0)时,我们来判断其上、下、左、右元素的值,再来结合 unordered_map 中存储的黑色像素区域编号与面积的对应关系,进行黑色像素区域面积计算即可。比如,在我们遍历的这个元素的周围:上元素值为:2,下元素值为:3,左元素为:0,右元素为:0,所以我们可以知道这块像素元素与黑色像素区域2和黑色像素区域 3 是相邻的,那么总的面积就是:黑色像素区域2的面积+ 黑色像素区域 3 的面积 + 像素元素翻转面积(1)。通过这种方式,将遍历所有元素,改动两次像素元素后,返回最大的黑色像素区域面积。
对于每个元素遍历的时候,我们采用深度优先遍历方式,即:先后深度的去遍历该元素的上方向、下方向、左方向和右方向。为了防止遍历不同元素时,出现重复遍历,我们采取遍历到“岛屿”后,将格子值赋值为区域面积编号的方式。
代码实现:
#include<vector>
#include<iostream>
#include<string>
#include<sstream>
#include<unordered_set>
#include<unordered_map>
#include<bits/stdc++.h>
using namespace std;
vector<int> inputToVecInt() {
string line, word;
getline(cin, line);
stringstream sin(line);
vector<int> ret;
while (sin >> word) {
ret.push_back(stoi(word));
}
return ret;
}
class Solution {
public:
int m, n;
int dfs(vector<vector<int>>& map, int x, int y, int sign) {
if (x<0 || x >= m || y<0 || y >= n) return 0;
if (map[x][y] != 1) return 0;
map[x][y] = sign;
return 1 + dfs(map, x - 1, y, sign) + dfs(map, x + 1, y, sign) + dfs(map, x, y + 1, sign) + dfs(map, x, y - 1, sign);
}
void findNeighbours(vector<vector<int>>& map, unordered_set<int>& set, int x, int y) {
if (x - 1 >= 0 && map[x - 1][y] != 0) set.emplace(map[x - 1][y]);
if (x + 1<m && map[x + 1][y] != 0) set.emplace(map[x + 1][y]);
if (y - 1 >= 0 && map[x][y - 1] != 0) set.emplace(map[x][y - 1]);
if (y + 1<n && map[x][y + 1] != 0) set.emplace(map[x][y + 1]);
}
int largestIsland(vector<vector<int>> &map) {
m = map.size();
if (!m) return 0;
n = map[0].size();
// 记录当前岛屿的面积,并同时给岛屿进行标记:组成同一岛屿的每一块具有相同的标记
unordered_map<int, int> singleArea;
int maxSingleArea = 0;
int sign = 2; // 0 和 1 都用了,所以从 2 开始编号
for (int i = 0; i<m; ++i) {
for (int j = 0; j<n; ++j) {
if (map[i][j] == 1) {
singleArea.emplace(sign, dfs(map, i, j, sign));
maxSingleArea = max(maxSingleArea, singleArea[sign]);
sign++;
}
}
}
// 查询海洋相邻的路径
int x = -1, y = -1;
for (int time = 0; time != 2; ++time) {
unordered_set<int> alterSignSet;
for (int i = 0; i<m; ++i) {
for (int j = 0; j<n; ++j) {
// 遇到一个非岛屿,则判断上下左右是否连通。使用 unordered_set 进行去重
if (map[i][j] == 0) {
unordered_set<int> set;
findNeighbours(map, set, i, j);
int unionMax = 0;
for (auto iter = set.begin(); iter != set.end(); ++iter) {
unionMax += singleArea[*iter];
}
if (unionMax>=maxSingleArea) {
maxSingleArea = unionMax;
if (time == 0) {
alterSignSet = set;
x = i;
y = j;
}
}
}
}
}
if (time == 0) {
map[x][y] = sign;
singleArea.insert(pair<int, int>(sign, maxSingleArea + 1>m*n ? m*n : maxSingleArea + 1));
for (int k = 0; k<m; ++k) {
for (int l = 0; l<n; ++l) {
if (alterSignSet.find(map[k][l]) != alterSignSet.end()) {
map[k][l] = sign;
}
}
}
}
}
// 矩阵一个 0 没有,全为 1, 矩阵的面积就是岛屿的面积
return maxSingleArea + 1>m*n ? m*n : maxSingleArea + 1;
}
};
int main()
{
vector<int> mn = inputToVecInt();
int m = mn[0], n = mn[1];
vector<vector<int>> map;
for (int i = 0; i != m; ++i) {
map.push_back(inputToVecInt());
}
cout << Solution().largestIsland(map);
system("pause");
return 0;
}