美团暑期实习
只留下了后两道编程题。。。 不过据说前两个编程题比较简单
编程题03 - 众数
具体题我就不抄了.. 大概意思是求滑动窗口(长度为k)内的所有最小众数(只有一个众数 直接输出, 有多个众数出现次数相同-> 输出最小的)
具体方案是维护这样一个数据结构:
hash
: 维护窗口内每个元素的出现次数vector<set<int>> A
: 对于每个出现次数i而言 A[i]存放出现次数为i的所有元素
这样在进入窗口和弹出窗口的时候更新一下这两个就好了
void modify(vector<set<int>>& A, unordered_map<int, int>& hash, int val, bool is_add)
{
A[hash[val]].erase(val);
if(is_add) hash[val]++;
else hash[val]--;
A[hash[val]].insert(val);
}
vector<int> solution(vector<int>& nums, int k)
{
vector<int> res;
unordered_map<int, int> hash;
vector<set<int>> A(k + 1); // 出现次数为i的元素所在的集合
for(int l = 0, r = 0, max_cnt = 0; r < nums.size(); r++)
{
modify(A, hash, nums[r], true);
if(hash[nums[r]] > max_cnt) max_cnt = hash[nums[r]];
if(l < r - k + 1)
{
modify(A, hash, nums[l++], false);
if(A[max_cnt].empty()) max_cnt--;
}
if(r >= k - 1) res.push_back(*A[max_cnt].begin());
}
return res;
}
编程题04 - 树上DP
美团图论和dp是必考的 得了 这回考了个图论+dp的结合
具体题的意思: 给定一棵树,每一个节点有一个权重,选择其中某些节点,满足被选中的节点两两不相邻,求在所有的选择方案中,最大化被选择节点权值之和的情况下,被选择节点权值最小值尽可能大。
输入
第一行两个整数N和M,分别表示树的节点数和边数 第二行为N个整数,分别表示每个节点的权重 接下来M行,每行两个整数a和b,存在一条从a到b的边。
输出
输出两个整数,表示能选择的最大权值之和是多少,以及权值最小值是多少,用空格分割。
输入样例
5 4
3 4 1 4 9
1 2
1 3
2 4
3 5
输出样例
16 3
基础就是 树上一条边只能选一个节点, 求权值最大 可以说是树上DP的经典题了
这题比我做过的树上DP还要怪 我开始也没反应过来那个最大化被选择节点权值之和的情况下,被选择节点权值最小值尽可能大是啥意思
后来发现是在两个子节点权值一样 选哪个都可以的时候,选哪个权值大的child
剩下的建图和DFS(是的树上dp都是dfs写的)都是很经典的套路了
f[i, 0] 表示不选node[i]的最大方案
f[i, 1] 表示选node[i]的最大方案
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int n, m;
int h[N], e[N], ne[N], idx;
int val[N];
int f[N][2], minv[N][2];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int father)
{
f[u][1] = val[u];
minv[u][1] = val[u];
for(int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if(j == father) continue;
dfs(j, u);
// // 一般处理
// f[u][1] += f[j][0];
// f[u][0] += max(f[j][1], f[j][0]);
f[u][1] += f[j][0];
minv[u][1] = min(minv[u][1], f[j][0]);
// 带最大值的更新
f[u][0] += max(f[j][0], f[j][1]);
if(f[j][0] > f[j][1])
minv[u][0] = min(minv[u][0], minv[j][0]);
else if (f[j][0] < f[j][1])
minv[u][0] = min(minv[u][0], minv[j][1]);
else
minv[u][0] = min(minv[u][0], max(minv[j][0], minv[j][1])); // 如果f一样 就挑大的
}
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", val + i);
// 1. 建图
while(m--)
{
int a, b;
scanf("%d%d", &a, &b);
add(a, b), add(b, a);
}
// 2. 树上dp
dfs(1, -1);
if(f[1][0] > f[1][1])
cout << f[1][0] << ' ' << minv[1][0] << endl;
else
cout << f[1][1] << ' ' << minv[1][1] << endl;
return 0;
}
Last updated