我几天前在一家公司的在线筛选测试中遇到了这个问题。问题陈述如下:
有n个人排队购买演出门票。由于很高 要求,场地按照以下规则出售门票:
- 该行的负责人可以购买一张票,然后必须退出该行。
- 如果一个人需要购买额外的门票,他们必须重新进入线路末端并等待出售他们的下一张门票(假设退出 并且重新进入需要零秒。)
- 每张门票只需一秒钟。
我们将n个人的初始行表示为数组,ticket = [tickets0, tickets1 ... ticketsN-1],其中ticketi表示门票数量 我想买的人。如果杰西站在这个位置p ,找出他需要花多少时间购买所有门票。 在下面的编辑器中完成等待时间功能。它有两个 参数:
- n个正整数的数组,票据,描述排队的人的初始顺序。每个ticketi描述的数量 一个人在最初的地方等候的门票。
- 醇>
整数p,表示杰西在故障单中的位置。
样品输入5 2 6 3 4 5 2样品输出12 样品输入4 5 5 2 3 3样品输出11
在测试期间,我想出了这个简单的方法,它通过了大多数测试用例,但是在一些测试用例上超时了:
long waitingTime(vector<int> tickets, int p) {
// bool flag indicates whether it's Jesse or not
queue<pair<int, bool> > aQueue;
for(int i = 0; i < tickets.size(); i++) {
aQueue.push(make_pair(tickets[i], i == p));
}
long long nTime = 1;
while(!aQueue.empty()) {
pair<int, bool> aItem = aQueue.front();
aQueue.pop();
nTime++;
if(aItem.first == 1 && aItem.second == true)
break;
else if(aItem.first > 1) {
aQueue.push(make_pair(aItem.first-1, aItem.second));
}
}
return nTime-1;
}
但我无法找到解决此问题的不同方法。我认为还有其他方法,无需模拟整个队列流。如果有人能为我提供正确的解决方法,我将非常感激。提前谢谢!
答案 0 :(得分:8)
两次看问题,我认为应该有可能采用分析解决方案。
我的想法是:
因此,应该可以简单地在一个循环中总结数字。 这将意味着O(n)而不是O(n 2 )。
我意识到,结果也取决于杰西的位置。
但是,我的结果看起来与样本输出有所不同。
因此,我也实施了一个天真的解决方案(类似于OP)。
来源waiting-queue.cc
:
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
// naive approach
int waitingTimeSim(const std::vector<int> &tickets, int p)
{
// setup sim. model
std::queue<std::pair<int, bool> > people;
for (int i = 0, n = (int)tickets.size(); i < n; ++i) {
people.push(std::make_pair(tickets[i], i == p));
}
// simulation
int tP = 0;
for (;;) {
std::pair<int, bool> person = people.front();
people.pop();
--person.first; ++tP; // buy ticket
if (!person.first) { // if person is done
if (person.second) return tP; // It's Jesse -> terminate
} else people.push(person);
}
}
// analytical approach
int waitingTime(const std::vector<int> &tickets, int p)
{
int tP = 0, ticketsP = tickets[p];
for (int i = 0, n = (int)tickets.size(); i < n; ++i) {
tP += std::min(tickets[i], ticketsP - (i > p));
// i > p -> people after jesse -> decr. by 1
}
return tP;
}
int main()
{
{ std::vector<int> tickets{ 2, 6, 3, 4, 5 };
for (int p = 0, n = tickets.size(); p < n; ++p) {
std::cout << "tickets{ 2, 6, 3, 4, 5 }, p = " << p << std::endl;
int tS = waitingTimeSim(tickets, p);
std::cout << "simulated t: " << tS << std::endl;
int t = waitingTime(tickets, p);
std::cout << "computed t: " << t << std::endl;
}
}
{ std::vector<int> tickets{ 5, 5, 2, 3 };
for (int p = 0, n = tickets.size(); p < n; ++p) {
std::cout << "tickets{ 5, 5, 2, 3 }, p = " << p << std::endl;
int tS = waitingTimeSim(tickets, p);
std::cout << "simulated t: " << tS << std::endl;
int t = waitingTime(tickets, p);
std::cout << "computed t: " << t << std::endl;
}
}
return 0;
}
我将来源上传到 ideone.com。
我的测试会话(g ++,cygwin,Windows 10):
$ g++ -std=c++11 -o waiting-queue waiting-queue.cc
$ ./waiting-queue.exe
tickets{ 2, 6, 3, 4, 5 }, p = 0
simulated t: 6
computed t: 6
tickets{ 2, 6, 3, 4, 5 }, p = 1
simulated t: 20
computed t: 20
tickets{ 2, 6, 3, 4, 5 }, p = 2
simulated t: 12
computed t: 12
tickets{ 2, 6, 3, 4, 5 }, p = 3
simulated t: 16
computed t: 16
tickets{ 2, 6, 3, 4, 5 }, p = 4
simulated t: 19
computed t: 19
tickets{ 5, 5, 2, 3 }, p = 0
simulated t: 14
computed t: 14
tickets{ 5, 5, 2, 3 }, p = 1
simulated t: 15
computed t: 15
tickets{ 5, 5, 2, 3 }, p = 2
simulated t: 7
computed t: 7
tickets{ 5, 5, 2, 3 }, p = 3
simulated t: 11
computed t: 11
$
注意:的
恕我直言,名称waitingTime()
有点误导,因为作业明确说明你必须
了解他购买所有门票需要多长时间。
因此,我的实施计算了等待时间 + 杰西需要购买他的最后一张票的时间。
更新
一个经常使用的德语短语说:谁能读懂显然是有利的。 (听起来听起来不像德语那样好用和方便:“Wer lesen kann,ist klar im Vorteil。”)然而,在再次阅读Rohan Kumar的评论答案后,我的评论问题,将我的样本输入调整到OP,突然得到了预期的输出。但是,算法没有改变。
答案 1 :(得分:6)
这是我解决这个问题的想法,先来看看这一行。我们将人分为两组:
1 /那些站在 pth 之前
2 /那些站在 pth perosn后面
我们打电话次 - 购买足够票的 pth 人必须采取的行动次数。
现在考虑第一组[ tickets0,tickets1,...,ticketsP-1 ],如果有一个人 i 需要购买小于 pth 人的票数,然后只需添加&lt; ticket i &gt; 次( pth 人必须等待我之前的持续时间,直到他离开线路为止)。 否则,如果 i 的人购票金额大于人 pth ,请添加&lt; ticket p &GT; 次。
其次,对于那些站在 pth 人[ ticketsP + 1,ticketsP + 2,...,ticketsN ]后面的人也有同样的想法。考虑到人 t ( t&gt; p ),我们添加&lt; ticket t &gt;如果 ticketT &lt; 次 ticketP 即可。除非 person t 购买的门票少于 person p ,否则跳过最后一轮,只需添加&lt; ticket p - 1&gt;至次
在迭代这些行时,不要忘记每当遇到 person p 时,将 ticket p 添加到次。
public static long times( int[] tickets, int p) {
long times = 0;
int[] temp = Arrays.copyOf(tickets, tickets.length); //creating this array to check whether the *person i* buy tickets less than *person p*
for(int i = 0; i < tickets.length; i++ ) {
temp[i] = tickets[i] - tickets[p];
}
for(int i = 0; i < tickets.length; i++ ) {
if(temp[i] < 0) times += tickets[i];
else {
if(i <= p) times += tickets[p];
else times += tickets[p] - 1;
}
}
return times;
}
说明:
样本输入 4 5 5 2 3 3 样本输出 14
p = 4,14 = 3 + 3 + 2 + 3 + 3
答案 2 :(得分:6)
通过HackerRank上的所有测试用例。最简单的解决方案是 -
def waitingTime(tickets, p):
total_steps = tickets[p]
first_half = tickets[:p]
second_half = tickets[p+1:]
for num in first_half:
if num < tickets[p]:
total_steps += num
else:
total_steps += tickets[p]
for num in second_half:
if num < tickets[p]:
total_steps += num
else:
total_steps += tickets[p] - 1
return total_steps
e.g。五个人站在队列中。他们的票数在下面的列表中给出。 Jesse站在第3位(列表索引= 2)
[2,6,3,4,5]
上半场= [2,6] 下半场= [4,5]
现在考虑上半年 -
#1号人想买2张票。 Jesse的数量(3)大于2.所以这个人肯定会在Jesse之前两次访问售票窗口。因此,total_unit_time = 2
第2号人想购买6张门票。 Jesse的数量(3)小于6.所以这个人将在Jesse之前3次访问售票窗口。所以total_unit_time = 2+ 3
现在考虑下半场 - 1.#1人想买4张票。 Jesse的数量(3)小于4.现在,Jesse将购买他的第一张票然后该人将有机会购买他的第一张票。但是杰西将不得不等待2个回合才能购买剩余的2张门票。所以total_unit_time = 2 + 3 + (3-1)
答案 3 :(得分:1)
Java解决方案:
static long waitingTime(int[] tickets, int p) {
long noOfIterations = 0;
int ticketBeingProcessed = 0;
int numberOfParticipantsInLine = tickets.length;
if(numberOfParticipantsInLine > p)
{
while(tickets[p] != 0)
{
// The person has already got his ticket and exited the line, just go to the next person, dont increase number of iterations because it took no time
if(tickets[ticketBeingProcessed] != 0)
{
// ticket being processed got one ticket
tickets[ticketBeingProcessed] = tickets[ticketBeingProcessed] -1;
// if we have reached the end of the line
if(ticketBeingProcessed == numberOfParticipantsInLine -1)
ticketBeingProcessed = 0;
else
ticketBeingProcessed ++;
noOfIterations ++;
}
else {
if (ticketBeingProcessed == numberOfParticipantsInLine - 1)
ticketBeingProcessed = 0;
else
ticketBeingProcessed++;
}
Log.d("asd",printArray(tickets));
}
}
return noOfIterations;
}
答案 4 :(得分:1)
对于python:
def function(tickets):
count = 0
delta = 0
for i in range(len(tickets)):
if tickets[i] < tickets[p]:
delta+=tickets[p]-tickets[i]
if i > p:
delta - = 1
count = len(tickets) * (tickets[p] - 1) + (p+1) - delta
return count
答案 5 :(得分:0)
这是我提出的解决方案(在Java中,但是有c ++背景的人都可以阅读此代码)
import java.util.Arrays;
import java.util.List;
public class TickerPurcahseTime {
public static int calculateTimeOptimized(List<Integer> line, int pos) {
// Minimum time I have to wait is the number of tickets I want to buy.
int waitingTime = line.get(pos);
for (int i = 0; i < line.size(); i++) {
if (i == pos) continue;
// I will see people -> minimum(how many tickets I need, how many tickets they need).
waitingTime += (Math.min(line.get(pos), line.get(i)));
// Unless they were behind me, I got my ticket before them so I need to see them 1 time less.
if (i > pos) {
waitingTime--;
}
}
return waitingTime;
}
public static void main(String [] args) {
System.out.println(calculateTimeOptimized(Arrays.asList(5, 5, 2, 3), 3));
}
}
答案 6 :(得分:0)
这是简单的C ++解决方案:
#include<bits/stdc++.h>
using namespace std;
int waiting_time(int ticket[],int p,int size)
{
int count=0;
while(ticket[p]!=0)
for(int i=0;i<size;i++)
{
if(ticket[p]!=0)
{
if(ticket[i]>0)
count++;
ticket[i]--;
}
}
return count;
}
int main()
{
int ticket[]={5, 5, 2, 3};
int p=3;
int size=sizeof(ticket)/sizeof(ticket[0]);
cout<<waiting_time(ticket,p,size);
return 0;
}
答案 7 :(得分:0)
这是使用红宝石的简单解决方案
def waiting_line(tickets, p)
user_tickets = tickets[p]
time = 0
while user_tickets > 0
for i in (0...tickets.length)
break if tickets[p] == 0
next if (tickets[i] == 0)
time +=1
tickets[i] -= 1
end
user_tickets -=1
end
time
end
答案 8 :(得分:0)
这个在python中怎么样
def calculateTickets(l,p):
j=int(0)#contador de
while(l[p]!= 0 ):
i=0
for i in range (len(l)):
if(l[p]==0):
break
if(l[i]>0):
l[i]-=1
j+=1
i+=1
print(str(j)+"\n")
答案 9 :(得分:0)
解决方案:C#
/// <summary>
/// Buying show tickets
/// </summary>
public static void BuyingShowTickets()
{
int[] tickets = { 2, 6, 3, 4, 5 };
int alexPos = 2;
Queue queue = new Queue();
foreach (int tik in tickets)
queue.Enqueue(tik);
int alexValue = tickets[alexPos];
int queuePopValue = 0;
int queuePopNewValue = 0;
int noOfTransactions = 0;
//Loop until Alex has bought all the tickets
while (alexValue != 0)
{
//Total no of tickets to buy
queuePopValue = (int)queue.Peek();
//Buy one ticket
queuePopNewValue = queuePopValue - 1;
//Move out from the queue
queue.Dequeue();
//Increase the number of iteration
noOfTransactions++;
//If you still have more tickets to buy go to the end of the line
if (queuePopNewValue != 0)
{
queue.Enqueue(queuePopNewValue);
}
//Track where Alex is now. If Alex is buying the ticket and
//he has more tickets to buy then go to the end of the line
//else just more forward
if (alexPos > 0)
{
alexPos--;
}
else
{
alexPos = queue.Count - 1;
alexValue--;
}
}
Console.WriteLine("Total time taken: {0}",noOfTransactions);
}
答案 10 :(得分:0)
Python中的简单代码
# position is in zero based indexing
def calculate_time(pos, line):
# get the number of tickets at given position
value = line[pos]
# split the people before and after the given position
people_before = line[:pos+1]
people_after = line[pos+1:]
time_taken = 0
while value > 0:
# reduce 1 from each of the person
people_before = [x-1 for x in people_before]
time_taken += len(people_before)
# remove the persons with zero tickets
people_before = list(filter(lambda x: x>0, people_before))
value -= 1
if value != 0: # if the number of ticket at given position becomes zero, stop
people_after = [x-1 for x in people_after]
time_taken += len(people_after)
people_after = list(filter(lambda x: x>0, people_after))
return time_taken
jesse_pos = 4
line = [2, 6, 3, 4, 5 ]
print(calculate_time(jesse_pos, line))
输出: 19
时间复杂度:O(n)
答案 11 :(得分:-1)
这是一种使用ruby的不同方法,但可以很容易地转换为C或Java。
def incr_i n, i
i += 1
i = 0 if i >= n
i
end
def waitingTime(tickets, p)
time = 0
i = 0
n = tickets.size
# Note: a timeout can be added for avoiding infinite loops
while true
next i = incr_i(n, i) if tickets[i] <= 0
#puts "#{tickets.to_s}, i: #{i}, time: #{time}"
tickets[i] -= 1
time += 1
break if tickets[p] <= 0
i = incr_i(n, i)
end
time
end