I know how Merge Sort works, but How Merge Sort Code Works? - algorithm

You can read this on Wikipedia:
function merge_sort(list m)
// Base case. A list of zero or one elements is sorted, by definition.
if length(m) <= 1
return m
// Recursive case. First, *divide* the list into equal-sized sublists.
var list left, right
var integer middle = length(m) / 2
for each x in m before middle
add x to left
for each x in m after or equal middle
add x to right
// Recursively sort both sublists
left = merge_sort(left)
right = merge_sort(right)
// Then merge the now-sorted sublists.
return merge(left, right)
On line 1 there's a list of numbers, let's say 9 6 3 7 5 1 8 2
They say that merge_sort divides the list on 2 and 2 again and again until each list has only 1 integer left, like this one:
9 6 3 7 5 1 8 2 -->
9 6 3 7 - 5 1 8 2 -->
9 6 - 3 7 - 5 1 - 8 2 -->
9 - 6 - 3 - 7 - 5 - 1 - 8 - 2
And then the numbers are put together like this:
6 9 - 3 7 - 1 5 - 2 8 -->
3 6 7 9 - 1 2 5 8 -->
1 2 3 5 6 7 8 9 -->
But I don't see where in the code the list of integers are divided on 2 again and again until each has only 1 integer left?
var list left, right
var integer middle = length(m) / 2
for each x in m before middle
add x to left
for each x in m after or equal middle
add x to right
As I understand, on the code above, the list of numbers is divided to two different lists:
9 6 3 7 and 5 1 8 2
What then happens on the code below?
left = merge_sort(left)
right = merge_sort(right)
Can someone explain me how the merge_sort code above exactly works step by step?

But I don't see where in the code the list of integers are divided on 2 again and again until each has only 1 integer left?
var list left, right
var integer middle = length(m) / 2 --------statement-1
for each x in m before middle --------statement-2
add x to left
for each x in m after or equal middle --------statement-3
add x to right
At the statement-1 you divide the array into two parts and add them to the left and right sub-array. In the statement-2, you are adding all the element before middle, which is your middle element of the array. Similarly statement-3, you are adding rest of the element in right sub-array. So essentially, you keep on dividing the array in two parts until their size is 1 or 0.
if length(m) <= 1
return m
In the start you have above conditional check, which return the method call if the size of the array is less then or equal to one.
What then happens on the code below?
left = merge_sort(left)
right = merge_sort(right)
This is a recursive call to sort (divide the array until size is one) the each sub array. Which is created in the above pseudo-code. You sort left and right sub-array separately and then join them into a single array.
return merge(left, right)
Here both left and right sub-array are passed to a merge function. These both array are sorted array. The task of the merge function is merge these sub-array into a single sorted array.

The pseudo code is missing some details. There was debate on the talk page about removing it or fixing it. Note it's supposed to be working with a list, not an array, which is why elements can only be appended one at a time. The list is not really split into 2 parts; instead two new initially empty lists left and right are created, then (middle = length/2) elements are moved from list to left, then (length - middle) elements are moved from list to right. This cleaned up example with C++ comments may make more sense, but it's still an inefficient way to sort a list. A bottom up merge sort using an array of pointers is much more efficient. I can add example code here if anyone is interested.
var list left, right
var integer middle = length(m) / 2
var integer count
for (count = 0; count < middle; count += 1)
get x from front of list // x = *list.front()
remove first element from list // list.pop_front()
add x to left // left.push_back(x)
for (count = middle; count < length; count += 1)
get x from front of list // x = *list.front()
remove first element from list // list.pop_front()
add x to right // right.push_back(x)
In that same wiki article, there are two C / C++ like code examples, which should be easier to understand. The examples are simplified and copy data back to the original array after each merge step, which could be avoided with more optimized code.
http://en.wikipedia.org/wiki/Merge_sort#Top-down_implementation
http://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation
The sequence is different for top down merge sort, it's depth first, left first:
9 6 3 7 5 1 8 2
9 6 3 7|5 1 8 2
9 6|3 7
9|6
6 9
3|7
3 7
3 6 7 9
5 1|8 2
5|1
1 5
8|2
2 8
1 2 5 8
1 2 3 5 6 7 8 9
Bottom up merge sort skips the recursion and just starts off assuming a run size of 1, and merges width first, left to right:
9 6 3 7 5 1 8 2
9|6|3|7|5|1|8|2 run size = 1
6 9|3 7|1 5|2 8 run size = 2
3 6 7 9|1 2 5 8 run size = 4
1 2 3 5 6 7 8 9 done
Another example of bottom up merge sort algorithm:
http://www.mathcs.emory.edu/~cheung/Courses/171/Syllabus/7-Sort/merge-sort5.html

Related

what does 'work through an algorithm by hand' mean?

I'm doing this assignment and I don't understand the wording. Do you think it means to write in pseudocode or write a paragraph? Does anyone have any ideas?
It means to describe the algorithm with words and draw the array values in each step. Here is an example: https://www.geeksforgeeks.org/bubble-sort/
Before executing the algorithm, the array is:
4 2 12 1 7 9 9
After executing the algorithm, the array is:
1 2 4 7 9 9 12
During the execution of the algorithm, the array slowly changes from what is was before, to what it will be after. Your assignment requires you to show all the intermediate steps.
For instance, the very first step of execution will be "compare element at position 0 with position 1; if element at position 1 is lower, then swap the two elements". The first two elements are 4 and 2; 2 is lower; hence they should be swapped; the resulting array is:
2 4 12 1 7 9 9
Then the second step will be "compare elements at position 1 and 2", which are 4 and 12; etc.

Assignment regarding, dynamic programming. Making my code more efficient?

I've got an assignment regarding dynamic programming.
I'm to design an efficient algorithm that does the following:
There is a path, covered in spots. The user can move forward to the end of the path using a series of push buttons. There are 3 buttons. One moves you forward 2 spots, one moves you forward 3 spots, one moves you forward 5 spots. The spots on the path are either black or white, and you cannot land on a black spot. The algorithm finds the smallest number of button pushes needed to reach the end (past the last spot, can overshoot it).
The user inputs are for "n", the number of spots. And fill the array with n amount of B or W (Black or white). The first spot must be white. Heres what I have so far (Its only meant to be pseudo):
int x = 0
int totalsteps = 0
n = user input
int countAtIndex[n-1] <- Set all values to -1 // I'll do the nitty gritty stuff like this after
int spots[n-1] = user input
pressButton(totalSteps, x) {
if(countAtIndex[x] != -1 AND totalsteps >= countAtIndex[x]) {
FAILED } //Test to see if the value has already been modified (not -1 or not better)
else
if (spots[x] = "B") {
countAtIndex[x] = -2 // Indicator of invalid spot
FAILED }
else if (x >= n-5) { // Reached within 5 of the end, press 5 so take a step and win
GIVE VALUE OF TOTALSTEPS + 1 A SUCCESSFUL SHORTEST OUTPUT
FINISH }
else
countAtIndex[x] = totalsteps
pressButton(totalsteps + 1, x+5) //take 5 steps
pressButton(totalsteps + 1, x+3) //take 3 steps
pressButton(totalsteps + 1, x+2) //take 2 steps
}
I appreciate this may look quite bad but I hope it comes across okay, I just want to make sure the theory is sound before I write it out better. I'm wondering if this is not the most efficient way of doing this problem. In addition to this, where there are capitals, I'm unsure on how to "Fail" the program, or how to return the "Successful" value.
Any help would be greatly appreciated.
I should add incase its unclear, I'm using countAtIndex[] to store the number of moves to get to that index in the path. I.e at position 3 (countAtIndex[2]) could have a value 1, meaning its taken 1 move to get there.
I'm converting my comment into an answer since this will be too long for a comment.
There are always two ways to solve a dynamic programming problem: top-down with memoization, or bottom-up by systematically filling an output array. My intuition says that the implementation of the bottom-up approach will be simpler. And my intent with this answer is to provide an example of that approach. I'll leave it as an exercise for the reader to write the formal algorithm, and then implement the algorithm.
So, as an example, let's say that the first 11 elements of the input array are:
index: 0 1 2 3 4 5 6 7 8 9 10 ...
spot: W B W B W W W B B W B ...
To solve the problem, we create an output array (aka the DP table), to hold the information we know about the problem. Initially all values in the output array are set to infinity, except for the first element which is set to 0. So the output array looks like this:
index: 0 1 2 3 4 5 6 7 8 9 10 ...
spot: W B W B W W W B B W B
output: 0 - x - x x x - - x -
where - is a black space (not allowed), and x is being used as the symbol for infinity (a spot that's either unreachable, or hasn't been reached yet).
Then we iterate from the beginning of the table, updating entries as we go.
From index 0, we can reach 2 and 5 with one move. We can't move to 3 because that spot is black. So the updated output array looks like this:
index: 0 1 2 3 4 5 6 7 8 9 10 ...
spot: W B W B W W W B B W B
output: 0 - 1 - x 1 x - - x -
Next, we skip index 1 because the spot is black. So we move on to index 2. From 2, we can reach 4,5, and 7. Index 4 hasn't been reached yet, but now can be reached in two moves. The jump from 2 to 5 would reach 5 in two moves. But 5 can already be reached in one move, so we won't change it (this is where the recurrence relation comes in). We can't move to 7 because it's black. So after processing index 2, the output array looks like this:
index: 0 1 2 3 4 5 6 7 8 9 10 ...
spot: W B W B W W W B B W B
output: 0 - 1 - 2 1 x - - x -
After skipping index 3 (black) and processing index 4 (can reach 6 and 9), we have:
index: 0 1 2 3 4 5 6 7 8 9 10 ...
spot: W B W B W W W B B W B
output: 0 - 1 - 2 1 3 - - 3 -
Processing index 5 won't change anything because 7,8,10 are all black. Index 6 doesn't change anything because 8 is black, 9 can already be reached in three moves, and we aren't showing index 11. Indexes 7 and 8 are skipped because they're black. And all jumps from 9 are into parts of the array that aren't shown.
So if the goal was to reach index 11, the number of moves would be 4, and the possible paths would be 2,4,6,11 or 2,4,9,11. Or if the array continued, we would simply keep iterating through the array, and then check the last five elements of the array to see which has the smallest number of moves.

Efficient algorithm to find kth largest numbers from N lists by picking one number each time from N lists

There are given N lists of numbers. Every time one number will be picked from each list and all the picked numbers will be sorted. The k th largest of sorted numbers will be added to a set.
Finally the size of the set will be reported.
For Example
3 3
3 2 5 3
3 8 1 6
3 7 4 9
First integer is the no of lists N(From next line there are N lists. In this case it is 3, so next three lines have list values). Second integer is the k value.And first entry of the next N lines are the list size.
List values are list1 -> (2,5,3) , list2 ->(8,1,6), list3 ->(7,4,9)
Any number can be picked from the list. For example (2,8,7),(2,8,4),(2,8,9),(2,1,7),(2,1,4),(2,1,9)..etc are all valid combinations. From this combinations kth largest will be selected from each combination.
In this case the following numbers have the chance to be the 3 rd largest (since k=3)
(4,5,6,7,8,9)
The total count must be reported. So the output is 6
One way:
I am trying to find the permutation of all the list values, sort it and take the k th largest every time. In this way the complexity is high. For example 4 lists of sizes (10,12,15,20)= (10 *12 * 15 * 20) list values. So it will not fit in memory.
Is there any other efficient algorithm for this problem?
This is an interesting question , took a while to figure it out .
Make 2 max-heaps , h1 and h2 .
put 1st element of all lists at each time in h1 , and 1 element (maximum) from h1 to h2 and when size of h2 >=K ,
pop 1 element (maximum) from h2 and add it into your set .
Run on your case :
1) h1 = empty h2 = empty set=empty
2) h1 = 2 8 7 h2 = empty set=empty
3) h1 = 2 7 5 1 4 h2 = 8 set=empty
4) h1 = 2 5 1 4 3 6 9 h2 = 8 7 set=empty
5) h1 = 2 5 1 4 3 6 h2 = 8 7 9 set=empty
6) h1 = 2 5 1 4 3 h2 = 8 7 6 set=9
7) h1 = 2 1 4 3 h2 = 5 7 6 set=9 8
8) h1 = 2 1 3 h2 = 5 4 6 set=9 8 7
9) h1 = 2 1 h2 = 5 4 3 set=9 8 7 6
10) h1 = 1 h2 = 2 4 3 set=9 8 7 6 5
11) h1 = empty h2 = 2 1 3 set=9 8 7 6 5 4
h1 = empty , STOP.
Time complexity : O(N log N)

smallest number greater than given number which is a palindrome

This was asked in an interview. Given a number, say 900, output the smallest palindrome greater than the number, 909 in this case. I gave a brute force solution that checks every number but I'm assuming there's a better way to go about this
Just for fun, here's a simple implementation in Python (using essentially the same algorithm as described by Guntram Blohm).
def next_palindrome(n):
"""
Given a non-negative integer n, return the first integer strictly
greater than n whose decimal representation is palindromic.
"""
s = str(n + 1)
l = len(s)
if s[:l//2][::-1] < s[(l+1)//2:]:
head = str(int(s[:(l+1)//2])+1)
else:
head = s[:(l+1)//2]
return int(head + head[:l//2][::-1])
And some sample output:
>>> next_palindrome(123)
131
>>> next_palindrome(4321)
4334
>>> next_palindrome(999)
1001
Copy the first digit to the last, second digit to the second-last etc until you reach the center digit (or center 2 digits if there is an even number of digits).
If the resulting number is smaller than the original number, increase the center digit/center 2 digits by one. If they are 9, set them to zero and retry with the 2 digits next to them, moving outwards until you hit a non-9.
Edit:
If the loop that moves outwards never hits a non-9, prepend a 1 to the string, set all digits except the last one to 0, and the last one to 1. This is the same as adding 2 to the number.
Though what has been answered above is absolutely correct. Just to add more understanding :)
There can be three different types of inputs that need to be handled separately.
1) The input number is palindrome and has all 9s. For example “9 9
9″. Output should be “1 0 0 1″
2) The input number is not palindrome. For example “1 2 3 4″. Output
should be “1 3 3 1″
3) The input number is palindrome and doesn’t have all 9s. For example
“1 2 2 1″. Output should be “1 3 3 1″.
Solution for input type 1
is easy. The output contains n + 1 digits where the corner digits are 1, and all digits between corner digits are 0.
Now let us first talk about input type 2 and 3. Let us first define the following two terms:
Left Side: The left half of given number. Left side of “1 2 3 4 5 6″ is “1 2 3″ and left side of “1 2 3 4 5″ is “1 2″
Right Side: The right half of given number. Right side of “1 2 3 4 5 6″ is “4 5 6″ and right side of “1 2 3 4 5″ is “4 5″
To convert to palindrome, we can either take the mirror of its left side or take mirror of its right side. However, if we take the mirror of the right side, then the palindrome so formed is not guaranteed to be next larger palindrome.
So, we must take the mirror of left side and copy it to right side. But there are some cases that must be handled in different ways. See the following steps.
We will start with two indices i and j. i pointing to the two middle elements (or pointing to two elements around the middle element in case of n being odd). We one by one move i and j away from each other.
Step 1. Initially, ignore the part of left side which is same as the corresponding part of right side. For example, if the number is “8 3 4 2 2 4 6 9″, we ignore the middle four elements. i now points to element 3 and j now points to element 6.
Step 2. After step 1, following cases arise:
Case 1: Indices i & j cross the boundary.
This case occurs when the input number is palindrome. In this case, we just add 1 to the middle digit (or digits in case n is even) propagate the carry towards MSB digit of left side and simultaneously copy mirror of the left side to the right side.
For example, if the given number is “1 2 9 2 1″, we increment 9 to 10 and propagate the carry. So the number becomes “1 3 0 3 1″
Case 2: There are digits left between left side and right side which are not same. So, we just mirror the left side to the right side & try to minimize the number formed to guarantee the next smallest palindrome.
In this case, there can be two sub-cases.
2.1) Copying the left side to the right side is sufficient, we don’t need to increment any digits and the result is just mirror of left side. Following are some examples of this sub-case.
Next palindrome for “7 8 3 3 2 2″ is “7 8 3 3 8 7″
Next palindrome for “1 2 5 3 2 2″ is “1 2 5 5 2 1″
Next palindrome for “1 4 5 8 7 6 7 8 3 2 2″ is “1 4 5 8 7 6 7 8 5 4 1″
How do we check for this sub-case? All we need to check is the digit just after the ignored part in step 1. This digit is highlighted in above examples. If this digit is greater than the corresponding digit in right side digit, then copying the left side to the right side is sufficient and we don’t need to do anything else.
2.2) Copying the left side to the right side is NOT sufficient. This happens when the above defined digit of left side is smaller. Following are some examples of this case.
Next palindrome for “7 1 3 3 2 2″ is “7 1 4 4 1 7″
Next palindrome for “1 2 3 4 6 2 8″ is “1 2 3 5 3 2 1″
Next palindrome for “9 4 1 8 7 9 7 8 3 2 2″ is “9 4 1 8 8 0 8 8 1 4 9″
We handle this subcase like Case 1. We just add 1 to the middle digit (or digits in ase n is even) propagate the carry towards MSB digit of left side and simultaneously copy mirror of the left side to the right side.
SOURCE: http://www.geeksforgeeks.org/given-a-number-find-next-smallest-palindrome-larger-than-this-number/

How to split a list to obtain the power set of its elements?

I have a list and I want to split it into sub lists with +/- 1 items.
Example
I have a list with 17 items in it. What I want is to split it into 4 sub lists like these
1.List = 5 elements
2.List = 4 elements
3.List = 4 elements
4.List = 4 elements
How can I do that? What algorithm I should use here?
Use integer division to get the items in each group and then use modular division to get the number of the first n groups that will have +1 item. For example:
17 items into 4 groups:
17 / 4 = 4 - So there will be 4 groups with 4 elements.
17 % 4 = 1 - So the first 1 groups will have an additional 1 element.
Another example:
18 / 4 = 4 - So there will be 4 groups with 4 elements.
18 % 4 = 2 - So the first 2 groups will have an additional 1 element.
What you want is the Power Set of your original list. The more generic approach for retrieving the power set and the respective properties are given at the Power Set page at Wikipedia

Resources