Min Path Sum in Matrix- Brute Force - ruby

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.

Related

How can I improve my "rotate (roll / cyclic permutation) array" solution?

I am doing some stuff on leetcode and came up with solution it works fine but some cases.
Here is the problem itself:
But in case like this it doesn't:
It doesn't make sense how can I rotate elements if k is bigger than length of array.
If you have any idea how to improve this solution I would be grateful
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
if len(nums) > k:
self.swap(nums, 0, len(nums)-1)
self.swap(nums, 0,k-1)
self.swap(nums, k, len(nums)-1)
def swap(self, nums, start, end):
while start < end:
nums[start], nums[end] = nums[end], nums[start]
start+=1
end-=1
In order to understand why this doesn't work for the cases where k is larger than the array length, let me try to explain some of the logic behind rotating by such values of k.
The modulo operator, % will be useful. For example, if an array is 5 long, and you want to rotate by 5, you end up with the same array. So technically, you'd optimally want to rotate by 0. This is where the % operator comes into play. 5 % 5 = 0. If we want to rotate an array length 5 by 7 spots, we would end up with the same thing as rotating the array by 2, and it turns out that 7 % 5 = 2. Do you see where I am going with this?
This also holds true if the value of k is less than the length of the array. Say we want to rotate an array length 5 by 3, we do 3 % 5 = 3.
So for any rotation of amount k and array length L, optimization rotation amount n is equivalent to n = k % L.
You should modify your code at the beginning of your rotate method to adjust the rotation amount:
k = k % L
and use this value to rotate the correct amount.
The fastest and cleanest solution by far and large is:
def rotate_right(items, shift):
shift = -shift % len(items)
return items[shift:] + items[:shift]
ll = [i + 1 for i in range(7)]
# [1, 2, 3, 4, 5, 6, 7]
rotate_right(ll, 3)
# [5, 6, 7, 1, 2, 3, 4]
rotate_right([1, 2], 3)
# [2, 1]
of course, short of using numpy.roll() or itertools.cycle().

Check whether 2 nodes have any common parent(s) in a DAG graph

The input is:
An int[][], each sub array contains 2 int as {parent, child}, means there is a path from parent -> child.
e.g
{ { 1, 3 }, { 2, 3 }, { 3, 6 }, { 5, 6 }, { 5, 7 }, { 4, 5 }, { 4, 8 }, { 8, 9 } };
Or as a tree structure:
1 2 4
\ / / \
3 5 8
\ / \ \
6 7 9
The task is:
Giving 2 value (x, y), return a boolean value, to indicate whether they have any common parent(s).
Sample input and output:
[3, 8] => false
[5, 8] => true
[6, 8] => true
My idea:
Represent the input data as a DAG graph, in which data are stored in a Map like this Map<Integer, LinkedList<Integer>>, where key is the vertex, value is its adjacency list. And the direction in graph is reversed (compared to input data) as child -> parent, so that easy to search for parent.
Use a function findAvailableParents(Integer vertex) to find all parents (direct and indirect) for a single vertex, and return Set<Integer>.
Thus, only need to call findAvailableParents() once for each input vertex, then compare whether the 2 returned Sets have any intersection. If yes, then they have common parent; otherwise, they don't.
My questions are:
The time complexity in the solution above is between O(1) ~ O(E), right? (E is edge counts in the graph)
Is there a better solution?
A modified BFS might help you to solve the problem
Algorithm: checkCommonParent
def checkCommonParent(G, v1, v2):
# Create a queues for levelorder traversal
q1 = []
# Mark all the vertices as not visited
# This will be used to cover all the parts of graph
visited = [False]*(len(G.Vertices))
for v in G.Vertices:
if visited[v] == False:
q1.append(v)
visited[v] = True
# Check a connected component and see if it has both vertices exists.
# If it exists, that means they have a common ancestor
v1Visited = False
v2Visited = False
while ((len(q1) > 0) or (len(q2) > 0)):
while len(q1) > 0:
curVertex = q1.popleft()
for adjV in curVertex.adjecentVertices:
if visited[adjV] == False:
q1.append(adjV)
visited[adjV] = True
if adjV == v1:
v1Visited = True
elif adjV == v2:
v2Visited = True
if v1Visited and v2Visited:
return True
return False
I guess the idea is clear on the modification of BFS. Hope it helps!
suppose you have multiple inputs, now BFS would take around O(E) time to process each input.
All inputs can be queried in O(logn) if we do some pre computation which should take about O(nlogn) time
basically you want to find what is the Least common ancestor of those nodes
this thread in topcoder discusses the logic for a tree which can be extended to a DAG
You can also refer to this question for some further ideas
If an LCA exists between 2 nodes, then they have a common parent

Breadth first search for an 8 puzzle

I was asked to implement a breadth first search for solving an eight-puzzle, representing each of its states with a vector with 9 elements, storing the tile number (or 0 for the gap) as the the data in the position.
For example [1, 3, 4, 2, 8, 0, 6, 7, 5] represents:
1 3 4
2 8 # <- Gap here
6 7 5
My pseudo-coded algorithm so far is:
startnode.configuration = start
startnode.parent = NIL
startnode.distance = 0
startnode.state = DISCOVERED
nodes_to_process = queue {}
nodes_to_process.enqueue(startnode)
while nodes_to_process is not empty
node = nodes_to_process.dequeue()
for each neighbour in NEIGHBOURS(node)
if neighbour.state == UNDISCOVERED
neighbour.distance = node.distance + 1
neighbour.parent = node
neighbour.state = DISCOVERED
The problem with this is: when I add a new neighbour how do I keep track of which nodes have been assigned as visited? Should I compare the state arrays one by one (preferaby having an ordered set of them), or is there a more refined approach, where I can skip this array-comparison step? Is the best algorithm complexity O(N * ln N) for the search?

Minimum number of special moves to sort number

Given the list of numbers
1 15 2 5 10
I need to obtain
1 2 5 10 15
The only operation I can do is "move the number X at position Y".
In the above example I only need to do "move the number 15 at position 5".
I would like to minimize the number of operations but I can't find/remember a classical algorithm for that, given the operation available.
Some background :
I'm interacting with an API for a kanban-like service.
I have about 600 cards and some actions on our bug-tracker can imply a reordering of these 600 cards in the kanban (multiple cards can move at the same time if the priority of a project is changed)
I can do it in 600 calls to the API but I'm trying to reduce that number as much as possible.
Lemma: The minimum number of (delete element, insert element) pairs you can perform to sort a list L (in increasing order) is:
Smin(L) = |L| - |LIC(L)|
Where LIC(L) is the Longest Increasing Subsequence.
Thus, you have to:
Establish the LIC of your list.
Remove the elements not in it and insert them back at the appropriate position (using binary search).
Proof:
By induction.
For a list of size 1, the longest increasing subsequence is of length... 1! The list is already sorted so the number of (del,ins) pairs required is
|L| - |LIC(L)| = 1 - 1 = 0
Now let Ln be a list of length n, 1 ≤ n. Let Ln+1 be the list obtained by adding an element en+1 to the left of Ln.
This element may or may not influence the Longest Increasing Subsequence. Let's try to see how...
Let in,1 and in,2 be the two first elements of LIC(Ln) (*):
If en+1 > in,2, then LIC(Ln+1) = LIC(Ln)
If en+1 ≤ in,1, then LIC(Ln+1) = en+1 || LIC(Ln)
Else, LIC(Ln+1) = LIC(Ln) - in,1 + en+1. We keep the LIC with the highest first element. This is done by removing in,1 from the LIC and replacing it with en+1.
In the first case, we delete en+1, we thus get to sort Ln. By the induction hypothesis, this require n (deletion, insertion) pairs. We then have to insert en+1 at the appropriate position. Thus:
S(Ln+1)min = 1 + S(Ln)min
S(Ln+1)min = 1 + n - |LIC(Ln)|
S(Ln+1)min = |Ln+1| - |LIC(Ln+1|
In the second case, we ignore en+1. We begin by deleting elements not in LIC(Ln). These elements have to be inserted again! There are
S(Ln)min = |Ln| - |LIC(Ln)|
such elements.
Now, we just have to take care and insert them in the right order (relatively to en+1). In the end, it requires:
S(Ln+1)min = |Ln| - |LIC(Ln)|
S(Ln+1)min = |Ln| + 1 - (|LIC(Ln)| + 1)
Since we have |LIC(Ln+1)| = |LIC(Ln)| + 1 and |Ln+1| = |Ln| + 1, we have in the end:
S(Ln+1)min = |Ln+1| - |LIC(Ln+1)|
The last case can be proved by considering the list L'n obtained by removing in,1 from Ln+1. In that case LIC(L'n) = LIC(Ln+1) and thus:
|LIC(L'n)| = |LIC(Ln)| (1)
From there, we can sort L'n (which takes |L'n| - |LIC(L'n| by the induction hypothesis. The previous equality (1) leads to the result.
(*): If LIC(Ln) < 2, then in,2 doesn't exist. Just ignore the comparisons with it. In that case, only case 2 and case 3 apply... The result is still valid
One possible solution is to find the longest increasing subsequence and move only elements that aren't inside it.
I can't prove it's optimal, but it is easy to prove it is correct and better than N swaps.
Here is a proof-of-concept in Python 2. I implemented it as a O(n2) algorithm, but I'm pretty sure it can be reduced to O(n log n).
from operator import itemgetter
def LIS(V):
T = [1]*(len(V))
P = [-1]*(len(V))
for i, v in enumerate(V):
for j in xrange(i-1, -1, -1):
if T[j]+1 > T[i] and V[j] <= V[i]:
T[i] = T[j] + 1
P[i] = j
i, _ = max(enumerate(T), key=itemgetter(1))
while i != -1:
yield i
i = P[i]
def complement(L, n):
for a, b in zip(L, L[1:]+[n]):
for i in range(a+1, b):
yield i
def find_moves(V):
n = len(V)
L = list(LIS(V))[::-1]
SV = sorted(range(n), key=lambda i:V[i])
moves = [(x, SV.index(x)) for x in complement(L, n)]
while len(moves):
a, b = moves.pop()
yield a, b
moves = [(x-(x>a)+(x>b), y) for x, y in moves]
def make_and_print_moves(V):
print 'Initial array:', V
for a, b in find_moves(V):
x = V.pop(a)
V.insert(b, x)
print 'Move {} to {}. Result: {}'.format(a, b, V)
print '***'
make_and_print_moves([1, 15, 2, 5, 10])
make_and_print_moves([4, 3, 2, 1])
make_and_print_moves([1, 2, 4, 3])
It outputs something like:
Initial array: [1, 15, 2, 5, 10]
Move 1 to 4. Result: [1, 2, 5, 10, 15]
***
Initial array: [4, 3, 2, 1]
Move 3 to 0. Result: [1, 4, 3, 2]
Move 3 to 1. Result: [1, 2, 4, 3]
Move 3 to 2. Result: [1, 2, 3, 4]
***
Initial array: [1, 2, 4, 3]
Move 3 to 2. Result: [1, 2, 3, 4]
***

Algorithm to find words spelled out by a number

I'm trying to find a way to determine all possible words that can be spelled out by a given number, given a mapping of alphabets to values.
I eventually want to find a solution that works for any 1- or 2- digit value mapping for a letter, but for illustration, assume A=1, B=2, ... Z=26.
Example: 12322 can be equal to abcbb (1,2,3,2,2), lcbb (12,3,2,2), awbb (1,23,2,2), abcv (1,2,3,22), awv (1,23,22), or lcv (12,3,22).
Here's what I have thought of so far:
I will build a tree of all possible words using the number.
To do this, I will start out with a tree with one root node with dummy data.
I will parse then the number digit-by-digit starting from the least significant digit.
At each step, I will take the last digit of the remaining part of the number and insert it into the left subtree of the current node, and remove that digit from the number for that node's left subtree. For the same node, I will then check if the previous TWO digits together form a valid alphabet, and if so, I will put them into the right subtree (and remove the 2 digits from the number for that node's right subtree).
I will then repeat the above steps recursively for each node, using the part of the number that's left, until there are no more digits left.
To illustrate, for 12322 my tree will look something like this:
*
/ \
/ \
2 22
/ / \
2 3 23
/ \ / \ /
3 23 2 12 1
/ \ / /
2 12 1 1
/
1
To get the words then, I will traverse all possible paths from the leaves to the nodes.
This seems to be an overly complex solution for what I thought would be a fairly simple problem, and I'm trying to find if there's a simpler way to solve this.
You need not actually construct a tree - just recurse:
Take a single digit. See if we can form a word considering it as a letter in itself, and recurse.
When we return from the recursion, try adding another digit (if we were 1 or 2 previously), and re-recursing.
Suppose you aleady have all the possible combination of [2, 3, 2, 2] ,what would be the combination of [1, 2, 3, 2, 2] (add [1] to the head)? It is not difficult the deduce it should be:
A1: put [1] to the head of all_the_combinations_of[1,2,3,2,2] and
A2: put [1*10 + 2] to the head of all_the_combinations_of[2,3,2,2] if [1*10 + 2 <=26]
Once we got this , the following should be easy. I implemented an Ruby version with the recusion trace for your reference.
def comb a
c = []
puts a.inspect
return [a] if a.length <= 1
c = comb(a[1..-1]).map {|e| [a[0]] + e}
if a[0] * 10 + a[1] <= 26
c += comb(a[2..-1]).map { |f| [a[0] * 10 + a[1]] + f }
end
c
end
h = Hash[*(1..26).to_a.zip(('A'..'Z').to_a).flatten]
#h.keys.sort.each {|k| puts "#{k}=>#{h[k]}"}
comb([1,2,3,2,2]).each do |comb|
puts comb.map {|k| h[k]}.join
end
[1, 2, 3, 2, 2]
A1 [2, 3, 2, 2]
[3, 2, 2]
[2, 2]
[2]
[]
[2, 2]
[2]
[]
A2 [3, 2, 2]
[2, 2]
[2]
[]
ABCBB
ABCV
AWBB
AWV
LCBB
LCV
A brute-force solution would be to dynamically fill the array from 1 to N, where a[i] element contains a set of strings that form a[1]a[2]a[3]...a[i] after expansion. You can fill a[1] from stratch, then fill a[2], based on a[1] set and second character in the string. Then you fill a[3], etc. At each sted you only have to look back to a[i-1] and a[i-2] (and to s[i-1] and s[i], where s is your number sequence).
Finally, after you fill a[n], it will contain the answer.
For the example '12322', the sequence becomes:
a[1] = { "a" }
a[2] = { a + 'b' | a in a[1] } union { "l" } = { "ab", "l" }
a[3] = { a + 'c' | a in a[2] } union { a + 'w' | a in a[1] } = { "abc", "lc", "aw" }
a[4] = { a + 'b' | a in a[3] } union { } = { "abcb", "lcb", "awb" }
a[5] = { a + 'b' | a in a[4] } union { a + 'v' | a in a[3] } = { "abcbb", "lcbb", "awbb", "abcv", "lcv", "awv" }
This is essentially the dynamic programming version of the recursive solution above.
An alternative way to do this would be to reverse the problem:
Given a dictionary of words, calculate the numeric strings that would be generated, and store this data into a map/dictionary structure, i.e. table['85'] = 'hi'
For each of the first x digits of the number you are looking up, see if it's in the table, i.e. table.ContainsKey('1'), table.ContainsKey('12'), ...
If you're trying to find the word sequences, generate the words that start at each location in the numeric string, and then do a recursive lookup to find all phrases from that.

Resources