Engines numbered 1, 2, ..., n are on the line at the left, and it is desired to rearrange(permute) the engines as they leave on the right-hand track. An engine that is on the spur track can be left there or sent on its way down the right track, but it can never be sent back to the incoming track. For example if n = 3, and we ha the engines numbered 1,2,3 on the left track, then 3 first goes to the spur track. We could then send 2 to the spur, then on the way to its right,then send 3 on the way, then 1, obtaining the new order 1,3,2.
We have to find all the possible permutations for specific n.
For n=1, answer = 1;
For n=2 answer = 2;
For n=3 answer = 5;
Didn't find any generality.
Using Stack Implementation would be very helpful.
But any solution is welcomed.
p.s. This is not a homework question, as I am a self taught person.
Here's my attempt at a recursive solution (see comments in Java code):
private static int result = 0;
private static int n = 3;
public static void g(int right,int spur){
if (right == n) // all trains are on the right track
result++;
else if (right + spur < n) // some trains are still on the left track
g(right,spur + 1); // a train moved from the left track to the spur
if (spur > 0) // at least one train is on the spur
g(right + 1,spur - 1); // a train moved from the spur to the right track
// (also counts trains moving directly from the left to right track)
}
public static void main (String[] args){
g(0,0);
System.out.println(result); // 5
}
The recursive solution above actually counts each possibility. For a combinatorial solution we consider all combinations of n movements on and out of the spur, where adjacent such movements are equivalent to movements directly from the left to right track. There are 2n choose n such combinations. Now let's count the invalid ones:
Consider all combinations of (n - 1) ins and (n + 1) outs of the spur. All these include a point, p, where a train is counted as leaving the spur when no trains are on it. Let's say that p has k ins and (k + 1) outs preceding it - then the number of remaining ins is (n - 1 - k); and remaining outs, (n + 1) - (k + 1) = (n - k).
Now reverse the ins and outs for each one of these combinations starting after p so that in becomes out and out in. Each one of the reversed sections has necessarily (n - k) ins and (n - 1 - k) outs. But now if we total the number of ins and outs before and after p we get k + (n - k) = n ins, and (k + 1) + (n - 1 - k) = n outs. We have just counted the number of combinations of n ins and n outs that are invalid. If we assume that one such combination may not have been counted, theoretically reverse that combination after its p and you will find a combination of (n - 1) ins and (n + 1) outs that was not counted. But by definition we counted them all already so our assumed extra combination could not exist.
Total valid combinations then are 2n choose n - 2n choose (n + 1), the Catalan numbers.
(Adapted from an explanation by Tom Davis here: http://mathcircle.berkeley.edu/BMC6/pdf0607/catalan.pdf)
First, note that you may ignore the possibility of moving the train from incoming directly to outgoing: such a move can be done by moving a train to the spur and then out again.
Denote a train move from incoming to spur as ( and a train move from spur to outgoing as ), and you get a bijection between permutations of the trains and strings of n pairs of correctly balanced parenthesis. That statement needs proving, but the only hard part of the proof is proving that no two strings of balanced parentheses correspond to the same permutation. The number of such strings is the n'th Catalan number, or choose(2n, n)/(n+1), where choose(n, k) is the number of ways of choosing k items from n.
Here's code to compute the solution:
def perms(n):
r = 1
for i in xrange(1, n+1):
r *= (n + i)
r //= i
return r // (n + 1)
You can generate all the permutations with this code, which also exposes the Catalan nature of the solution.
def perms(n, i=0):
if n == 0:
yield []
for k in xrange(n):
for s in perms(k, i+1):
for t in perms(n-k-1, i+k+1):
yield s + [i] + t
print list(perms(4))
Output:
[[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1],
[0, 3, 2, 1], [1, 0, 2, 3], [1, 0, 3, 2], [1, 2, 0, 3],
[2, 1, 0, 3], [1, 2, 3, 0], [1, 3, 2, 0], [2, 1, 3, 0],
[2, 3, 1, 0], [3, 2, 1, 0]]
The status of the system can be described by giving the 3 (ordered!) lists of engines, in the left, spur and right tracks. Given the status, it is possible to calculate all the possible moves. This creates a tree of possibilities: the root of the tree is the initial status, and every move corresponds to a branch which leads to a new status. The final status at the end of a branch (a leaf) is your final position in the right track.
So, you have to build and explore all the tree, and at the end you have to count all the leaves. And the tree is a common data structure.
Just to clarify, the tree in this case wouldn't replace the stacks. The stacks are used to store your data (the position of the engines); the tree is used to track the progress of the algorithm. Every time you have a status (a node of the tree) you have to analyse your data (=the content of the stacks) and find the possible moves. Every move is a branch in the tree of the algorithm, and it leads to a new status of the stacks (because the engine has moved). So basically you will have one "configuration" of the 3 stacks for each node of the tree.
Related
For the Leetcode question "Number of islands," I am trying to determine the SPACE complexity for the Breadth First Search solution.
from collections import deque
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
num_islands = 0
num_row, num_col = len(grid), len(grid[0])
for r in range(num_row):
for c in range(num_col):
if grid[r][c] == '1':
num_islands += 1
self.bfs(r, c, grid)
return num_islands
def bfs(
self,
row: int,
col: int,
grid: List[List[str]]
) -> None:
queue = deque([(row, col)])
while queue:
r, c = queue.popleft()
if grid[r][c] != '1':
continue
grid[r][c] = 'X'
if r+1 <= len(grid)-1 and grid[r+1][c] == '1':
queue.append((r+1, c))
if r-1 >= 0 and grid[r-1][c] == '1':
queue.append((r-1, c))
if c+1 <= len(grid[0])-1 and grid[r][c+1] == '1':
queue.append((r, c+1))
if c-1 >= 0 and grid[r][c-1] == '1':
queue.append((r, c-1))
I am looking at this SO answer, but that example doesn't really elaborate on how exactly worst case BFS space complexity = O(M · N), where M = # of rows and N = number of columns. It states that the queue will have all of the leaf nodes, but how will that be? Also, how are all of the leaf nodes proportional to M · N? I think that diagram makes it hard to conceptualize.
I worked out a few examples, and I definitely see some cases where BFS space complexity > O(Max(M, N)), but can't grasp how it can be O(M·N) worst case. Can someone please explain, preferably with a visual walkthrough?
Example with space complexity = O(Min(M, N)) if you start at top-left corner, but > O(Max(M, N)) if you start in the middle:
[
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]
]
A visual example like the one above will be easier to digest.
It's not so easy to arrange, but the worst case BFS queue size for an MxM matrix is indeed in Ω(M2)
Lets say we have an MxM block, with M odd, where a BFS starting in the center of one side can reach W cells at the same time, implying a queue size of W.
It's not hard to arrange these into a 2M+3 x 2M+3 block that starts in the center of one side and reaches 4W cells at the same time, like this:
### ###
### ###
#S# #S#
# #
#######
# # #
#S# # #S#
### # ###
### S ###
We can then repeat the procedure with these new blocks, and then repeat again, etc., as long as we like.
As these blocks get bigger and bigger, the extra 3 rows and columns take up a smaller and smaller proportion of the total. In terms of the number of repetitions of this procedure n, the length of the side M is in O(2n),
The maximum BFS queue size, of course is in Ω(4n), which is Ω(M2).
Here's what it looks like if you repeat the procedure a bunch of times. A BFS starting at the top will find all the other end points at the same level:
I have a list of integers, and I need to find a way to get the maximum sum of a subset of them, adding elements to the total until the sum is equal to (or greater than) a fixed cutoff. I know this seems similar to the knapsack, but I was unsure whether it was equivalent.
Sorting the array and adding the maximum element until sum <= cutoff does not work. Observe the following list:
list = [6, 5, 4, 4, 4, 3, 2, 2, 1]
cutoff = 15
For this list, doing it the naive way results in a sum of 15, which is very sub-optimal. As far as I can see, the maximum you could arrive at using this list is 20, by adding 4 + 4 + 4 + 2 + 6. If this is just a different version of knapsack, I can just implement a knapsack solution, as I probably have small enough lists to get away with this, but I'd prefer to do something more efficient.
First of all in any sum, you won't have produced a worse result by adding the largest element last. So there is no harm in assuming that the elements are sorted from smallest to largest as a first step.
And now you use a dynamic programming approach similar to the usual subset sum.
def best_cutoff_sum (cutoff, elements):
elements = sorted(elements)
sums = {0: None}
for e in elements:
next_sums = {}
for v, path in sums.iteritems():
next_sums[v] = path
if v < cutoff:
next_sums[v + e] = [e, path]
sums = next_sums
best = max(sums.keys())
return (best, sums[best])
print(best_cutoff_sum(15, [6, 5, 4, 4, 4, 3, 2, 2, 1]))
With a little work you can turn the path from the nested array it currently is to whatever format you want.
If your list of non-negative elements has n elements, your cutoff is c and your maximum value is v, then this algorithm will take time O(n * (k + v))
I've a list of n elements (e_i). For each i, e_i have a probability p_i to be selected.
I want to write an algorithm to pick k elements from theses n, but I have to respect the probabilities of each element when I choose them. I've no idea how to do that, I didn't know any algorithm which do that :/
Can you direct my reflection?
Let's say you have 3 possible values: A, B, C and:
P(A) = 0.2, P(B) = 0.3, P(C) = 0.5. Then you will put the cumulative probabilities in an array p = [0.2, 0.5, 1]. In each pick you will generate a random number in the range [0, 1] (using the built in library of the language you use). Based on that number, you will return as a response the smallest number which is greater or equal to the randomly generated number (actually the class which corresponds to that number A, B or C).
Hint: that class can be obtained in O(logN) time, if the optimal approach is used.
Here is an example:
if you generate value of 0.4, then you will return B, because 0.5 is the smallest number >= 0.4. If you generate 0.01 you will return A.
That's the idea, I'll let you try implement that. If you need more help, I could write some (pseudo)code too.
Assuming that you want k distinct elements, you could do the following: keep track of the total remaining probability of the non-selected elements. Repeatedly (k times) pick a random number, r, in the range [0,remaining]. Scan over the probabilities, accumulating the probabilities until the sum exceeds r. Pick the corresponding element. Then -- reduce remaining by this probability and then zero the probability of that element so that it won't be picked again.
Here is a Python implementation:
from random import random
def choose(probs,k):
choices = []
remaining = 1
p = probs[:] #create a local copy
for i in range(k):
r = remaining * random()
i = 0
s = p[i]
while s < r:
i += 1
s += p[i]
choices.append(i)
remaining -= p[i]
p[i] = 0 #so won't be chosen again
return choices
#test:
dist = [0.2, 0.4, 0.1, 0.1, 0.1, 0.05, 0.05]
for i in range(10):
print(choose(dist,4))
Typical output:
[2, 5, 1, 3]
[1, 0, 6, 4]
[0, 4, 1, 6]
[1, 2, 3, 0]
[1, 5, 2, 4]
[3, 1, 0, 2]
[1, 2, 0, 4]
[1, 2, 0, 4]
[2, 5, 1, 4]
[1, 2, 0, 3]
Note how 0 and 1 are frequently chosen but 5 and 6 are comparatively rare.
As an implementation detail: the above algorithm should always work in principle, but it is possible that round-off error and a value of r which is extremely close to remaining could lead to a subscript out of range error. For some use cases this should be so rare that you need not worry about it, but you could add error-trapping to e.g. pick the element with the last non-zero probability in the cases that the sum of all non-zero probabilities rounds to just below remaining and the r chosen happens to fall in that narrow gap.
So element ix can be expressed as (e_ix, p_ix), as those are its two components. You apparently already know what values to fill in for all of these. I am going to come up with an example though, so I can show you how to do this without doing it for you:
(A, 1) (B, 2) (C, 3)
What you need to do is assign each value to a range. I'll do it an easy way and just go left to right, starting at zero.
So, we need 1 slot for A, 2 for B, 3 for C. Our possible indices will be 0, 1, 2, 3, 4, and 5.
0->A
1->B
2->B
3->C
4->C
5->C
This is a basic example, and your weights might be floating point, but it should give you a start.
Edit: Floating point example
(D, 2) (E, .5123) (F, 1)
D < 2
2 <= E < 2.5123
2.5123 <= F < 3.5123
Necessary assumption
By linearity of the expectation, it is easy to show that if you pick elements among the n elements 0, 1, 2, ..., n-1 such that each element i has probability p_i of being selected, then the expectation of the number of picked elements is exactly sum p_i. This holds no matter the algorithm used to pick the elements.
You are looking for such an algorithm, but with the added constraint that the number of picked elements is always k. It follows that a necessary assumption is:
sum p_i = k
Fortunately, it turns out that this assumption is also sufficient.
Algorithm
Assume now that sum p_i = k. The following algorithm will select exactly k elements, such that each element i in 0,1,...,n-1 has probability p_i of being chosen.
Compute the cumulative sums:
c_0 = 0
c_1 = p_0
...
c_i = p_0 + p_1 + ... + p_(i-1)
...
c_n = k
Pick a number x uniformly at random in [0,1[
For every number y in the list x, 1+x, 2+x, 3+x, ..., k-1+x:
Choose element i such that c_i <= y < c_(i+1)
It is easy to verify that exactly k elements are chosen, and that every element i has probability p_i of being chosen.
Reference
The previous algorithm is the subject of a research paper from the 80s or 90s, which I can't put my hands on at this exact moment; I will edit this post with a reference if I can find it again.
ranking an element x in an array/list is just to find out how many elements in the array/list that strictly smaller than x.
So ranking a list is just get ranks of all elements in the list.
For example, rank [51, 38, 29, 51, 63, 38] = [3, 1, 0, 3, 5, 1], i.e., there are 3 elements smaller than 51, etc.
Ranking a list can be done in O(NlogN). Basically, we can sort the list while remembering the original index of each element, and then see for each element, how many before it.
The question here is How to rank the suffixes of a list, in O(NlogN)?
Ranking the suffixes of a list means:
for list [3; 1; 2], rank [[3;1;2]; [1;2]; [2]]
note that elements may not be distinct.
edit
We don't need to print out all elements for all suffixes. You can image that we just need to print out a list/array, where each element is a rank of a suffix.
For example, rank suffix_of_[3;1;2] = rank [[3;1;2]; [1;2]; [2]] = [2;0;1] and you just print out [2;0;1].
edit 2
Let me explain what is all suffixes and what means sorting/ranking all suffixes more clearly here.
Suppose we have an array/list [e1;e2;e3;e4;e5].
Then all suffixes of [e1;e2;e3;e4;e5] are:
[e1;e2;e3;e4;e5]
[e2;e3;e4;e5]
[e3;e4;e5]
[e4;e5]
[e5]
for example, all suffixes of [4;2;3;1;0] are
[4;2;3;1;0]
[2;3;1;0]
[3;1;0]
[1;0]
[0]
Sorting above 5 suffixes implies lexicographic sort. sorting above all suffixes, you get
[0]
[1;0]
[2;3;1;0]
[3;1;0]
[4;2;3;1;0]
by the way, if you can't image how 5 lists/arrays can be sorted among them, just think of sorting strings in lexicographic order.
"0" < "10" < "2310" < "310" < "42310"
It seems sorting all suffixes is actually sorting all elements of the original array.
However, please be careful that all elements may not be distinct, for example
for [4;2;2;1;0], all suffixes are:
[4;2;2;1;0]
[2;2;1;0]
[2;1;0]
[1;0]
[0]
then the order is
[0]
[1;0]
[2;1;0]
[2;2;1;0]
[4;2;2;1;0]
As MBo noted correctly, your problem is that of constructing the suffix array of your input list. The fast and complicated algorithms to do this are actually linear time, but since you only aim for O(n log n), I will try to propose a simpler version that is much easier to implement.
Basic idea and an initial O(n log² n) implementation
Let's take the sequence [4, 2, 2, 1] as an example. Its suffixes are
0: 4 2 2 1
1: 2 2 1
2: 2 1
3: 1
I numbered the suffixes with their starting index in the original sequence. Ultimately we want to sort this set of suffixes lexicographically, and fast. We know we can represent each suffix using its starting index in constant space and we can sort in O(n log n) comparisons using merge sort, heap sort or a similar algorithm. So the question remains, how can we compare two suffixes fast?
Let's say we want to compare the suffixes [2, 2, 1] and [2, 1]. We can pad those with negative infinity values changing the result of the comparison: [2, 2, 1, -∞] and [2, 1, -∞, -∞].
Now the key idea here is the following divide-and-conquer observation: Instead of comparing the sequences character by character until we find a position where the two differ, we can instead split both lists in half and compare the halves lexicographically:
[a, b, c, d] < [e, f, g, h]
<=> ([a, b], [c, d]) < ([e, f], [g, h])
<=> [a, b] < [e, f] or ([a, b,] = [e, f] and [c, d] < [g, h])
Essentially we have decomposed the problem of comparing the sequences into two problems of comparing smaller sequences. This leads to the following algorithm:
Step 1: Sort the substrings (contiguous subsequences) of length 1. In our example, the substrings of length 1 are [4], [2], [2], [1]. Every substring can be represented by the starting position in the original list. We sort them by a simple comparison sort and get [1], [2], [2], [4]. We store the result by assigning to every position it's rank in the sorted lists of lists:
position substring rank
0 [4] 2
1 [2] 1
2 [2] 1
3 [1] 0
It is important that we assign the same rank to equal substrings!
Step 2: Now we want to sort the substrings of length 2. The are only really 3 such substrings, but we assign one to every position by padding with negative infinity if necessary. The trick here is that we can use our divide-and-conquer idea from above and the ranks assigned in step 1 to do a fast comparison (this isn't really necessary yet but will become important later).
position substring halves ranks from step 1 final rank
0 [4, 2] ([4], [2]) (2, 1) 3
1 [2, 2] ([2], [2]) (1, 1) 2
2 [2, 1] ([2], [2]) (1, 0) 1
3 [1, -∞] ([1], [-∞]) (0, -∞) 0
Step 3: You guessed it, now we sort substrings of length 4 (!). These are exactly the suffixes of the list! We can use the divide-and-conquer trick and the results from step 2 this time:
position substring halves ranks from step 2 final rank
0 [4, 2, 2, 1] ([4, 2], [2, 1]) (3, 1) 3
1 [2, 2, 1, -∞] ([2, 2], [1, -∞]) (2, 0) 2
2 [2, 1, -∞, -∞] ([2, 1], [-∞,-∞]) (1, -∞) 1
3 [1, -∞, -∞, -∞] ([1,-∞], [-∞,-∞]) (0, -∞) 0
We're done! If our initial sequence would have had size 2^k, we would have needed k steps. Or put the other way round, we need log_2 n steps to process a sequence of size n. If its length is not a power of two, we just pad with negative infinity.
For an actual implementation we just need to remember the sequence "final rank" for every step of the algorithm.
An implementation in C++ could look like this (compile with -std=c++11):
#include <algorithm>
#include <iostream>
using namespace std;
int seq[] = {8, 3, 2, 4, 2, 2, 1};
const int n = 7;
const int log2n = 3; // log2n = ceil(log_2(n))
int Rank[log2n + 1][n]; // Rank[i] will save the final Ranks of step i
tuple<int, int, int> L[n]; // L is a list of tuples. in step i,
// this will hold pairs of Ranks from step i - 1
// along with the substring index
const int neginf = -1; // should be smaller than all the numbers in seq
int main() {
for (int i = 0; i < n; ++i)
Rank[1][i] = seq[i]; // step 1 is actually simple if you think about it
for (int step = 2; step <= log2n; ++step) {
int length = 1 << (step - 1); // length is 2^(step - 1)
for (int i = 0; i < n; ++i)
L[i] = make_tuple(
Rank[step - 1][i],
(i + length / 2 < n) ? Rank[step - 1][i + length / 2] : neginf,
i); // we need to know where the tuple came from later
sort(L, L + n); // lexicographical sort
for (int i = 0; i < n; ++i) {
// we save the rank of the index, but we need to be careful to
// assign equal ranks to equal pairs
Rank[step][get<2>(L[i])] = (i > 0 && get<0>(L[i]) == get<0>(L[i - 1])
&& get<1>(L[i]) == get<1>(L[i - 1]))
? Rank[step][get<2>(L[i - 1])]
: i;
}
}
// the suffix array is in L after the last step
for (int i = 0; i < n; ++i) {
int start = get<2>(L[i]);
cout << start << ":";
for (int j = start; j < n; ++j)
cout << " " << seq[j];
cout << endl;
}
}
Output:
6: 1
5: 2 1
4: 2 2 1
2: 2 4 2 2 1
1: 3 2 4 2 2 1
3: 4 2 2 1
0: 8 3 2 4 2 2 1
The complexity is O(log n * (n + sort)), which is O(n log² n) in this implementation because we use a comparison sort of complexity O(n log n)
A simple O(n log n) algorithm
If we manage to do the sorting parts in O(n) per step, we get a O(n log n) bound. So basically we have to sort a sequence of pairs (x, y), where 0 <= x, y < n. We know that we can sort a sequence of integers in the given range in O(n) time using counting sort. We can intepret our pairs (x, y) as numbers z = n * x + y in base n. We can now see how to use LSD radix sort to sort the pairs.
In practice, this means we sort the pairs by increasing y using counting sort, and then use counting sort again to sort by increasing x. Since counting sort is stable, this gives us the lexicographical order of our pairs in 2 * O(n) = O(n). The final complexity is thus O(n log n).
In case you are interested, you can find an O(n log² n) implementation of the approach at my Github repo. The implementation has 27 lines of code. Neat, ain't it?
This is exactly suffix array construction problem, and wiki page contains links to the linear-complexity algorithms (probably, depending on alphabet)
There is N number of sets, each containing various number of integers, e.g.:
(-2, -1, 0), (-1,4), (-2, 2, 3), (-3, -2, 4, 6), (-2)
How to pick exactly one number from each set so that these N integers sum to zero? For example:
-1, -1, 2, -2, 4, -2
Note there might be no solution or multiple (in which case it doesn't matter which one I choose).
I was thinking that I can do breath-first search but was wondering if there are any other, preferably faster, ways to solve this.
Let dp[i, j] = true iff we can make sum j using one number from each of the sets 1, 2, ..., i.
dp[i, 0] = true for all i
for i = 1 to numSets do
for num = 1 to sets[i].Count do
for j = maxSum - sets[i, num] downto -maxSum do
dp[i, j + sets[i, num]] |= dp[i - 1, j]
You can use a map to handle negative indexes or add an offset to make them positive. maxSum is the maximum value your sum can take (for example sum of maximums of all sets or sum of absolute values of minimums, whichever is larger). There might be ways to update maxSum as you go as an optimization.
For your example, this will run like so:
(-2, -1, 0), (-1,4), (-2, 2, 3), (-3, -2, 4, 6), (-2)
Iteration over the first set will give dp[1, -2] = dp[1, -1] = dp[1, 0] = true.
Iteration over the second will give dp[2, -3] = true (because dp[2, -2 + -1] |= dp[1, -1] = true), dp[2, -2] = true (because dp[2, -1 + -1] |= dp[1, -1] = true) etc.
If dp[numSets, 0] = true, there is a solution, which you can reconstruct by keeping tracking of which last number you picked for each dp[i, j].
The complexity is O(numSets * K * maxSum), where K is the number of elements of a set. This is pseudopolynomial. It might be fast enough if your values are small. If your values are large but you have few sets with few elements, you are better off bruteforcing it using backtracking.
This seems related to the subset sum problem: given a set n integers, is there a subset that sums to 0? That problem is known to be NP-complete and that, in short, means your chances are very small of finding a fast way of doing this.
For one set of integers it's hard enough and in your problem another constraint is added that one integer must be selected from each set. A search algorithm is indeed the way to go but in the worst case you won't be doing much better than an exhaustive search.