题目一:披萨问题
简介
一家披萨电制作素食披萨和肉类披萨,顾客在店里下达N个订单后,订单号码会打印在他们的账单上,该店会在显示器屏幕上同时显示N个订单中的K个素食和肉类披萨订单,这家店非常有名,会收到很多订单。因此,为了避免混淆,素食披萨订单显示为正订单号,肉类披萨订单显示为负订单号,所有订单按照其在屏幕上显示的顺序派送。每当有显示的订单完成后,就将它从显示屏幕上删除,并将下一个订单添加到末尾。
一对夫妇带着他们的孩子来吃披萨,孩子非常调皮,为了让他一直有事可做,他的父母要他列出店中屏幕上显示的每K个订单中第一个肉类披萨的订单号。
编写一个算法,帮助他列出每派送一个订单给顾客后,屏幕上显示的第一个肉类披萨的订单号
输入
- numOfOrders,表示所下达的订单总数(N)的整数。
- size,表示屏幕上所显示订单数(K)的整数。
- orders,表示顾客下达的订单中素食披萨和肉类披萨订单号的订单列表。
输出
- 返回每次向顾客派送订单后,屏幕上显示的每组K个订单的第一个肉类披萨的订单号,如果屏幕未显示任何肉类披萨订单,则返回0。
约束条件
示例
输入
- numOfOrders = 6
- size = 3
- orders = [-11,-2,19,37,64,-18]
输出
- [-11,-2,0,-18]
说明
- 第1步:第一次显示时,显示的订单号是[-11,-2,19],所以显示的第一个肉类披萨订单号是-11。
- 第2步:第二次显示时,显示的订单号是[-2,19,37],所以显示的第一个肉类披萨订单号是-2。
- 第3步:第三次显示时,显示的订单号是[19,37,64],由于未显示肉类披萨订单,因此输出为0。
- 第4步:第四次显示时,显示的订单号是[37,64,-18],所以显示的第一个肉类披萨订单号是-18。
分析
我们很直观的可以想到一个笨办法,即显示的K个订单中,第一个订单下标为i,那么我们可以遍历[i,i+3),查看范围内是否有负订单号,是则遇到第一个负订单号即停止,否则为0。笨办法的时间复杂度为O(N*K)。
屏幕每次显示K个订单,当K个订单中的第一个订单派送后,若第一个订单为负订单号,则下一次计算出的第一个负订单号变;若第一个订单号为正订单号,则下一次计算出的第一个负订单号不变,仍为原来的负订单号。如何记录负订单号呢,我们想到了队列,队列有先进先出的优点,符合我们的要求。
但同时我们注意到,如何判断队列中的负订单号应该出队列?显然,下标可以做到。当队列中的第一个负订单号下标为i时,我们遍历到i+2下标时就需要出队列操作。因此,队列中的元素应为负订单号的下标值。
这种思路的时间复杂度为O(N)。
步骤
前k-1个订单,直接判断订单号:若为负订单号,则下标进队列;若为正订单号,直接++i。
从第K个订单起,先判断订单号:若为负订单号,则下标进队列。
若队列为空,说明没有负订单号,结果为0。
若队列不为空,将第一个负订单号记录到结果中,并且判断第一个负订单号是否应该出队列(下标判断)。
代码段
#include<vector>
#include<iostream>
#include<queue>
using namespace std;
vector<int> pizzaOrder(int numOfOrders, int size, int* orders) {
vector<int> res;
queue<int> index;
for (int i = 0; i < numOfOrders; ++i) {
//前k-1个订单,直接判断订单号:若为负订单号,则下标进队列
if (i < size-1 ) {
if(orders[i] < 0)
index.push(i);
continue;
}
//从第K个订单起,先判断订单号,若为负订单号,则下标进队列
if (orders[i] < 0)
index.push(i);
//此时,若队列为空,说明没有负订单号,结果为0
if (index.empty()) {
res.push_back(0);
}
else {
//若队列不为空,将第一个负订单号记录到结果中。判断第一个负订单号是否应该出队列
res.push_back(orders[index.front()]);
if(i-index.front()+1==size)
index.pop();
}
}
return res;
}
int main(int argc, char* argv[]) {
int n = 7;
int k = 4;
int order[] = { 35,-42,23,-56,-84,92,39 };
vector<int> res = pizzaOrder(n, k, order);
getchar();
return 0;
}
题目二:最小信号强度
简介
X位工程师正在进行公司的一个项目,他们需要一个媒介来互相联系和共享数据。网络管理员奥斯汀建立了一个分级网络,使得每个工程师可以进一步连接到网络中最多两名工程师。他在网络中建立了所有的全双工连接,即如果A和B之间有连接,则数据可以从A传输到B,也能从B传输到A。信号的强度在每个跃点减少一个单位。因此,为了让所有人都能收到信号,他需要确定每个工程师发送信号所需的最小强度。
编写一个算法,帮助奥斯汀找出每个工程师发送信号所需的最小强度,以便网络中的每个人都能收到信号。
输入
- 该函数的输入包括一个字符串网络network,表示处于一种层级顺序的网络,该层级顺序使得索引 和 处的字符是索引 处字符的子项。
输出
- 返回一个非负整数列表,表示每个工程师按照层级顺序发送数据所需的最小信号强度。
注意
- 在输入字符串中用1表示一位工程师。如果某一位工程师不能进一步连接到其他工程师,则应该在其子节点位置出现0,以表示一个空的子项。
约束条件
- 其中len表示给定字符串的长度。
示例
输入
- network = 111110000010000
输出
- [3,2,4,3,3,4]
解释
- 对于network = 111110000010000的情况,网络表示为:
- 距离节点A最远的节点为F。所以节点A发送信号所需的最小信号强度为3。
- 距离节点B最远的节点是F和C,而距离C最远的是F。所以节点B和C发送信号所需的最小信号强度为2和4。
- 距离节点D和E最远的节点为C。所以节点D和E发送信号所需的最小信号强度为3。
- 距离节点F最远的节点为C。所以节点F发送信号所需的最小信号强度为4。
- 对于network = 111110000010000的情况,网络表示为:
分析
我们可以看出,对节点的存储和描述和堆的定义很相似。
字符串相当于数组,下标访问为父节点到左节点: ,父节点到右节点: 。
左右节点到父节点: 。
先遍历一遍字符串,记录字符串中字符为1(某工程师)的节点到叶子节点的最小信号强度,即 。用map来存储(map<字符下标,最小信号强度> m;),节点高度用length函数计算。
再遍历一遍字符串,从该节点向父节点查询是否还存在更远的节点。以节点F为例:
- 节点F的下标为10,则m[10]=0;设上查找操作的最大值为
- 找到节点F的父节点E,即 ,信号强度+1=1,因节点E无左子树, ,进入下一步。
- 找到节点E的父节点B,即 ,信号强度+1=2,因节点B存在左子树,需计算一下左子树的高度,D的高度=D的最小强度+1=1,则 ,进入下一步。
- 找到节点B的父节点A,即 ,信号强度+1=3,因节点A存在右子树,需计算一下右子树的高度,C的高度=C的最小强度+1=1,则 ,进入下一步。
- 因访问到根节点,跳出循环,判断上查找操作的最大值与下查找操作的值(即节点到叶子节点的最小信号强度)的大小,找到最小信号强度。
代码段
#include<vector>
#include<iostream>
#include<map>
#include<algorithm>
#include<string>
using namespace std;
int length(string network,int i) {
if ((i >= network.length()) || network[i]=='\0' || network[i] == '0')
return 0;
int left = lens(network, 2 * i + 1);
int right = lens(network, 2 * i + 2);
return left > right ? left+1 : right+1;
}
vector<int> mm(string network) {
vector<int> res;
map<int, int> m;
for (int i = 0; network[i] != '\0'; ++i) {
if (network[i] == '1') {
m[i] = lens(network,i)-1;
}
}
for (int i = 0; network[i] != '\0'; ++i) {
if (network[i] == '1') {
if (i == 0) {
res.push_back(m[i]);
}
else {
int max_res = 0;
int temp = 0;
int j = (i-1)/2;
int z = i;
int flag = 0;
while (j >= 0) {
if (flag == 1)
break;
if (flag == 0 && j == 0) {
flag = 1;
}
++temp;
if (z == 2 * j + 1 && network[2*j+2]!='0') {
int k = 2 * j + 2;
max_res = max(max_res, m[k] + temp + 1);
}
else if (z == 2 * j + 2 && network[2 * j + 1] != '0') {
int k = 2 * j + 1;
max_res = max(max_res, m[k] + temp + 1);
}
z = j;
j = (z - 1) / 2;
}
max_res = max(m[i], max_res);
res.push_back(max_res);
}
}
}
return res;
}
int main(int argc, char* argv[]) {
string network;
cin >> network;
mm(network);
getchar();
return 0;
}