The function accepts two arguments: a word list and the string s. First, it determines if s or words are empty and returns -1 if either is. Then, a sliding window technique is used to assess whether the substring in s that begins at index I and has a length of word len * word count can be formed by concatenating the words in words[1]. The frequency of each word in words is kept in an initialized dictionary word dict. If the function is unable to locate the substring’s beginning location, it returns -1. O(n*m) is the temporal complexity of the output from the screenshot, where n is the length of the string s and m is the total number of words in the list.

Question two

The top five horses might be selected via an elimination tournament format. The 25 horses will be divided into five groups of five to begin. Then, set each team against one another and record which horses win each race. Run the five winning horses from the previous step race a second time and record the top three, then run the three winning horses from the previous step race a second time and record the top two, and finally run the two winning horses from the previous step race a second time to determine the overall winner[2]. When n is the total number of horses, this method’s temporal complexity is O(n log n). Due to the fact that each race takes O(n) seconds and the number of horses is decreased by a factor of two in each round of the tournament, this is the case (for example, 25 horses, then 12 horses, then 6 horses, etc.).

In addition to assuring the five quickest horses, this method is straightforward to implement and comprehend. Among the algorithm’s potential flaws are the need for a large number of races and the removal of some horses before their full skills are revealed. One option to improve this strategy would be to utilize a machine learning algorithm to predict the outcomes of races. This would spare us the headache of racing sluggish horses. Utilize a genetic algorithm to determine the optimal mix of horses requiring the fewest races.


The python pseudo code for the implementation is shown in the screen shot below.

def find_fastest_5_horses(horses):

groups = divide_horses_into_groups(horses)

round1_winners = []

for group in groups:


round2_winners = race(round1_winners)

round3_winners = race(round2_winners[:3])

round4_winners = race(round3_winners)

fastest_5_horses = race(round4_winners)

return fastest_5_horses



Using a loop, as shown in the code below, we can simulate the races and keep track of the top five horses.

import random


# Initialize list of horses and their times

horses = [i for i in range(1, 26)]

times = [random.random() for _ in range(25)]

fastest_5 = []


# Run races until the fastest 5 horses are found

while len(fastest_5) < 5:

# Shuffle the horses for each race


race_horses = horses[:5]

race_times = [times[horse-1] for horse in race_horses]

# Determine the winner(s) of the race

min_time = min(race_times)

winners = [race_horses[i] for i in range(5) if race_times[i] == min_time]

# Add the winner(s) to the list of fastest horses

for horse in winners:

if horse not in fastest_5:



# Print the fastest 5 horses










The algorithm will choose five horses at random from the pool of twenty-five contenders. The fastest horse will be reinstated to the top five list once there are five horses in the running. Due to the random selection of horses and allocation of time for each horse, the aforementioned strategy will often but not always be effective.

Question three

Hash tables, often known as dictionaries or associative arrays, typically hold user-defined structures with predefined lengths. Each hash table item may have a signature, which is made up of two unsigned int types, and the hash table can be indexed by strings[3]. To implement the hash table in Python, a class that uses a list as the underlying data structure may be created. To accommodate the items, the list might begin with a preset size of, say, 1000. A list index may be produced by translating a string to a hash function. The hash function should be rapid, easy to use, and uniformly distributed. The built-in hash () function in Python offers a simple hash function that can be used.





delete(self, string):


This function takes a string as input, uses the hash function to map the string to an index in the list, and removes the entry at that index.


add(self, string, signature):


This function takes a string and a signature as input, uses the hash function to map the string to an index in the list, and stores the signature at that index. If the index is already occupied, the function can use open addressing or chaining to resolve collisions.


check(self, string):


The check function takes a string as input, uses the hash function to map the string to an index in the list, and returns the entry at that index if it exists, or None if it does not.



change(self, string, signature):


The change function takes a string and a signature as input, maps the string to an index in the list using the hash function, and replaces the item at that position with the new signature.



If the load factor exceeds a specific threshold, the underlying list may be dynamically resized to optimize the hash table. This can be done in Python as shown below to help prevent collisions and improve the performance of the hash table:







[1] J. Unpingco, Python Programming for Data Analysis. Springer, 2021.

[2] J. Unpingco, ‘Basic Programming’, in Python Programming for Data Analysis, Springer, 2021, pp. 1–65.

[3] B. Brock, A. Buluç, and K. Yelick, ‘BCL: A cross-platform distributed data structures library’, in Proceedings of the 48th International Conference on Parallel Processing, 2019, pp. 1–10.