Related
You are given a stack of N integers such that the first element represents the top of the stack and the last element represents the bottom of the stack. You need to pop at least one element from the stack. At any one moment, you can convert stack into a queue. The bottom of the stack represents the front of the queue. You cannot convert the queue back into a stack. Your task is to remove exactly K elements such that the sum of the K removed elements is maximised.
Print the maximum possible sum M of the K removed elements
Input: N=10, K=4
stack = [10 9 1 2 3 4 5 6 7 8]
Output: 34
Explanation:
Pop two elements from the stack. i.e {10,9}
Then convert the stack into queue and remove first 2 elements from the
queue. i.e {8,7}.
The maximum possible sum is 10+9+8+7 = 34
I was thinking of solving it with greedy algo, with code like following:
stk = [10, 9, 1, 30, 3, 4, 5, 100, 1, 8]
n = 10
k = 4
removed = 0
top = 0
sum = 0
bottom = len(stk)-1
while removed < k:
if stk[top] >= stk[bottom]:
sum += stk[top]
top += 1
else:
sum += stk[bottom]
bottom -= 1
removed += 1
print(sum)
under normal test case(given one) it'll work, but it'll fail in many other scenarios like:
[10, 9, 1, 30, 3, 4, 5, 100, 1, 8]
Any suggestions on how to improve on this?
The data structure gives you the option to select 1,...,n values from the stop of the structure and then m elements from the bottom of the structure where K = m+n. You can find the maximum by starting out with summing the first K elements of the structure and then work your way backwards by replacing the n'th element with the first element from the back. Working backwards to you get to only one stack element. Keep track of the maximum along the way.
In python:
lst = [10, 9, 1, 30, 3, 4, 5, 100, 1, 8]
K = 4
sum_ = sum(lst[0:K])
max_so_far = sum_
for i in range(K-1):
sum_ = sum_ - lst[K-1-i] + lst[-i-1]
max_so_far = max(sum_, max_so_far)
print(max_so_far)
The running time is O(n).
If you carefully look at the problem, it basically boils down to:
Select x elements from the start and y elements from the end of the array, such that the sum is maximum and x+y = K.
That is a pretty simple problem to solve, which basically requires this algorithm:
ans = sum(last K elements)
for i in range(0, K):
ans = max(ans, ans + array[i] - array[n-(k-i+1)]) #picking elements from the start and removing elements from the end
// code in C language
/*
Idea :
W.K.T even it is a stack or a queue we will pop/delete takes place at end or starting of array. we are making use of that.
2.K elements has to be removed in a stack such that their SUM is max
popping of elements has to be at start or end of stack and no. of elements has to be removed are 'K'.
4.We are taking all possibilities of K
i.e. if we take n elements from the front part of stack then K-n elements ahs to selected from back of stack
eg : K = 5 --> possibilities:
(0 5) (1 4) (2 3) (3 2) (4 1) (5 0) -->as you can observe first indx is increasing to K and second indx is decaying to 0 From K.
(0 5) means selecting 0 elements from front of stack and 5 elementts from back of stack
similarly, the other possibilities.
We are taking each possibility and calculating their sum , storing them in separate array 'Sum' and getting max of the sum[] and it will be answer . And the possibility (suppose a b) at which we are getting Max will be our moment where you can convert stack into a queue . Before stack converted into stack we have popped a elements from stack i.e. front of array and after stack converted to queue we deleting b elements which will be done at front of queue i.e. back of the stack.
*/
enter image description here
How to formulate this problem in code?
Problem Statement:
UPDATED:
Find the number of ways to pick the element from the array which are
not visited.
We starting from 1,2,.....,n with some (1<= x <= n) number of elements already picked/visited randomly which is given in the input.
Now, we need to find the number of ways we can pick rest of the (n - x) number of elements present in the array, and the way we pick an element is defined as:
On every turn, we can only pick the element which is adjacent(either left or right) to some visited element i.e
in an array of elements:
1,2,3,4,5,6 let's say we have visited 3 & 6 then we can now pick
2 or 4 or 5, as they are unvisited and adjacent to visited nodes, now say we pick 2, so now we can pick 1 or 4 or 5 and continues.
example:
input: N = 6(number of elements: 1, 2, 3, 4, 5, 6)
M = 2(number of visited elements)
visited elements are = 1, 5
Output: 16(number of ways we can pick the unvisited elements)
ways: 4, 6, 2, 3
4, 6, 3, 2
4, 2, 3, 6
4, 2, 6, 3
4, 3, 2, 6
4, 3, 6, 2
6, 4, 2, 3
6, 4, 2, 3
6, 2, 3, 4
6, 2, 4, 3
2, 6, 4, 3
2, 6, 3, 4
2, 4, 6, 3
2, 4, 3, 6
2, 3, 4, 6
2, 3, 6, 4.
Some analysis of the problem:
The actual values in the input array are assumed to be 1...n, but these values do not really play a role. These values just represent indexes that are referenced by the other input array, which lists the visited indexes (1-based)
The list of visited indexes actually cuts the main array into subarrays with smaller sizes. So for example, when n=6 and visited=[1,5], then the original array [1,2,3,4,5,6] is cut into [2,3,4] and [6]. So it cuts it into sizes 3 and 1. At this point the index numbering loses its purpose, so the problem really is fully described with those two sizes: 3 and 1. To illustrate, the solution for (n=6, visited=[1,5]) is necessarily the same as for (n=7, visited[1,2,6]): the sizes into which the original array is cut, are the same in both cases (in a different order, but that doesn't influence the result).
Algorithm, based on a list of sizes of subarrays (see above):
The number of ways that one such subarray can be visited, is not that difficult: if the subarray's size is 1, there is just one way. If it is greater, then at each pick, there are two possibilities: either you pick from the left side or from the right side. So you get like 2*2*..*2*1 possibilities to pick. This is 2size-1 possibilities.
The two outer subarrays are an exception to this, as you can only pick items from the inside-out, so for those the number of ways to visit such a subarray is just 1.
The number of ways that you can pick items from two subarrays can be determined as follows: count the number of ways to pick from just one of those subarrays, and the number of ways to pick from the other one. Then consider that you can alternate when to pick from one sub array or from the other. This comes down to interweaving the two sub arrays. Let's say the larger of the two sub arrays has j elements, and the smaller k, then consider there are j+1 positions where an element from the smaller sub array can be injected (merged) into the larger array. There are "k multichoose j+1" ways ways to inject all elements from the smaller sub array.
When you have counted the number of ways to merge two subarrays, you actually have an array with a size that is the sum of those two sizes. The above logic can then be applied with this array and the next subarray in the problem specification. The number of ways just multiplies as you merge more subarrays into this growing array. Of course, you don't really deal with the arrays, just with sizes.
Here is an implementation in JavaScript, which applies the above algorithm:
function getSubArraySizes(n, visited) {
// Translate the problem into a set of sizes (of subarrays)
let j = 0;
let sizes = [];
for (let i of visited) {
let size = i - j - 1;
if (size > 0) sizes.push(size);
j = i;
}
let size = n - j;
if (size > 0) sizes.push(size);
return sizes;
}
function Combi(n, k) {
// Count combinations: "from n, take k"
// See Wikipedia on "Combination"
let c = 1;
let end = Math.min(k, n - k);
for (let i = 0; i < end; i++) {
c = c * (n-i) / (end-i); // This is floating point
}
return c; // ... but result is integer
}
function getPickCount(sizes) {
// Main function, based on a list of sizes of subarrays
let count = 0;
let result = 1;
for (let i = 0; i < sizes.length; i++) {
let size = sizes[i];
// Number of ways to take items from this chunk:
// - when items can only be taken from one side: 1
// - otherwise: every time we have a choice between 2, except for the last remaining item
let pickCount = i == 0 || i == sizes.length-1 ? 1 : 2 ** (size-1);
// Number of ways to merge/weave two arrays, where relative order of elements is not changed
// = a "k multichoice from n". See
// https://en.wikipedia.org/wiki/Combination#Number_of_combinations_with_repetition
let weaveCount = count == 0 ? 1 // First time only
: Combi(size+count, Math.min(count, size));
// Number of possibilities:
result *= pickCount * weaveCount;
// Update the size to be the size of the merged/woven array
count += size;
}
return result;
}
// Demo with the example input (n = 6, visited = 1 and 5)
let result = getPickCount(getSubArraySizes(6, [1, 5]));
console.log(result);
I'm working on the following problem:
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
My initial impression here was to, from each position in the grid, get the min length of going to the right vs going downward. However, this gives me the incorrect answer for the following:
Input:
[[1,2],[1,1]]
Output:
2
Expected:
3
Intuitively, not sure what I'm doing wrong. It's also very simple code (I know it's not memoized--was planning on that for the next step) but intuitively not sure what's going wrong. The recursive base case makes sense, and each number is being taken into consideration.
def min_path_sum(grid)
smallest_path(0, 0, grid)
end
def smallest_path(row, col, grid)
return 0 if (row == grid.length || col == grid.first.length)
current_val = grid[row][col]
[current_val + smallest_path(row+1, col, grid), current_val + smallest_path(row, col+1, grid)].min #memoize here
end
You didn't make a proper termination condition. You check only until you hit either the right column or bottom row. You need to stay within bounds, but continue until you hit the lower-right corner. You need to recur within bounds until you hit both limits.
Given that, your code does work okay: it finds the path of 2 to the bottom row, rather than the path of 3 to the right edge. You just have to teach it to finish the job.
Is that enough to move you to a solution?
As this is a shortest path problem on an acyclic directed graph, you could use a standard shortest path algorithm.
You could also use dynamic programming ("DP), which may be the most efficient optimization technique. My answer implements a DP algorithm.
A shortest-path or DP algorithm would be vastly superior to enumerating all paths from top-left to bottom-right. As the number of paths increases exponentially with the size of the array, simple enumeration could only be used on modest-sized arrays.
The idea of the DP algorithm is as follows. Let n and m be the numbers of rows and columns, respectively. First compute the shortest path from each column in the last row to the last column in the last row. This is an easy calculation because there is only one path to [m-1, n-1] for each of these elements. Starting with [m-1, n-2] we simply work back to [m-1, 0].
Next we compute the shortest paths from each element in each of the other rows to [m-1, n-1], starting with the penultimate row (m-2) and working back to the first row (0). The last element in each row, [i, n-1], is an easy calculation because one can only go down (to [i+1, n-1]). Therefore, the shortest path from [i, n-1] to [m-1, n-1] is first going to [i+1, n-1] and then following the shortest path from [i+1, n-1], which we've already computed (including its length, of course). The length of the shortest path from [i, n-1] is the "down" distance for [i, n-1] plus the length of the shortest path from [i+1, n-1].
For elements [i, j], n-1,i < j < m-1, we calculate the shortest paths if we go right and down, and select the shorter of the two.
We can implement this as follows.
Code
def shortest_path(distance)
last_row, last_col = distance.size-1, distance.first.size-1
h = {}
last_row.downto(0) do |i|
last_col.downto(0) do |j|
h_right = { min_path_len: distance[i][j][:r] + h[[i,j+1]][:min_path_len],
next_node: [i,j+1] } if j < last_col
h_down = { min_path_len: distance[i][j][:d] + h[[i+1,j]][:min_path_len],
next_node: [i+1,j] } if i < last_row
g =
case
when i == last_row && j == last_col
{ min_path_len: 0, next_node: nil }
when i == last_row
h_right
when j == last_col
h_down
else
[h_right, h_down].min_by { |f| f[:min_path_len] }
end
h[[i,j]] = g
end
end
build_path(h)
end
def build_path(h)
node = [0, 0]
len = h[node][:min_path_len]
arr = []
while h[node][:next_node]
arr << node
node = h[node][:next_node]
end
[len, arr]
end
Example
Suppose these are the distances between adjacent nodes.
● 4 ● 3 ● 1 ● 2 ●
6 2 5 4 5
● 3 ● 4 ● 6 ● 3 ●
1 3 4 2 3
● 6 ● 3 ● 1 ● 2 ●
It's convenient to provide this information in the form of an array of hashes.
distance = [
[{ r: 4, d: 6 }, { r: 3, d: 2 }, { r: 1, d: 5 }, { r: 2, d: 4 }, { d: 5 }],
[{ r: 3, d: 1 }, { r: 4, d: 3 }, { r: 6, d: 4 }, { r: 3, d: 2 }, { d: 3 }],
[{ r: 6 }, { r: 3 }, { r: 1 }, { r: 2 }]
]
We may now compute a shortest path.
p shortest_path distance
#=> [15, [[0, 0], [0, 1], [1, 1], [2, 1], [2, 2], [2, 3]]]
A shortest path is given by the second element of the array that is returned. 15 is the length of that path.
I try to solve the following problem. Given an array of real numbers [7, 2, 4, 8, 1, 1, 6, 7, 4, 3, 1] for every element I need to find most recent previous bigger element in the array.
For example there is nothing bigger then first element (7) so it has NaN. For the second element (2) 7 is bigger. So in the end the answer looks like:
[NaN, 7, 7, NaN, 8, 8, 8, 8, 7, 4, 3, 1]. Of course I can just check all the previous elements for every element, but this is quadratic in terms of the number of elements of the array.
My another approach was to maintain the sorted list of previous elements and then select the first element bigger then current. This sounds like a log linear to me (am not sure). Is there any better way to approach this problem?
Here's one way to do it
create a stack which is initially empty
for each number N in the array
{
while the stack is not empty
{
if the top item on the stack T is greater than N
{
output T (leaving it on the stack)
break
}
else
{
pop T off of the stack
}
}
if the stack is empty
{
output NAN
}
push N onto the stack
}
Taking your sample array [7, 2, 4, 8, 1, 1, 6, 7, 4, 3, 1], here's how the algorithm would solve it.
stack N output
- 7 NAN
7 2 7
7 2 4 7
7 4 8 NAN
8 1 8
8 1 1 8
8 1 6 8
8 6 7 8
8 7 4 7
8 7 4 3 4
8 7 4 3 1 3
The theory is that the stack doesn't need to keep small numbers since they will never be part of the output. For example, in the sequence 7, 2, 4, the 2 is not needed, because any number less than 2 will also be less than 4. Hence the stack only needs to keep the 7 and the 4.
Complexity Analysis
The time complexity of the algorithm can be shown to be O(n) as follows:
there are exactly n pushes (each number in the input array is
pushed onto the stack once and only once)
there are at most n pops (once a number is popped from the stack,
it is discarded)
there are at most n failed comparisons (since the number is popped
and discarded after a failed comparison)
there are at most n successful comparisons (since the algorithm
moves to the next number in the input array after a successful
comparison)
there are exactly n output operations (since the algorithm
generates one output for each number in the input array)
Hence we conclude that the algorithm executes at most 5n operations to complete the task, which is a time complexity of O(n).
We can keep for each array element the index of the its most recent bigger element. When we process a new element x, we check the previous element y. If y is greater then we found what we want. If not, we check which is the index of the most recent bigger element of y. We continue until we find our needed element and its index. Using python:
a = [7, 2, 4, 8, 1, 1, 6, 7, 4, 3, 1]
idx, result = [], []
for i, v in enumerate(a, -1):
while i >= 0 and v >= a[i]:
i = idx[i]
idx.append(i)
result.append(a[i] if i >= 0 else None)
Result:
[None, 7, 7, None, 8, 8, 8, 8, 7, 4, 3]
The algorithm is linear. When an index j is unsuccessfully checked because we are looking for the most recent bigger element of index i > j then from now on i will point to a smaller index than j and j won't be checked again.
Why not just define a variable 'current_largest' and iterate through your array from left to right? At each element, current largest is largest previous, and if the current element is larger, assign current_largest to the current element. Then move to the next element.
EDIT:
I just re-read your question and I may have misunderstood it. Do you want to find ALL larger previous elements?
EDIT2:
It seems to me like the current largest method will work. You just need to record current_largest before you assign it a new value. For example, in python:
current_largest = 0
for current_element in elements:
print("Largest previous is "+current_largest)
if(current_element>current_largest):
current_largest = current_element
If you want an array of these, then just push the value to an array in place of the print statement.
As per my best understanding of your question. Below is a solution.
Working Example : JSFIDDLE
var item = document.getElementById("myButton");
item.addEventListener("click", myFunction);
function myFunction() {
var myItems = [7, 2, 4, 8, 1, 1, 6, 7, 4, 3, 1];
var previousItem;
var currentItem;
var currentLargest;
for (var i = 0; i < myItems.length; i++) {
currentItem = myItems[i];
if (i == 0) {
previousItem = myItems[0];
currentItem = myItems[0];
myItems[i] = NaN;
}
else {
if (currentItem < previousItem) {
myItems[i] = previousItem;
currentLargest = previousItem;
}
if (currentItem > currentLargest) {
currentLargest = currentItem;
myItems[i] = NaN;
}
else {
myItems[i] = currentLargest;
}
previousItem = currentItem;
}
}
var stringItems = myItems.join(",");
document.getElementById("arrayAnswer").innerHTML = stringItems;
}
I know that this question has been asked, and there is a very nice elegant solution using a min heap.
MY question is how would one do this using the merge function of merge sort.
You already have an array of sorted arrays. So you should be able to merge all of them into one array in O(nlog K) time, correct?
I just can't figure out how to do this!
Say I have
[ [5,6], [3,4], [1,2], [0] ]
Step 1: [ [3,4,5,6], [0,1,2] ]
Step2: [ [0,1,2,3,4,5,6] ]
Is there a simple way to do this? Is O(nlog K) theoretically achievable with mergesort?
As others have said, using the min heap to hold the next items is the optimal way. It's called an N-way merge. Its complexity is O(n log k).
You can use a 2-way merge algorithm to sort k arrays. Perhaps the easiest way is to modify the standard merge sort so that it uses non-constant partition sizes. For example, imagine that you have 4 arrays with lengths 10, 8, 12, and 33. Each array is sorted. If you concatenated the arrays into one, you would have these partitions (the numbers are indexes into the array, not values):
[0-9][10-17][18-29][30-62]
The first pass of your merge sort would have starting indexes of 0 and 10. You would merge that into a new array, just as you would with the standard merge sort. The next pass would start at positions 18 and 30 in the second array. When you're done with the second pass, your output array contains:
[0-17][18-62]
Now your partitions start at 0 and 18. You merge those two into a single array and you're done.
The only real difference is that rather than starting with a partition size of 2 and doubling, you have non-constant partition sizes. As you make each pass, the new partition size is the sum of the sizes of the two partitions you used in the previous pass. This really is just a slight modification of the standard merge sort.
It will take log(k) passes to do the sort, and at each pass you look at all n items. The algorithm is O(n log k), but with a much higher constant than the N-way merge.
For implementation, build an array of integers that contains the starting indexes of each of your sub arrays. So in the example above you would have:
int[] partitions = [0, 10, 18, 30];
int numPartitions = 4;
Now you do your standard merge sort. But you select your partitions from the partitions array. So your merge would start with:
merge (inputArray, outputArray, part1Index, part2Index, outputStart)
{
part1Start = partitions[part1Index];
part2Start = partitions[part2Index];
part1Length = part2Start - part1Start;
part2Length = partitions[part2Index-1] - part2Start;
// now merge part1 and part2 into the output array,
// starting at outputStart
}
And your main loop would look something like:
while (numPartitions > 1)
{
for (int p = 0; p < numPartitions; p += 2)
{
outputStart = partitions[p];
merge(inputArray, outputArray, p, p+1, outputStart);
// update partitions table
partitions[p/2] = partitions[p] + partitions[p+1];
}
numPartitions /= 2;
}
That's the basic idea. You'll have to do some work to handle the dangling partition when the number is odd, but in general that's how it's done.
You can also do it by maintaining an array of arrays, and merging each two arrays into a new array, adding that to an output array of arrays. Lather, rinse, repeat.
You should note that when we say complexity is O(n log k), we assume that n means TOTAL number of elements in ALL of k arrays, i.e. number of elements in a final merged array.
For example, if you want to merge k arrays that contain n elements each, total number of elements in final array will be nk. So complexity will be O(nk log k).
There different ways to merge arrays. To accoplish that task in N*Log(K) time you can use a structure called Heap (it is good structure to implement priority queue). I suppose that you already have it, if you don’t then pick up any available implementation: http://en.wikipedia.org/wiki/Heap_(data_structure)
Then you can do that like this:
1. We have A[1..K] array of arrays to sort, Head[1..K] - current pointer for every array and Count[1..K] - number of items for every array.
2. We have Heap of pairs (Value: int; NumberOfArray: int) - empty at start.
3. We put to the heap first item of every array - initialization phase.
4. Then we organize cycle:
5. Get pair (Value, NumberOfArray) from the heap.
6. Value is next value to output.
7. NumberOfArray – is number of array where we need to take next item (if any) and place to the heap.
8. If heap is not empty, then repeat from step 5
So for every item we operate only with heap built from K items as maximum. It mean that we will have N*Log(K) complexity as you asked.
I implemented it in python. The main idea is similar to mergesort. There are k arrays in lists. In function mainMerageK, just divide lists (k) into left (k/2) and right (k/2). Therefore, the total count of partition is log(k). Regarding function merge, it is easy to know the runtime is O(n). Finally, we get O(nlog k)
By the way, it also can be implemented in min heap, and there is a link: Merging K- Sorted Lists using Priority Queue
def mainMergeK(*lists):
# implemented by k-way partition
k = len(lists)
if k > 1:
mid = int(k / 2)
B = mainMergeK(*lists[0: mid])
C = mainMergeK(*lists[mid:])
A = merge(B, C)
print B, ' + ', C, ' = ', A
return A
return lists[0]
def merge(B, C):
A = []
p = len(B)
q = len(C)
i = 0
j = 0
while i < p and j < q:
if B[i] <= C[j]:
A.append(B[i])
i += 1
else:
A.append(C[j])
j += 1
if i == p:
for c in C[j:]:
A.append(c)
else:
for b in B[i:]:
A.append(b)
return A
if __name__ == '__main__':
x = mainMergeK([1, 3, 5], [2, 4, 6], [7, 8, 10], [9])
print x
The output likes below:
[1, 3, 5] + [2, 4, 6] = [1, 2, 3, 4, 5, 6]
[7, 8, 10] + [9] = [7, 8, 9, 10]
[1, 2, 3, 4, 5, 6] + [7, 8, 9, 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Just do it like a 2-way merge except with K items. Will result in O(NK). If you want O(N logK) you will need to use a min-heap to keep track of the K pointers(with source array as a metadata) in the algorithm below:
Keep an array of K elements - i.e K pointers showing position in each array.
Mark all K elements are valid.
loop:
Compare values in K pointers that are valid. if the value is minimum, select least index pointer and increment it into the next value in the array. If incremented value has crossed it's array, mark it invalid.
Add the least value into the result.
Repeat till all K elements are invalid.
For example,:
Positions Arrays
p1:0 Array 1: 0 5 10
p2:3 Array 2: 3 6 9
p3:2 Array 3: 2 4 6
Output (min of 0,3,2)=> 0. So output is {0}
Array
p1:5 0 5 10
p2:3 3 6 9
p3:2 2 4 6
Output (min of 5,3,2)=> 2. So {0,2}
Array
p1:5 0 5 10
p2:3 3 6 9
p3:4 2 4 6
Output (min of 5,3,4)=>3. So {0,2,3}
..and so on..until you come to a state where output is {0,2,3,4,5,6}
Array
p1:5 0 5 10
p2:9 3 6 9
p3:6 2 4 6
Output (min of 5,9,6)=>6. So {0,2,3,4,5,6}+{6} when you mark p3 as "invalid" as you have exhausted the array. (or if you are using a min-heap you will simply remove the min-item, get it's source array metadata: in this case array 3, see that it's done so you will not add anything new to the min-heap)