华为笔试真题

第一题:分配捐赠

思路:

代码实现:

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值