Counting number of key comparisons in hash table - algorithm

I have a hash table that look like this:
0
1 -> 1101 -> 1222 -> 1343 \\ 3 key comparison
2
3 -> 2973 -> 2588 \\ 2 key comparison
4
How many key comparisons are there?
The given answer is 1 + 2 + 1 = 4 but shouldn't it be 3 + 2 = 5?

The given answer is correct. One possible sequence:
At first, you have an empty list -> then add 1101 -> no comparison needed.
Add 1222 -> go to the 1 list, compared it with 1101 -> add it to the end of the list -> 1 comparison.
Add 1343 -> go to the 1 list, compared it with 1101, 1222 -> add it to the end of the list -> 2 comparisons.
Add 2973 -> no comparison,
Add 2588 -> go to 3 list, compared it with 2973 -> 1 comparison.
So, in total, the number of comparison is 0 + 1 + 2 + 0 + 1
Don't know where do you get the 3 + 2 = 5 from? total number of elements?

Related

Find recursive, hierarchical structures in a sequence

I am looking for an efficient algorithm to find structures that are both recursive and hierarchical from a sequence. I did come across the sequitur algorithm but it only returns hierarchical structures.
Consider the following sequence as an example: abcbcabc
What sequitur returns:
0 -> 1 2 1
1 -> a 2
2 -> b c
Required output:
0 -> 1 1
1 -> a 2
2 -> b c | b c 2

Algorithm help :Given a num, can it finally be 1

Given a number, you can divide it or its contiguous part by 2 , or multiply it or its continuous part by 2. Can the number finally be 1?
For example : 13
3 is a part of 13, first we take 3 * 2 = 6, the num turn to be 16,
second we can operate the whole num 16, 16 / 2 = 8, the num is 8 now,
8/2 = 4, num is 4 now,
4/2 = 2, num is 2 now,
2/2 = 1, num is 1 now.
finally we can say 13 can turn into 1, and the path is 13->16->8->4->2->1, we can use a List to store the path.
Example :27
first we operate the whole num 27, 27 * 2 = 54;
then we take 4 as the part of 54, 4 / 2 = 2 , so the 4 is 2 now, num becomes 52;
operate 52, 52 / 2 = 26, num is 26 now;
operate 26, 26 / 2 = 13, num is 13 now;
we just analyzed 13, so 27 can turn into 1 finally.
How to analyze such problem? What's the main idea of solving such type problem?
Sorry about the confusing description, let's take a more complex example: 316
16 is a contiguous part, let 16 / 2 = 8 , so the num is 38 now,
then take 8 / 2 = 4 , the num is 34,
take 4 / 2 = 2, the num is 32,
now take the whole num 32 / 2 = 16,
16 / 2 = 8, num is 8,
8 / 2 = 4, num is 4,
4 / 2 = 2, num is 2,
finally 2 / 2 = 1.
We say, original num 316 can turn into 1 finally after above conversion.
And the contiguous part means, if the input num is 12345,
then 123, 234,345,12,2345 and so on, they are all contiguous parts.
Any continuous subset of num is fine,including head or tail is NOT necessary.
The question is :
How to judge such a num? And if the num can turn into 1, print the path.
Can you find the shortest way?
I got some hints from interviewer (The interview is over):
Most of numbers are eligible, that means nums which are NOT eligible, these characteristics are obvious.
Brute fore way's time complexity is too high, we should pruning timely. (Slide window + pruning ?)
Here is a simple and unoptimized breadth-first search.
def shortest_digit_path (n):
path_from = {n: None}
queue = [n]
count = 0
while True:
m = queue.pop(0)
count += 1
if 0 == count %1000:
print((count, m))
if m == 1:
break
x = str(m)
for i in range(len(x)):
for j in range(i+1, len(x) + 1):
y = x[0:i]
z = x[i:j]
w = x[j:]
if z[0] == '0':
continue # The continuous section is not a proper number.
# Try half of z
if z[-1] in ['2', '4', '6', '8']:
next_m = int(y + str(int(z)//2) + w)
if next_m not in path_from:
path_from[next_m] = m
queue.append(next_m)
# Try doubling z
next_m = int(y + str(int(z)*2) + w)
if next_m not in path_from:
path_from[next_m] = m
queue.append(next_m)
path = []
while m is not None:
path.append(m)
m = path_from[m]
return list(reversed(path))
After playing around with this for a bit, I came up with the following observations.
If the number ends in 0 or 5, there is no path to having any other digit at the end, and therefore you can't get to 1. (The above function will just run forever.
For anything else we can find a path just dealing with 1-2 digits at a time.
Here are the special cases for observation #2. Our first goal is to get to just 0, 1, and 5 as digits.
0: 0
1: 1
2: 2 -> 1
3: 3 -> 6 -> 12 -> 24 -> 28 -> 56 -> 112 -> 16 -> 8 -> 4 -> 2 -> 1
4: 4 -> 2 -> 1
5: 5
6: 6 -> 12 -> 24 -> 28 -> 56 -> 112 -> 16 -> 8 -> 4 -> 2 -> 1
7: 7 -> 14 -> 28 -> 56 -> 112 -> 16 -> 8 -> 4 -> 2 -> 1
8: 8 -> 4 -> 2 -> 1
9: 9 -> 18 -> 28 -> 56 -> 112 -> 16 -> 8 -> 4 -> 2 -> 1
And now from the start of the number we have to deal with the following cases that reduce the number of digits and get back to our desired form.
10: 10 -> 5
11: 11 -> 22 -> 24 -> 28 -> 56 -> 112 -> 16 -> 8 -> 4 -> 2 -> 1
15: 15 -> 110 -> 220 -> 240 -> 280 -> 560 -> 1120 -> 160 -> 80 -> 40 -> 20 -> 10 -> 5
50: 50 -> 25 -> 15 -> 110 -> 220 -> 240 -> 280 -> 560 -> 1120 -> 160 -> 80 -> 40 -> 20 -> 10 -> 5
51: 51 -> 52 -> 26 -> 16 -> 8 -> 4 -> 2 -> 1
55: 55 -> 510 -> 520 -> 260 -> 160 -> 80 -> 40 -> 20 -> 10 -> 5
With this set of rules we can first normalize the number to a standard form, then we can shorten it one digit at a time. This lets us essentially instantly come up with a path. Almost certainly not the shortest one, but definitely a path.
Writing that function is left as an exercise to the reader.
Now back to the shortest path. The algorithm for the breadth-first search can be made much faster if we start with a breadth-first search from both ends and meet in the middle. For this you'd need to also have a path_to that is initialized with {1: None}, a queue containing elements of the form (m, is_rising) and initialize it with [(1, True), (n: False)]. You'd then have to branch on is_rising and before entering values into path_from/path_to check for whether it is in path_to/path_from. If it is, you've met in the middle. Now work out both halves of the path and join them together.
The approach is tricker. But it will let you find the shortest path in the square root of the number of steps that the current approach takes.

Algorithm to convert the given whole number into the custom binary representation

Problem Statement
I have two different patterns to represent whole numbers using binary digits as follows:
First (the standard decimal to binary conversion):
0 -> 000
1 -> 001
2 -> 010
3 -> 011
4 -> 100
5 -> 101
6 -> 110
7 -> 111
Second:
0 -> 0000
1 -> 0001
2 -> 0010
3 -> 0100
4 -> 1000
5 -> 0011
6 -> 0101
7 -> 1001
8 -> 0110
9 -> 1010
10 -> 1100
11 -> 0111
12 -> 1011
13 -> 1101
14 -> 1110
15 -> 1111
Explaination: First, take flip one bit each, highest priority to the least significant bit. Then in second iteration, keep first bit flipped and then flip the rest bits in order as before. In the third iteration, the least significant bit is unset, and then second significant bit set and then pattern continued.
But now, let's say I want to combine the first and second pattern into one single pattern where some parts are defined by the first patten while the others are defined by the second pattern. For example:
(First pattern, most 3 significant digits)(Second pattern, least 3 significant digits)
0 -> 000000
1 -> 000001
2 -> 000010
3 -> 000100
4 -> 000011
5 -> 000101
6 -> 000110
7 -> 000111
8 -> 001000
9 -> 001001
10 -> 001010
11 -> 001100
12 -> 001011
13 -> 001101
14 -> 001110
15 -> 001111
16 -> 010000
17 -> 010001
...
010111
011000
...
The goal:
Input which tells which group of bits have which of these 2 patterns (no. of bits can be as long as we want and the pattern repetition can keep shifting between groups of bits in this set infinitely); a whole number.
Output which converts the whole number to the corresponding binary representation based on the input pattern. E.g. 12 -> 001011
Where I am stuck:
The binary conversion is straight forward. The second pattern, I'm not really sure how to make. Even if I can convert the whole number to the second pattern binary representation, how could I combine the both types to find the correct binary equivalent for my input number? Since there is a pattern here, I'm sure there must be an elegant mathematical representation for this!
What is my use case?
I'm writing a code for an application where I want to create a search pattern similar to this binary representation, based on a similar type of input.
Assuming you have calculated first pattern and second pattern for a number.
Convert them back to "normal" decimal and then left shift firstNumber by 3 firstPatterNo << 3 and then do OR of 2 numbers firstPatterNo | secondPatterNo.
firstPatterNo = 3 // 011 (normal decimal representations)
secondPatternNo = 4 // 100 (normal decimal representations)
combined = (firstPatterNo << 3) | secondPatternNo
// Convert combined to normal binary representation
BTW whats the logic behind second pattern ? I am not able to figure out.

Algorithm to calculate the price volatility of a commodity

I am trying to design an algorithm to calculate how volatile the price fluctuations of a commodity are.
The way I would like this to work is that if the price of a commodity constantly goes up and down, it should have a higher score than if the price of the commodity gradually increases and then falls in price rapidly.
Here is an example of what I mean:
Commodity A: 1 -> 2 -> 3 -> 2 -> 1 -> 3 -> 4 -> 2 -> 1
Commodity B: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 2
Commodity C: 1 -> 2 -> 3 -> 4 -> 5 -> 4 -> 3 -> 2-> 1
Commodity A has a 'wave' like pattern in that its price goes up and falls down on a regular basis.
Commodity B has a 'cliff' like pattern in that the price goes up gradually and then falls steeply.
Commodity C has a 'hill' like pattern in that the price rises gradually and then falls gradually.
A should receive the highest ranking, followed by C, followed by B. The more of a wave pattern the price of the commodity follows, the higher a ranking it should have.
Does have any suggestions for an algorithm that could do this?
Thanks!
My Approach looks something like this.
For my algorithm, I am considering the above example.
A: 1 -> 2 -> 3 -> 2 -> 1 -> 3 -> 4 -> 2 -> 1
B: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 2
C: 1 -> 2 -> 3 -> 4 -> 5 -> 4 -> 3 -> 2-> 1
Now I will squash these list, by squash i mean taking the start value and end value of an increasing or decreasing sequence.
So, after squashing the list will look something like this.
A: 1 -> 3 -> 1 -> 4 -> 1
B: 1 -> 8 -> 2
C: 1 -> 5 -> 1
Now once this it done, I take the difference between i and i+1 element and then take the average and based on the average, I give them the rank.
So the difference between i and i+1 element will look something like this
2 2 3 3
A: 1 --> 3 --> 1 --> 4 --> 1
7 6
B: 1 --> 8 --> 2
4 4
C: 1 --> 5 --> 1
Now let's sum this difference and take the average.
A: (2+2+3+3)/4 = 2.5
B: (7+6)/2 = 6.5
C: (4+4)/2 = 4
Now we can assign ranks based on this average value where
A < C < B
Hope this helps!

Finding the root value of a binary tree?

I have an array which stores the relations of values, which makes several trees something like:
So, in this case, my array would be (root, linked to)
(8,3)
(8,10)
(3,1)
(3,6)
(6,4)
(6,7)
(10,14)
(14,13)
And i'd like to set all the root values in the array to the main root in the tree (in all trees):
(8,3)
(8,1)
(8,6)
(8,4)
(8,7)
(8,10)
(8,14)
(8,13)
What algorithm should i investigate?
1) Make a list of all the unique first elements of the tuples.
2) Remove any that also appear as the second element of a tuple.
3) You'll be left with the root (8 here). Replace the first elements of all tuples with this value.
EDIT:
A more complicated approach that will work with multiple trees would be as follows.
First, convert to a parent lookup table:
1 -> 3
3 -> 8
4 -> 6
6 -> 3
7 -> 6
10 -> 8
13 -> 14
14 -> 10
Next, run "find parent with path compression" on each element:
1)
1 -> 3 -> 8
gives
1 -> 8
3 -> 8
4 -> 6
...
3)
3 -> 8
4)
4 -> 6 -> 3 -> 8
gives
1 -> 8
3 -> 8
4 -> 8
6 -> 8
7 -> 6
...
6)
6 -> 8 (already done)
7)
7 -> 6 -> 8
etc.
Result:
1 -> 8
3 -> 8
4 -> 8
6 -> 8
7 -> 8
...
Then convert this back to the tuple list:
(8,1)(8,3)(8,4)...
The find parent with path compression algorithm is as find_set would be for disjoint set forests, e.g.
int find_set(int x) const
{
Element& element = get_element(x);
int& parent = element.m_parent;
if(parent != x)
{
parent = find_set(parent);
}
return parent;
}
The key point is that path compression helps you avoid a lot of work. In the above, for example, when you do the lookup for 4, you store 6 -> 8, which makes later lookups referencing 6 faster.
So assume you have a list of tuples representing the points:
def find_root(ls):
child, parent, root = [], [], []
for node in ls:
parent.append(node[0])
child.append(node[1])
for dis in parent:
if (!child.count(dis)):
root.append(dis)
if len(root) > 1 : return -1 # failure, the tree is not formed well
for nodeIndex in xrange(len(ls)):
ls[nodeIndex] = (root[0], ls[nodeIndex][1])
return ls

Resources