how to find the empty spot in a row? - combinatorics

I am suppose to put a group of people (given at run-time) in to a 2 dimensional array of spot, group together in a row randomly(find out all possible positions and randomly pick one)
To start of, I wanna try in an array first
if I have an array of spots of size 10 like below
spots[occupied,open,open,occupied,occupied,occupied,open,open,open,open]
to put 2 people
Is there a particular algorithm to do this kind of problem?
Thanks for any help!

in python:
seats =["occupied","open","open","occupied","occupied","occupied","open","open","open","open"]
def empty(seats,index,count):
if count == 0:
return True
else:
return (seats[index] == "open") & empty(seats,index+1,count-1)
def findEmpty(seats,count):
result = []
for (i=0;i<seats.size-count+1,i++)
if empty(seats,i,count):
result.append(<list of consecutive numbers from i to i+count>)
return result
print findEmpty(seats,2)
>>>[[1, 2], [6, 7], [7, 8], [8, 9]]
here's another approach, its a little more efficient:
seats = ["occupied","open","open","occupied","occupied","occupied","open","open","open","open"]
//counts the number of consecutive free seats starting at position index
def countEmpty(seats,index):
if index >= len(seats) or seats[index] == "occupied":
return 0
return 1 + countEmpty(seats,index+1)
def findEmpty(seats,count):
result = []
i = 0
while i < len(seats)-count+1:
c = countEmpty(seats,i)
if c>=count:
for (j=i;j<i+c-count+1;j++):
result.append(<list of consecutive numbers from j to j+count>)
i += 1 + c
return result
print findEmpty(seats,2)
>>>[[1, 2], [6, 7], [7, 8], [8, 9]]
and finally, if you did choose to use python you could do it in one line:
seats =["occupied","open","open","occupied","occupied","occupied","open","open","open","open"]
count = 2
print [range(i,i+count) for i in range(len(seats)-count+1) if all([seats[j]=="open" for j in range(i,i+count)]) ]
>>> [[1, 2], [6, 7], [7, 8], [8, 9]]

Pseudo code:
//Create 2 lists of blocks, both empty: tmp and final
List tmp=new List;
List final=new List;
//Cycle the seats
for (int i=0;i<length(seats);i++) {
//If the seat is occupied, start over
if (seats[i]==occupied) tmp.empty();
else {
//Cycle existing block candidates, add free seat
foreach (ref block in tmp) {
block.add(seats[i])
if (length(block)>=people_count) {
//HEUREKA, got a fitting block: Move it to the final list
tmp.remove(block)
final.add(block)
}
}
//Start a new block with this seat
tmp.add(new block(seats[i]));
//Read below for this edge case
}
}
final now has the blocks.
If you allow the edge case of people_num being 1, you have to check for a complete block at the position indicated in the pseudocode

I shall use Mathematica code but I believe you can follow the logic.
Starting with:
dat = spots[occupied, open, open, occupied, occupied, occupied, open, open, open, open];
fill = {"Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot"};
First find a random permutation of the list fill (it is easy to find an algorithm on StackOverflow):
randomfill = RandomSample # fill
{"Delta", "Echo", "Alpha", "Bravo", "Charlie", "Foxtrot"}
Then "map" a function onto each element of the spots list, and if the element is open return the next value from the randomfill list, else return the element unchanged:
i = 1;
If[# === open, randomfill[[i++]], #] & /# dat
spots[occupied, "Delta", "Echo", occupied, occupied, occupied, "Alpha", "Bravo", "Charlie", "Foxtrot"]

Related

How to get duplicates in sorted list with O(n) python

Hear i have a list, and i have to get duplicates from it. So i can use solution like this:
arr = [1, 1, 2, 3, 4, 4, 5]
def get_duplicates(arr):
duplicates = []
for index in range(len(arr)-1):
if arr[index] == arr[index+1]:
duplicates.append(arr[index])
return duplicates
print(*duplicates)
Ok, what if i have three or more duplicates in my list? I did something like that:
arr = [1, 1, 1, 2, 3, 4, 4, 4, 4, 5]
def get_duplicates(arr):
duplicates = []
for index in range(len(arr)-1):
if arr[index] == arr[index+1]:
duplicates.append(arr[index])
return duplicates
print(*set(duplicates))
Is that both my code works with O(n) or not? I just dont know what is speed of set() function in python, but i think that first for loop takes O(n),
if set() takes O(n), it doesnt matter, because finally i will have O(2n) = O(n) in this case.
Do i solve that task correctly, or my code is not effective? Smart people, help me please))
If u know how to do it in wright direction, explain me please.
Here is a version that is clearly O(n):
def get_duplicates(arr):
last_duplicate = None
duplicates = []
for i,v in enumerate(arr[1:]):
if v==arr[i-1] and v!=last_duplicate:
duplicates.append(v)
last_duplicate = v
return duplicates
Note that this assumes, as your original code does, that duplicates will be adjacent to one another. It also assumes that the first duplicate is not None.

Foobar Lucky Triple

I am trying to solve the following problem:
Write a function solution(l) that takes a list of positive integers l and counts the number of "lucky triples" of (li, lj, lk) where the list indices meet the requirement i < j < k. The length of l is between 2 and 2000 inclusive. A "lucky triple" is a tuple (x, y, z) where x divides y and y divides z, such as (1, 2, 4). The elements of l are between 1 and 999999 inclusive. The solution fits within a signed 32-bit integer. Some of the lists are purposely generated without any access codes to throw off spies, so if no triples are found, return 0.
For example, [1, 2, 3, 4, 5, 6] has the triples: [1, 2, 4], [1, 2, 6], [1, 3, 6], making the solution 3 total.
My solution only passes the first two tests; I am trying to understand what it is wrong with my approach rather then the actual solution. Below is my function for reference:
def my_solution(l):
from itertools import combinations
if 2<len(l)<=2000:
l = list(combinations(l, 3))
l= [value for value in l if value[1]%value[0]==0 and value[2]%value[1]==0]
#l= [value for value in l if (value[1]/value[0]).is_integer() and (value[2]/value[1]).is_integer()]
if len(l)<0xffffffff:
l= len(l)
return l
else:
return 0
If you do nested iteration of the full list and remaining list, then compare the two items to check if they are divisors... the result counts as the beginning and middle numbers of a 'triple',
then on the second round it will calculate the third... All you need to do is track which ones pass the divisor test along the way.
For Example
def my_solution(l):
row1, row2 = [[0] * len(l) for i in range(2)] # Tracks which indices pass modulus
for i1, first in enumerate(l):
for i2 in range(i1+1, len(l)): # iterate the remaining portion of the list
middle = l[i2]
if not middle % first: # check for matches
row1[i2] += 1 # increment the index in the tracker lists..
row2[i1] += 1 # for each matching pair
result = sum([row1[i] * row2[i] for i in range(len(l))])
# the final answer will be the sum of the products for each pair of values.
return result

while loop with dynamic list in python using a dictionnary

I have a dictionary with lots of data from a CSV file where the key is the row number and the value is a list that contains the column data.
What I want to do is to check from a data of each line (key) and from column 2, I take its data from column 4 and then look for this data in column 2 of another line (key) and take its data in column 4 and continue until it finds the last value of column 4 in column 2.
My code is this:
dict_FH_coord = self.dict_FH()
site_SI='some_site'
list_test = [site_SI]
while len(list_test) > 0:
for ele in list_test:
for cle, val in dict_FH_coord.items():
list_test = []
if val[2] == ele:
list_test.append(val[4])
list_def.append(val)
print(val)
But this code does not work because it stops at the first iteration and it finds that the elements linked to the starting site_SI only
Is there a way to do successive iterations with the list list_test which becomes dynamic to solve my problem?
If you want to modify list 'on air' you sohuld do something like
a = [1, 2, 3]
a[:] = [1, 2]
In your case the only way you may use this inside the loop (avoiding infinite list size increasement):
if val[2] == ele:
list_test[:] = list_test[1:]+[val[4]]
list_def.append(val)
else:
list_test[:] = list_test[1:]
But it wont work as intended because previous iteration ends at index 1 (for ele in list_test:), and list_test would never change in size.
Both this cases can not be merged with each other.
I suggest you to use Queue, but be careful to avoid infinite links looping inside your data:
from queue import Queue
dict_FH_coord = {
1: [0, 1, 'some_site', 3, 'some_site_2'],
2: [0, 1, 'some_site_2', 3, 'some_site_3'],
3: [0, 1, 'some_site_2', 3, 'some_site_4'],
4: [0, 1, 'some_site_3', 3, 'some_site_5'],
}
site_SI = 'some_site'
unvisited = Queue()
unvisited.put(site_SI)
list_def = list()
while not unvisited.empty():
ele = unvisited.get()
for cle, val in dict_FH_coord.items():
if val[2] == ele:
unvisited.put(val[4])
list_def.append(val)
print(val)

Fastest way to find all the indexes of maximum value in a list - Python

I am having list which as follows
input_list= [2, 3, 5, 2, 5, 1, 5]
I want to get all the indexes of maximum value. Need efficient solution. The output will be as follows.
output = [2,4,6] (The above list 5 is maximum value in a list)
I have tried by using below code
m = max(input_list)
output = [i for i, j in enumerate(a) if j == m]
I need to find any other optimum solution.
from collections import defaultdict
dic=defaultdict(list)
input_list=[]
for i in range(len(input_list)):
dic[input_list[i]]+=[i]
max_value = max(input_list)
Sol = dic[max_value]
You can use numpy (numpy arrays are very fast):
import numpy as np
input_list= np.array([2, 3, 5, 2, 5, 1, 5])
i, = np.where(input_list == np.max(input_list))
print(i)
Output:
[2 4 6]
Here's the approach which is described in comments. Even if you use some library, fundamentally you need to traverse at least once to solve this problem (considering input list is unsorted). So even lower bound for the algorithm would be Omega(size_of_list). If list is sorted we can leverage binary_search to solve the problem.
def max_indexes(l):
try:
assert l != []
max_element = l[0]
indexes = [0]
for index, element in enumerate(l[1:]):
if element > max_element:
max_element = element
indexes = [index + 1]
elif element == max_element:
indexes.append(index + 1)
return indexes
except AssertionError:
print ('input_list in empty')
Use a for loop for O(n) and iterating just once over the list resolution:
from itertools import islice
input_list= [2, 3, 5, 2, 5, 1, 5]
def max_indexes(l):
max_item = input_list[0]
indexes = [0]
for i, item in enumerate(islice(l, 1, None), 1):
if item < max_item:
continue
elif item > max_item:
max_item = item
indexes = [i]
elif item == max_item:
indexes.append(i)
return indexes
Here you have the live example
Think of it in this way, unless you iterate through the whole list once, which is O(n), n being the length of the list, you won't be able to compare the maximum with all values in the list, so the best you can do is O(n), which you already seems to be doing in your example.
So I am not sure you can do it faster than O(n) with the list approach.

I want to check the occurrence of a particular item in all other items (even be it a sub string)

I want to check the occurrence of a particular item in all other items (even be it a sub string) .
n_a = ['28', '4663', '66', '66']
occ_arr = [[0,0]]*len(n_a)
for i in range(len(n_a)):
count=0
for j in range(len(n_a)):
if n_a[i] in n_a[j]:
count+=1
occ_arr[i][0] = n_a[i]
occ_arr[i][1] = count
print(occ_arr)
This is my piece of code.
The result is
[['66', 3], ['66', 3], ['66', 3], ['66', 3]]
but the desired output is
[['28', 1], ['4663', 1], ['66', 3], ['66',3]].
Please help me to figure out what is wrong with the code.
All your sub-lists in the occ_arr list are referencing the same list because you're using the * operator to copy the reference of the same list, so any change in one sub-list is reflected on all the other sub-lists. You should instead use list comprehension to create a distinct sub-lists.
Change:
occ_arr = [[0,0]]*len(n_a)
to:
occ_arr = [[0,0] for _ in range(len(n_a))]
Changing:
occ_arr = [[0,0]]*len(n_a)
To:
occ_arr = []
for i in range(len(n_a)):
occ_arr.append([0,0])
Will fix the bug occuring with the program. If you want to make this a one line statement, use the following list comprehension:
occ_arr = [[0,0] for _ in n_a]
#Add the list [0,0] for each item in the list n_a
All together, the program turns into (using the one line solution):
n_a = ['28', '4663', '66', '66']
occ_arr = [[0,0] for _ in n_a]
for i in range(len(n_a)):
count=0
for j in range(len(n_a)):
if n_a[i] in n_a[j]:
count+=1
occ_arr[i][0] = n_a[i]
occ_arr[i][1] = count
print(occ_arr)
print(occ_arr)
Explanation of bug
The reason why the bug occurs is because of the way lists are stored. Rather than being stored as literal data (like ints, floats, etc...), they are stored as objects, with memory addresses and ids. The line:
cc_arr = [[0,0]]*len(n_a)
Creates a list with it's own unique id and then copies it (shallowly [copying just the memory address, rather than the data]) four times. This can be shown through the following example:
>>> x = [[0,0]] * 4
>>> for item in x:
... print(id(x))
4500701640
4500701640
4500701640
4500701640
Note that the output will be different for you.
Hence, when you change one list, you change the underlying representation of the object, which changes the other shallow copies, which is why your program was outputting [['66', 3], ['66', 3], ['66', 3], ['66', 3]] rather than [['28', 1], ['4663', 1], ['66', 3], ['66',3]]

Resources