Hackerrank

I ran into this issue in the company's online screening test a few days ago. The problem statement reads like this:

There are people queuing up to buy tickets for the show. demand, the venue sells tickets according to the following rules:

  • The head of the line can buy exactly one ticket and then exit the line.
  • If a person needs to purchase additional tickets, they must re-enter the end of the line and wait to sell their next ticket (suppose exiting and re-entering takes zero seconds).
  • Each ticket sale takes exactly one second.

We express the initial string of n people as an array, tickets = [tickets0, tickets1 ... ticketsN-1], where ticketi represents the number of tickets for the person I want to buy. If Jesse is in position p on this line, find out how long it will take to buy all the tickets. Complete the wait function in the editor below. It has two parameters:

  • Array, tickets, n natural numbers describing the initial sequence of people in the queue. Each ticket indicates the number of tickets that the person is waiting for at the original location.
  • An integer p representing Jesse's position in the tickets.

    Sample input 5 2 6 3 4 5 2 Sample output 12 Sample input 4 5 5 2 3 3 Output for output 11

During the test, I came up with this simple approach, which passed most of the test cases, but was tested on multiple test cases from time to time:

long waitingTime(vector<int> tickets, int p) {
  // bool flag indicates whether it 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;
}

      

But I cannot find another approach to solve this problem. I think there is another way as well without being able to simulate the whole queue flow. I would really appreciate it if someone could give me the correct approach to solve this. Thanks in advance!

+3


source to share


10 answers


After looking at the problem twice, I realized that an analytic solution should be possible.

My idea is this:

  1. People I am in front of Jesse will remain in front of him minute {tickets I, tickets Jesse} time.
  2. Jesse himself will consume the tickets Jessie time.
  3. People I after Jesse will stay in front of Jesse min {tickets I am, tickets Jesse - 1} times.

Thus, it should be possible to simply sum the numbers in one cycle. This would mean O (n) instead of O (n 2 ).

As I understand it, this result will also depend on Jesse's position. However, my results looked slightly different than the sample output. So I implemented a naive solution (similar to the OP). Source 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 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;
}

      

I have uploaded the source to ideone.com .

My test session (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

$

      

Notes:

IMHO the name is a waitingTime()

bit misleading because the assignment clearly says you should

find out how long it will take him to buy all the tickets.

So my implementation counts the waiting time + the time Jesse has to buy for his last ticket.

Update:

A frequently used German phrase reads: "He who can read is what he is." (In English this does not sound as nice and convenient as in German: "Wer lesen kann, ist klar im Vorteil.") However, after reading again Rohan Kumar's comment-answer to my comment-question, I set up my example entry into the OP and unexpectedly got the expected result, but the algorithms did not change.

+8


source


All test cases on HackerRank passed. The simplest solution to this is

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

      

Explanation -

  1. Divide the list into two halves. People in front of Jesse and people behind Jesse.
  2. Check with each person in both halves how many tickets that person wants to buy.
  3. Let's take a look at the first half
  4. If a person wants to buy fewer tickets than Jesse's, he will visit the ticket office until he buys tickets before Jesse . So add his ticket count to your total time
  5. If a person wants to buy more or equal tickets than Jesse, then he will visit the ticket window before Jesse will be exactly as many times as Jesse visits the ticket window. So add the number of tickets for Jesse to the total unit time - which is equal to the number of tickets the person buys before Jesse
  6. Now, consider the second half -
  7. If the person behind Jesse wants to buy more or equal tickets than Jesse, they will visit the ticket office less than Jesse. So add (Jesse tickets - 1) to the total time
  8. If the person behind Jesse wants to buy fewer tickets than Jesse, then he will visit the ticket office until he has bought all of his tickets. So add the total number of tickets to the total time.
  9. Finally, add Jesse's ticket counter to the total time unit because Jesse will also visit the ticket window until he buys all the tickets he wants

For example, five people are queuing. Their number of tickets is shown in the list below. Jesse is in 3rd position (index list = 2)

[2,6,3,4,5]



first half = [2.6] second half = [4.5]

now consider the first half -

  1. Person # 1 wants to buy 2 tickets. Jesse's number (3) is greater than 2. So this person will make sure to visit the ticket booth twice in front of Jesse. Hence total_unit_time = 2

  2. Person # 2 wants to buy 6 tickets. Jesse's number (3) is less than 6. So this person will visit the ticket booth 3 times in front of Jesse. Total total_unit_time = 2+ 3

Now let's consider the second half - 1. Person # 1 wants to buy 4 tickets. Jesse's number (3) is less than 4. Now Jesse will buy his first ticket and then the person will have a chance to buy their first ticket. But then Jesse will have to wait 2 more moves to buy the remaining 2 tickets after this person. Total total_unit_time = 2+ 3+ (3-1)

  1. Person # 2 wants to buy 5 tickets. Jesse will buy his first ticket again and wait for the remaining two moves until this guy buys two tickets. Total total_unit_time = 2+ 3+ 2+ (3-1)

enter image description here

+7


source


Here is my idea to solve this problem, take a look at this line first. We divide people into two groups:
1 / Those who stand in front of the person. 2 / Those behind pth perosn.
Call times is the number of moves a person pth has to make to buy enough tickets.

Now, considering the first group [ticket0, tickets1, ..., ticketsP-1], if there is a person who needs to buy the number of tickets less than pth person , then just add <ticket i> times (duration, in which a person must wait for a person I until he gets out of line). Otherwiseif the amount of ticket purchases of person i is more than person pth, add <ticket p> at times .

Second, the same idea for those behind the person pth [tickets P + 1, tickets P + 2, ..., ticketsN]. Given the person t ( t> p ), add <ticket t> times if ticketT <ticketP . If person t does not buy less tickets than person p, skip the last round to just add <ticket p - 1> at times

When repeating lines, be sure to add ticket p every time you meet person 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;
} 

      

Explain:
Example Input 4 5 5 2 3 3 Output 14
p = 4, 14 = 3 + 3 + 2 + 3 + 3

+6


source


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

      

+1


source


For 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

      

+1


source


Here is the solution I came across (in Java, but anyone with a C ++ background can read this code)

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

      

0


source


Here's a simple C ++ solution:

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

      

0


source


so here is my comprehensive and clear O (n) solution

# people stading before jess will be waiting for t(p) times 
# (or)
# t(i) times (if t(i) - t(p) < 0 this means they will buy less tickets than jess, 
# so they will stand only t(i) times)
#
# people standing beside jess will be waiting for t(p)-1 times
# (or)
# t(i) time (if t(i) - t(p) < 0 )
#
# sum of the above will result in the wating time for jess

def wt(tickets, p):
    sum = 0;
    for i in range(len(tickets)):
        if i<=p :
            if tickets[i]-tickets[p] >= 0 :
                sum += tickets[p];
            else :
                sum += tickets[i];
        else:
            if tickets[i]-(tickets[p]-1) >= 0 :
                sum += tickets[p]-1;
            else:
                sum += tickets[i];
    print(sum);

      

test cases:

wt([5,5,2,3], 3)

wt([5,5,2,3], 0)

wt([5,5,2,3], 1)

wt([5,5,2,3], 2)

wt([1,1,1,1], 0)

wt([2,6,3,4,5], 2)

wt([2,6,3,4,5], 0)

wt([2,6,3,4,5], 1)

wt([2,6,3,4,5], 3)

wt([2,6,3,4,5], 4)

      

outputs:

11

14

15

7

1

12

6

20

16

19

      

0


source


Here is a simple solution using ruby

    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

      

0


source


This is a different approach using ruby, but can be easily translated to C or 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

      

-1


source







All Articles