问题陈述
一所大学只有一个旋转门。它既可以用作出口也可以用作入口。不幸的是,有时很多人想穿过旋转栅门,他们的方向可能会有所不同。第i个人在时间[i]到达旋转栅门,并希望在direction [i] = 1时退出大学,或者在direciton [i] = 0时进入大学。人们排成2个队列,一个队列退出,一个进入。它们按到达转闸的时间排序,如果时间相等,则按其索引排序。 如果有人想同时进入大学而又想离开大学,则有以下三种情况:
• If in the previous second the turnstile was not used (maybe it was used before, but not at the previous second), then the person who wants to leave goes first.
• If in the previous second the turnstile was used as an exit, then the person who
wants to leave goes first
• If in the previous second the turnstile was used as an entrance, then the person
who wants to enter goes first
通过旋转栅门需要1秒
为每个人找到他们通过旋转闸门的时间
该函数必须返回由n个整数组成的数组,当第i个人通过旋转闸门时,index [i]处的值相同。
该函数具有以下参数:
• time: an array of n integers where the value at index i is the time when the
ith person will came to the turnstile
• direction: an array of n integers where the value at index i is the direction
of the ith person
约束
• 1 <= n <= 105
• 0 <= time[i] <= 109 for 0 <= i <= n – 1
• time[i] <= time[i+1] for 0 <= i <= n - 2
• 0 <= direction [i] <= 1 for 0 <= i <= n – 1
示例:
n = 4
时间= [0,0,1,5]
方向= [0,1,1,0]
输出= [2,0,1,5]
示例2
n = 5
时间= [0,1,1,3,3]
方向= [0,1,0,0,1]
输出= [0,2,1,4,3]
这是我的实际尝试
def getTimes(time, direction)
persons = time.size - 1
exits = []
(0..persons).each do |person|
if time[person] == time[person + 1]
exits[person + 1] = time[person] if direction[person + 1] == 1 and direction[person] == 0
else
exits[person] = time[person] if direction[person] != direction[person + 1]
end
end
p exits
end
我的回复 [nil,0,1,5]
答案 0 :(得分:2)
代码
def pass_times(time, direction)
dir = direction.map { |d| d.zero? ? :ENTER : :EXIT }
enter, exit = time.each_index.map do |i|
{ person: i, direction: dir[i], arrival_time: time[i] }
end.partition { |h| h[:direction] == :ENTER }.
map { |arr| arr.sort_by { |h| h[:arrival_time] } }
time.each_index.with_object([]) do |_i,arr|
last_pass = last_pass_time(arr)
next_enter_time = enter.empty? ? Float::INFINITY :
[enter.first[:arrival_time], last_pass].max
next_exit_time = exit.empty? ? Float::INFINITY :
[exit.first[:arrival_time], last_pass].max
h = case
when last_pass_time(arr) < [next_enter_time, next_exit_time].min
g = next_exit_time <= next_enter_time ? exit.shift : enter.shift
add_pass_time(g, g[:arrival_time] + 1)
when next_enter_time < next_exit_time
add_pass_time(enter.shift, last_pass + 1)
when next_exit_time < next_enter_time
add_pass_time(exit.shift, last_pass + 1)
else
add_pass_time(arr.last[:direction] == :ENTER ?
enter.shift : exit.shift, last_pass + 1)
end
arr << h
end.sort_by { |h| h[:person] }.map { |h| h[:pass_time] }
end
def last_pass_time(arr)
arr.empty? ? -1 : arr.last[:pass_time]
end
def add_pass_time(g, pass_time)
g.merge(:pass_time => pass_time)
end
示例
time = [0,1,1,3,3]
direction = [0,1,0,0,1]
pass_times(time, direction)
#=> [1, 3, 2, 5, 4] (compares with [0,2,1,4,3] from the question)
time = [0,0,1,5]
direction = [0,1,1,0]
pass_times(time, direction)
#=> [3, 1, 2, 6] (compares with [2,0,1,5] from the question)
n = 10
time = n.times.map { rand 13 }
#=> [3, 5, 1, 12, 7, 3, 9, 3, 9, 0]
direction = n.times.map { rand 2 }
#=> [0, 0, 0, 1, 0, 0, 0, 1, 1, 1]
pass_times(time, direction)
#=> [5, 7, 2, 13, 8, 6, 11, 4, 10, 1]
说明
以下是上面第一个示例的步骤。
time = [0,1,1,3,3]
direction = [0,1,0,0,1]
首先,为了提高可读性并避免为了进入和退出而混淆零和一个的问题,我选择使用数组dir
代替direction
:
dir = direction.map { |d| d.zero? ? :ENTER : :EXIT }
#=> [:ENTER, :EXIT, :ENTER, :ENTER, :EXIT]
接下来,创建一个哈希数组,其中包含每个接近转弯人的基本信息。
a = time.each_index.map do |i|
{ person: i, direction: dir[i], arrival_time: time[i] }
end
#=> [{:person=>0, :direction=>:ENTER, :arrival_time=>0},
# {:person=>1, :direction=>:EXIT, :arrival_time=>1},
# {:person=>2, :direction=>:ENTER, :arrival_time=>1},
# {:person=>3, :direction=>:ENTER, :arrival_time=>3},
# {:person=>4, :direction=>:EXIT, :arrival_time=>3}]
现在将这些哈希划分为到达和离开。
b = a.partition { |h| h[:direction] == :ENTER }
#=> [[{:person=>0, :direction=>:ENTER, :arrival_time=>0},
# {:person=>2, :direction=>:ENTER, :arrival_time=>1},
# {:person=>3, :direction=>:ENTER, :arrival_time=>3}],
# [{:person=>1, :direction=>:EXIT, :arrival_time=>1},
# {:person=>4, :direction=>:EXIT, :arrival_time=>3}]]
现在将到达和离开排序到队列中。
enter, exit = b.map { |arr| arr.sort_by { |h| h[:arrival_time] } }
enter
#=> [{:person=>0, :direction=>:ENTER, :arrival_time=>0},
# {:person=>2, :direction=>:ENTER, :arrival_time=>1},
# {:person=>3, :direction=>:ENTER, :arrival_time=>3}]
exit
#=> [{:person=>1, :direction=>:EXIT, :arrival_time=>1},
# {:person=>4, :direction=>:EXIT, :arrival_time=>3}]
我们现在处理两个队列,将结果保存到数组c
中。请注意,time.each_index
只会处理队列中的每个人。我本可以写例如dir.size.times
。
c = time.each_index.with_object([]) do |_i,arr|
last_pass = last_pass_time(arr)
next_enter_time = enter.empty? ? Float::INFINITY :
[enter.first[:arrival_time], last_pass].max
next_exit_time = exit.empty? ? Float::INFINITY :
[exit.first[:arrival_time], last_pass].max
# Note next_enter_time and next_exit_time cannot both be infinite
h = case
when last_pass_time(arr) < [next_enter_time, next_exit_time].min
# if the turnstile was not used in the last second, FIFO with exit
# having priority in ties
g = next_exit_time <= next_enter_time ? exit.shift : enter.shift
add_pass_time(g, g[:arrival_time] + 1)
when next_enter_time < next_exit_time
# next entering person arrives before or when last person passes
# through turnstile and next exiting person has not yet joined the queue.
add_pass_time(enter.shift, last_pass + 1)
when next_exit_time < next_enter_time
# next exiting person arrives before or when last person passes
# through turnstile and next entering person has not yet joined the queue.
add_pass_time(exit.shift, last_pass + 1)
else
# next entering and exiting persons both arrive arrive before or when last
# person passes through turnstile. Person who passes next depends if last
# person passing through the turnstile was entering or exiting.
add_pass_time(arr.last[:direction] == :ENTER ?
enter.shift : exit.shift, last_pass +1)
end
arr << h
end
#=> [{:person=>0, :direction=>:ENTER, :arrival_time=>0, :pass_time=>1},
# {:person=>2, :direction=>:ENTER, :arrival_time=>1, :pass_time=>2},
# {:person=>1, :direction=>:EXIT, :arrival_time=>1, :pass_time=>3},
# {:person=>4, :direction=>:EXIT, :arrival_time=>3, :pass_time=>4},
# {:person=>3, :direction=>:ENTER, :arrival_time=>3, :pass_time=>5}]
这表明人0是第一个在时间0到达的人,因此该人立即经过了旋转栅门,并在时间(:pass_time
)1出现。人2和1都在时间1到达,当人0从旋转门中出来时。第二个人接下来要经过旋转门(在时间2出现),因为该个人像个人0一样正在进入,因此优先于希望退出的个人1。
人员1接下来经过时间3的旋转门,因为没有人在时间2等待。人员4和3都在时间3到达,因为人员1从旋转门中出来。这次人4具有优先权,因为该人正像人1即将离开一样。人4在时间4从旋转栅门出现,此时人3(最后一个经过的人)进入栅门并在时间5出现。
仍然需要创建一个数组arr
,以使arr[i]
返回人物i
的通过时间。
arr = c.sort_by { |h| h[:person] }.map { |h| h[:pass_time] }
#=> [1, 3, 2, 5, 4]
示例2导致以下旋转通道通过顺序。
[{:person=>1, :direction=>:EXIT, :arrival_time=>0, :pass_time=>1},
{:person=>2, :direction=>:EXIT, :arrival_time=>1, :pass_time=>2},
{:person=>0, :direction=>:ENTER, :arrival_time=>0, :pass_time=>3},
{:person=>3, :direction=>:ENTER, :arrival_time=>5, :pass_time=>6}]
示例3导致以下旋转门通过顺序。
[{:person=>0, :direction=>:ENTER, :arrival_time=>0, :pass_time=>1},
{:person=>2, :direction=>:ENTER, :arrival_time=>1, :pass_time=>2},
{:person=>1, :direction=>:EXIT, :arrival_time=>1, :pass_time=>3},
{:person=>4, :direction=>:EXIT, :arrival_time=>3, :pass_time=>4},
{:person=>3, :direction=>:ENTER, :arrival_time=>3, :pass_time=>5}]
示例4导致以下旋转通道通过顺序。
[{:person=>9, :direction=>:EXIT, :arrival_time=>0, :pass_time=>1},
{:person=>2, :direction=>:ENTER, :arrival_time=>1, :pass_time=>2},
{:person=>7, :direction=>:EXIT, :arrival_time=>3, :pass_time=>4},
{:person=>0, :direction=>:ENTER, :arrival_time=>3, :pass_time=>5},
{:person=>5, :direction=>:ENTER, :arrival_time=>3, :pass_time=>6},
{:person=>1, :direction=>:ENTER, :arrival_time=>5, :pass_time=>7},
{:person=>4, :direction=>:ENTER, :arrival_time=>7, :pass_time=>8},
{:person=>8, :direction=>:EXIT, :arrival_time=>9, :pass_time=>10},
{:person=>6, :direction=>:ENTER, :arrival_time=>9, :pass_time=>11},
{:person=>3, :direction=>:EXIT, :arrival_time=>12, :pass_time=>13}]
我将它留给读者来验证这些顺序。
答案 1 :(得分:1)
stackoverflow通常不是代码编写服务。但是,事实证明这是一个有趣的问题。
所以,我为您编写了一些代码。在这里:
list, sepby(id)
+-------------------------+
| id code cost tag |
|-------------------------|
1. | 1 15342 18 1 |
2. | 1 16786 32 1 |
3. | 1 23432 22 1 |
4. | 1 34234 23 1 |
|-------------------------|
5. | 2 15342 12 1 |
6. | 2 15366 12 1 |
7. | 2 22223 12 1 |
|-------------------------|
8. | 4 15342 64 1 |
9. | 4 23453 345 1 |
+-------------------------+
如果您想尝试一下,这里有一个RSpec测试:
def calculate_turnstile_times(time, direction)
current_time = 0
dir = direction.map { |d| d.zero? ? :enter : :exit }
enter_queue, exit_queue = time.each_index.map do |i|
{person: i, time: time[i], direction: dir[i]}
end.partition do |h|
h[:direction] == :enter
end.map do |arr|
arr.sort_by { |h| h[:time] }
end
enterer = enter_queue.shift
exiter = exit_queue.shift
time.each_with_object([]) do |_t, to_return|
person_to_go = nil
enterer ||= enter_queue.shift
exiter ||= exit_queue.shift
current_time = [[enterer,exiter].map{|p|p.try(:[],:time)}.compact.min,current_time].max
enterer_arrived = enterer && enterer[:time] <= current_time
exiter_arrived = exiter && exiter[:time] <= current_time
person_to_go = :enterer if enterer_arrived && !exiter_arrived
person_to_go ||= :exiter if exiter_arrived && !enterer_arrived
person_to_go ||= :exiter if exiter_arrived && to_return.empty?
person_to_go ||= :exiter if exiter_arrived && ((to_return.last.try(:[],:time)||-2) != (current_time-1))
person_to_go ||= :enterer if enterer_arrived && to_return.last.try(:[],:direction) == :enter
person_to_go ||= :exiter if exiter_arrived
case person_to_go
when :exiter
person_to_go = exiter
exiter = nil
when :enterer
person_to_go = enterer
enterer = nil
end
person_to_go[:time] = current_time
to_return << person_to_go
current_time += 1
end.sort_by{|p| p[:person]}.map{|p| p[:time]}
end
哪个给我:
require 'rails_helper'
RSpec.describe "Turnstiles" do
it "using calculate_turnstile_times" do
%i(calculate_turnstile_times).each do |method_sym|
test_cases.each do |test_case|
expect(send(method_sym,test_case[0],test_case[1])).to eq(test_case[2])
end
end
end
end
def test_cases
[
[[10],[1],[10]],
[[0,0,0],[0,0,1],[1,2,0]],
[[0,0,1,5],[0,1,1,0],[2,0,1,5]],
[[0,0],[0,1],[1,0]],
[[0,0],[1,1],[0,1]],
[[0,0],[1,0],[0,1]],
[[4,4],[0,1],[5,4]],
[[0,0,0],[0,1,1],[2,0,1]],
[[0,0,0],[0,0,0],[0,1,2]],
[[0,0,0,0],[0,1,1,1],[3,0,1,2]],
[[0,0,0,5],[0,1,1,1],[2,0,1,5]],
[[0,1,1,3,3],[0,1,0,0,1],[0,2,1,4,3]],
[[0,1,1,3,3],[0,1,1,0,1],[0,1,2,4,3]],
[[0,1,1,6,7],[0,1,1,0,1],[0,1,2,6,7]],
[[0,1,1,3,6],[0,1,1,0,1],[0,1,2,3,6]],
[[0,0,1,5],[0,1,1,0],[2,0,1,5]],
[[0,1,1,3,3],[0,1,0,0,1],[0,2,1,4,3]]
]
end
def calculate_turnstile_times(time, direction)
current_time = 0
dir = direction.map { |d| d.zero? ? :enter : :exit }
enter_queue, exit_queue = time.each_index.map do |i|
{person: i, time: time[i], direction: dir[i]}
end.partition do |h|
h[:direction] == :enter
end.map do |arr|
arr.sort_by { |h| h[:time] }
end
enterer = enter_queue.shift
exiter = exit_queue.shift
time.each_with_object([]) do |_t, to_return|
person_to_go = nil
enterer ||= enter_queue.shift
exiter ||= exit_queue.shift
current_time = [[enterer,exiter].map{|p|p.try(:[],:time)}.compact.min,current_time].max
enterer_arrived = enterer && enterer[:time] <= current_time
exiter_arrived = exiter && exiter[:time] <= current_time
person_to_go = :enterer if enterer_arrived && !exiter_arrived
person_to_go ||= :exiter if exiter_arrived && !enterer_arrived
person_to_go ||= :exiter if exiter_arrived && to_return.empty?
person_to_go ||= :exiter if exiter_arrived && ((to_return.last.try(:[],:time)||-2) != (current_time-1))
person_to_go ||= :enterer if enterer_arrived && to_return.last.try(:[],:direction) == :enter
person_to_go ||= :exiter if exiter_arrived
case person_to_go
when :exiter
person_to_go = exiter
exiter = nil
when :enterer
person_to_go = enterer
enterer = nil
end
person_to_go[:time] = current_time
to_return << person_to_go
current_time += 1
end.sort_by{|p| p[:person]}.map{|p| p[:time]}
end
答案 2 :(得分:1)
这里是一个专注于数据建模以提高可读性和可追溯性的实现。
class Turnstile
DIRECTIONS = { IN: 0, OUT: 1 }
Person = Struct.new(:index, :arrival_time, :direction, :enter_turnstile_time) do
def has_not_exited?
!enter_turnstile_time
end
end
State = Struct.new(:time, :entry_queue, :exit_queue, :person_in_turnstile) do
def build_next
State.new(time + 1, entry_queue.dup, exit_queue.dup, person_in_turnstile)
end
end
def initialize(time, direction)
@people = time.map.with_index { |t, ix| Person.new(ix, t, direction[ix], nil) }
@states = [State.new(-1, Array.new, Array.new, nil)]
end
def process
while @people.any?(&:has_not_exited?)
@states << process_next_state(@states)
end
@people.map(&:enter_turnstile_time)
end
def process_next_state(states)
current_state = states.last.build_next
log_str = "Time: #{current_state.time}"
@people.each do |person|
next unless person.arrival_time == current_state.time
case person.direction
when DIRECTIONS[:IN]
log_str += ", Person #{person.index} queued for entry"
current_state.entry_queue << person
when DIRECTIONS[:OUT]
log_str += ", Person #{person.index} queued for exit"
current_state.exit_queue << person
end
end
if current_state.person_in_turnstile
log_str += ", Person #{current_state.person_in_turnstile.index} exited turnstile"
turnstile_direction_priority = current_state.person_in_turnstile.direction
current_state.person_in_turnstile = nil
end
turnstile_direction_priority ||= DIRECTIONS[:OUT]
prioritized_queues =
case turnstile_direction_priority
when DIRECTIONS[:IN]
[current_state.entry_queue, current_state.exit_queue]
when DIRECTIONS[:OUT]
[current_state.exit_queue, current_state.entry_queue]
end
if current_state.person_in_turnstile = prioritized_queues.first.pop || prioritized_queues.last.pop
current_state.person_in_turnstile.enter_turnstile_time = current_state.time
log_str += ", Person #{current_state.person_in_turnstile.index} entered turnstile"
end
puts log_str
current_state
end
end
结果:
2.5.5 :049 > Turnstile.new([0,1,1,3,3], [0,1,0,0,1]).process
Time: 0, Person 0 queued for entry, Person 0 entered turnstile
Time: 1, Person 1 queued for exit, Person 2 queued for entry, Person 0 exited turnstile, Person 2 entered turnstile
Time: 2, Person 2 exited turnstile, Person 1 entered turnstile
Time: 3, Person 3 queued for entry, Person 4 queued for exit, Person 1 exited turnstile, Person 4 entered turnstile
Time: 4, Person 4 exited turnstile, Person 3 entered turnstile
=> [0, 2, 1, 4, 3]