How to find all possible unique paths in a grid? - algorithm

I have a 3 x 3 grid with randomly placed obstacles in which there is a random starting point but no endpoint. The endpoint is created when there are no more cells to occupy. Movement can occur up, down, left or right.
How can I see all possible unique paths within the grid?
Example:
Once a cell is used when looking for a path, it cannot be used again (1 becomes a 0).
If there are no more neighbouring cells to move into the path has ended. Regardless of weather all the cells have been visited.
# bottom left is (0, 0) and top right is (2, 2)...
# start is (1, 1) and obstacle is (2, 1)
[1] [1] [1]
[1] [S] [0]
[1] [1] [1]
S = starting point
0 = obstacle
1 = open cell
With the above example there would be 6 unique paths.
path_1 = (1, 2), (2, 2) # up, right
path_2 = (1, 0), (2, 0) # down, right
path_3 = (0, 1), (0, 2), (1, 2), (2, 2) # left, up, right, right
path_4 = (0, 1), (0, 0), (1, 0), (2, 0) # left, down, right, right
path_5 = (1, 2), (0, 2), (0, 1), (0, 0), (1, 0), (2, 0) # up, left, down, down, right, right
path_6 = (1, 0), (0, 0), (0, 1), (0, 2) (1, 2), (2, 2) # down, left, up, up, right, right

To get all the paths, you can use DFS or BFS but each path needs to have a unique visited set to keep track that you:
do not go back to the same coordinate twice in a single path
allow different paths to go on the same coordinate
I wrote a DFS implementation for a grid here and the solution will rely on this example.
Solution
To do graph search one would need to define the states, which are the coordinates in this case, but for this problem we will keep track of two parameters, for convenience:
The path taken will be documented via Crack code (right=0, down=1, left=2, up=3) which is a form of chain code
the visited set for each path will de documented for the reasons noted above
The implementation in Python is as follows (in my case the top left matches coordinate (0,0) and lower right matches (n-1,n-1) for nXn grid)
import collections
def find_paths(grid, start_coord):
paths = set() # paths will be added here
state_queue = collections.deque([]) # Pending states which have not been explored yet
# State is a tuple consists of:
# 1. current coordinate
# 2. crack code path
# 3. set of visited coordinates in that path
state = [start_coord, [], {start_coord}] # Starting state
while True:
# Getting all possible neighboring states
# Crack code (right=0, down=1, left=2, up=3)
state_right = [(state[0][0],state[0][1]+1), state[1] + [0], state[2].copy()] if state[0][1]+1 < len(grid[state[0][0]]) else None
state_down = [(state[0][0]+1,state[0][1]), state[1] + [1], state[2].copy()] if state[0][0]+1 < len(grid) else None
state_left = [(state[0][0],state[0][1]-1), state[1] + [2], state[2].copy()] if state[0][1]-1 >= 0 else None
state_up = [(state[0][0]-1,state[0][1]), state[1] + [3], state[2].copy()] if state[0][0]-1 >= 0 else None
# Adding to the queue all the unvisited states, as well as to the visited to avoid returning to states
blocked_counter = 0
for next_state in [state_right, state_down, state_left, state_up]:
if next_state is None:
blocked_counter += 1
elif next_state[0] in state[2] or grid[next_state[0][0]][next_state[0][1]] == 0:
blocked_counter += 1
else:
next_state[2].add(next_state[0])
state_queue.append(next_state)
# After checking all directions' if reached a 'dead end', adding this path to the path set
if blocked_counter == 4:
paths.add(tuple(state[1]))
# Popping next state from the queue and updating the path if needed
try:
state = state_queue.pop()
except IndexError:
break
return paths
Explanation
At the beginning we create the initial state, as well as the initial path which is an empty list and the visited set, containing only the start coordinate
For each state we are in we do the following:
2.1. create the four neighboring states (advancing right, up, left or down)
2.2. checking if we can advance in each direction by checking if the path we are in already visited this coordinate and if the coordinate is valid
2.3. if we can advance in the said direction, add this next_state to the state_queue as well as to the visited set of the path
2.4. if we can not advance in any of the four directions, we reached a 'dead end' and we add the path we are in to the paths set
2.5. pop the next state from state_queue which is kind of a bad name since it is a stack (due to the appending and popping from the same side of the deque()
When the state_queue is empty, we finished the search and we can return all the found paths
When running this with the given example, i.e.
start_coord = (1,1)
grid = [[1, 1, 1],
[1, 1, 0],
[1, 1, 1]]
We get:
find_paths(grid, start_coord)
# {(2, 3, 0, 0), (3, 2, 1, 1, 0, 0), (3, 0), (2, 1, 0, 0), (1, 0), (1, 2, 3, 3, 0, 0)}

This is actually not as difficult as it seems. Since it seems to me that you are learning, I avoid giving you code and will focus on the ideas.
The solution
Since you need to find all solutions, this is a classical backtracking problem. The idea of backtracking is to try out every possibility and store all the solutions. Particularities about your problem:
grid
movement
obstacles
unique solutions
How to check everything?
You need to loop your grid and for each point and for each point, starting from a depth of 0, you repeat the following:
if depth < available points map the possible moves (no obstacles, not visited) (1)
for each point:
increase depth with 1
mark the current point as visited
check whether there was a solution and handle it if so
with the current status, jump to (1)
unmark the current point from being visited
decrease depth by 1
Handling the solution
You need to have a unique, predictable signature for your solution, like the points you have moved to in their order and store all solutions you had so far. Before you enter your new solution, check whether it's already among the solutions and only append it if it's not there.
Pruning
You can prune your findings based on earlier findings, if the problem-space is big-enough to make this a performance optimization, but you should only consider that when you already have a solution.

I was looking to solve this with dynamic programming to avoid the exponential time complexity but failed to do so. However, here is a dense version in Javascript which uses DFS (which given this problem is the same as brute-forcing since we are interested in all possible paths) and recursion in a functional style with es6 features. We also make use of a single-dimension array to represent the board with the directions method accounting for which positions are reachable from a given position. The single-dimension array contains the rows of the board laid out sequentially from top to bottom.
[ 0 1 2 ]
[ 3 4 5 ] => [0, 1, 2, 3, 4, 5, 6, 7, 8]
[ 6 7 8 ]
The algorithm works for any m by n grid and so we must specify the width as an input parameter.
const directions = (pos, board, width) => {
const [n, s, w, e] = [pos - width, pos + width, pos - 1, pos + 1]
return [
n >= 0 && board[n] ? n : null,
s < board.length && board[s] ? s : null,
pos % width !== 0 && board[w] ? w : null,
e % width !== 0 && board[e] ? e : null
]
.filter(pos => pos !== null)
}
const solve = (pos, board, width, path) => {
const next = directions(pos, board, width)
return next.length === 0 ?
[[...path, pos]] // have a complete path
:
next
.map(nextPos => solve(nextPos, [...board.slice(0, pos), 0, ...board.slice(pos + 1)], width, [...path, pos]))
.flat()
}
const oneDim2TwoDim = (oneDimCoord, width) =>
[Math.floor(oneDimCoord / width), oneDimCoord % width]
const res = solve(4, [1, 1, 1, 1, 1, 0, 1, 1, 1], 3, [])
console.log(res.map(path => path.map(step => oneDim2TwoDim(step, 3))))
At each step, we check which directions are possible to go in. If no direction is available, we return the current path, otherwise we make a recursive call in each of the directions.
Use it like
solve(4, [1, 1, 1, 1, 1, 0, 1, 1, 1], 3, [])
/*
[
[ 4, 1, 0, 3, 6, 7, 8],
[ 4, 1, 2 ],
[ 4, 7, 6, 3, 0, 1, 2],
[ 4, 7, 8 ],
[ 4, 3, 0, 1, 2 ],
[ 4, 3, 6, 7, 8 ]
]
*/
Each path starts with the starting position and you can easily convert it back to (x, y) coordinate style with
const oneDim2TwoDim = (oneDimCoord, width) =>
[Math.floor(oneDimCoord / width), oneDimCoord % width]
const res = solve(4, [1, 1, 1, 1, 1, 0, 1, 1, 1], 3, [])
.map(path => path.map(step => oneDim2TwoDim(step, 3)))
/*
[
[ [ 1, 1 ], [ 0, 1 ], [ 0, 0 ], [ 1, 0 ], [ 2, 0 ], [ 2, 1 ], [ 2, 2 ] ],
[ [ 1, 1 ], [ 0, 1 ], [ 0, 2 ] ],
[ [ 1, 1 ], [ 2, 1 ], [ 2, 0 ], [ 1, 0 ], [ 0, 0 ], [ 0, 1 ], [ 0, 2 ] ],
[ [ 1, 1 ], [ 2, 1 ], [ 2, 2 ] ],
[ [ 1, 1 ], [ 1, 0 ], [ 0, 0 ], [ 0, 1 ], [ 0, 2 ] ],
[ [ 1, 1 ], [ 1, 0 ], [ 2, 0 ], [ 2, 1 ], [ 2, 2 ] ]
]
*/

Related

How to check if every element in a 2D Array are connected together

Question is in the title. I have a 2D array:
array = [
[0, 0, 1, 0, 1],
[0, 0, 1, 0, 1],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0]
]
How do I check to see if every element "1" in this example are all connected together as neighbors either laterally or horizontally. In this example the function should return TRUE since all of the 1's are all connected together. In contrast:
array = [
[0, 0, 0, 1, 1],
[0, 0, 0, 1, 1],
[0, 0, 0, 0, 0],
[1, 1, 0, 0, 0],
[1, 1, 0, 0, 0]
]
This should return FALSE, since their is a divide between the 1's and not all of them are neighbors.
My initial thought was to iterate through the array and check to see if any of the adjacent items were 1's or not. However, this doesn't work since two elements can be next to each other yet away from the rest of the group. Any help is greatly appreciated.
You can use BFS or DFS for that.
These are exploration algorithms that helps you to discover all nodes connected to your starting one.
The "trick" is to think of your matrix as a graph where:
V = { (i,j) | a[i][j] == 1} (informally, all locations where there is 1 in the matrix
E = { ((i1, j1), (i2, j2)) | (i1, j1), (i2, j2) are adjacent }
Then, just find a place where a[i][j] == 1, and start a BFS or DFS from it to disccover all reachable nodes.
Once you are done, iterate the matrix again, and see if each a[i][j] == 1 element was discovered.
Good luck!
The correct answer for this question is counting all the elements that are 1's then finding any element that is a '1' then using a flood fill algorithm that counts the amount of 1's. If the two values are equal then the answer is True if not then false.
https://en.wikipedia.org/wiki/Flood_fill

How I can find the next value? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Given an array of 0 and 1, e.g. array[] = {0, 1, 0, 0, 0, 1, ...}, how I can predict what the next value will be with the best possible accuracy?
What kind of methods are best suited for this kind of task?
The prediction method would depend on the interpretation of data.
However, it looks like in this particular case we can make some general assumptions that might justify use of certain machine learning techniques.
Values are generated one after another in chronological order
Values depend on some (possibly non-observable) external state. If the state repeats itself, so do the values.
This is a pretty common scenario in many machine learning contexts. One example is the prediction of stock prices based on history.
Now, to build the predictive model you'll need to define the training data set. Assume our model looks at the last k values. In case if k=1, we might end up with something similar to a Markov chain model.
Our training data set will consist of k-dimensional data points together with their respective dependent values. For example, suppose k=3 and we have the following input data
0,0,1,1,0,1,0,1,1,1,1,0,1,0,0,1...
We'll have the following training data:
(0,0,1) -> 1
(0,1,1) -> 0
(1,1,0) -> 1
(1,0,1) -> 0
(0,1,0) -> 1
(1,0,1) -> 1
(0,1,1) -> 1
(1,1,1) -> 1
(1,1,1) -> 0
(1,1,0) -> 1
(1,0,1) -> 0
(0,1,0) -> 0
(1,0,0) -> 1
Now, let's say you want to predict the next value in the sequence. The last 3 values are 0,0,1, so the model must predict the value of the function at (0,0,1), based on the training data.
A popular and relatively simple approach would be to use a multivariate linear regression on a k-dimensional data space. Alternatively, consider using a neural network if linear regression underfits the training data set.
You might need to try out different values of k and test against your validation set.
You could use a maximum likelihood estimator for the Bernoulli distribution. In essence you would:
look at all observed values and estimate parameter p
then use p to determine the next value
In Python this could look like this:
#!/usr/bin/env python
from __future__ import division
signal = [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0]
def maximum_likelihood(s, last=None):
"""
The maximum likelihood estimator selects the parameter value which gives
the observed data the largest possible probability.
http://mathworld.wolfram.com/MaximumLikelihood.html
If `last` is given, only use the last `n` values.
"""
if not last:
return sum(s) / len(s)
return sum(s[:-last]) / last
if __name__ == '__main__':
hits = []
print('p\tpredicted\tcorrect\tsignal')
print('-\t---------\t-------\t------')
for i in range(1, len(signal) - 1):
p = maximum_likelihood(signal[:i]) # p = maximum_likelihood(signal[:i], last=2)
prediction = int(p >= 0.5)
hits.append(prediction == signal[i])
print('%0.3f\t%s\t\t%s\t%s' % (
p, prediction, prediction == signal[i], signal[:i]))
print('accuracy: %0.3f' % (sum(hits) / len(hits)))
The output would like this:
# p predicted correct signal
# - --------- ------- ------
# 1.000 1 False [1]
# 0.500 1 True [1, 0]
# 0.667 1 True [1, 0, 1]
# 0.750 1 False [1, 0, 1, 1]
# 0.600 1 False [1, 0, 1, 1, 0]
# 0.500 1 True [1, 0, 1, 1, 0, 0]
# 0.571 1 False [1, 0, 1, 1, 0, 0, 1]
# 0.500 1 True [1, 0, 1, 1, 0, 0, 1, 0]
# 0.556 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1]
# 0.600 1 False [1, 0, 1, 1, 0, 0, 1, 0, 1, 1]
# 0.545 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0]
# 0.583 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1]
# 0.615 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]
# 0.643 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1]
# 0.667 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1]
# 0.688 1 False [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1]
# 0.647 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0]
# 0.667 1 False [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1]
# 0.632 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0]
# 0.650 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1]
# accuracy: 0.650
You could vary the window size for performance reasons or to favor recent events.
In above example, if we would estimate the the next value by looking only at the last 3 observed values, we could increase our accuracy to 0.7.
Update: Inspired by Narek's answer I added a logistic regression classifier example to the gist.
You can predict by calculating the probabilities of 0s and 1s and make their probability ranges and then draw a random number between 0 and 1 to predict.....
If these are series of numbers that are generated each time after some reset event, and next numbers are somehow related to previous ones, you could create a tree (binary tree with two branches at each node in your case) and feed in such historical series from the root, adjusting weights (say a count) on each branch you follow.
Could divide such counts by the number of series you entered before using them, or keep a number on each node too, increased before choosing a branch. That way root node contains number of series entered.
Then, as you feed it a new sequence you can see which branch is "hotter" (would make nice visualization as heatmap/tree btw) to follow, especially if sequence is long enough. That is, assuming order of items in sequence plays a role in what comes next.

Find the maximal k such that there exists a point covered by k intervals

Suppose that n closed intervals [a[i], b[i]] on the real line are given (i = 1..n). Find the maximal k such that there exists a point covered by k intervals (the maximal number of “layers”). The number of operations should be of order nlogn.
There is a solution about it.
[Hint. Sort all the left and right endpoints of the intervals together. While sorting, assume that the left endpoint precedes the right endpoint located at the same point of the real line. Then move from left to right counting the number of layers. When we cross the left endpoint, increase the number of layers by 1; when we cross the right endpoint, decrease the number of layers by 1. Please note that two adjacent intervals are processed correctly; that is, the left endpoint precedes the right endpoint according to our convention.]
My question is, how do I know if the point encountered is left endpoint or right endpoint? Do I need extra spaces to take record?
The question itself contains the steps of the expected algorithm, almost a pseudo-code.
I turned the description into a python 3 program as an excercise:
def prefix_sum(seq, acc = 0):
for i in seq:
acc += i
yield acc
def count_layers(intervals):
endpoints = sorted([(s, -1) for s,e in intervals] + [(e, +1) for s,e in intervals])
return -min(prefix_sum(delta for _,delta in endpoints))
print(count_layers([[2,3],[1,2]]))
Tested with:
def test(intervals):
print()
print('Test')
for s,e in intervals:
print(' ' * s + '-' * (e - s + 1))
print('Answer:', count_layers(intervals))
TEST_CASES = [
[ [ 1, 5], [ 4, 9], [ 2, 4], [ 6,12], ],
[ [ 1, 3], [ 3, 5], [ 7, 9], [ 5, 7], ],
[ [ 3, 4], [ 1, 2], ],
[ [ 2, 3], [ 1, 2], ],
]
for test_case in TEST_CASES:
test(test_case)

Finding a substring, with some additional conditions

I'm given a string which looks like this:
1011010100
And my task is to find the length of a substring which number of nulls is always <= number of ones. And this should always happen while 'scanning' substring from right to left and from left to right. So in this example, the answer would be:
10110101 => 8
I know that the complexity should be either O(n) or O(n log n), because length can reach up to 10^6
Any ideas?
The O(n) solution is quite simple actually, by building the "height array", representing the number of 1's relative to number of 0's. So a height of 2 means there are 2 more 1's than 0's. The we iterate over the height array once performing some maximality checking with some conditions.
Crucial Observation
Note that a subarray fulfilling the conditions must have its height minimum at the beginning, and maximum at the end (as relative to the subarray, not the whole array).
The height array for the sample in the question can be plotted like this, with marked answer:
v
/\/\/\
/\/ \
^
Proof:
Suppose the height is not minimum at the beginning, that means there is a point inside the subarray where the height is lower than the beginning. At this point, the number of 0 should be larger than the number of 1. Contradiction.
Suppose the height is not maximum at the end, that means there is a point in the subarray where the height is larger than the end, say at index j. Then at index j to the end there are more 0 than 1 (since the height decreases), and so when we "scan" the subarray from right to left we will find more 0 than 1 at index j. Contradiction.
Algorithm
Now the problem can be interpreted as finding the longest subarray which ends with the highest height in the subarray, while keeping the minimum to not exceed the height at the beginning. This is very similar to maximum subarray problem like mentioned by klrmlr ("contiguous subsequence of an array" is better said as "subarray"). And the idea is not keeping an O(n) state, but rather keeping the "maximum so far" and "maximum at this point".
Following that algorithm, below is the pseudocode, traversing the array once:
Procedure Balance_Left_Right
Record the lowest and highest point so far
If the height at this point is lower than the lowest point so far, then change the starting point to the index after this point
If the height at this point is higher or equal to the highest point so far, then this is a valid subarray, record the length (and start and end indices, if you like)
However we will soon see a problem (as pointed by Adam Jackson through personal communication) for this test case: 1100101, visualized as follows:
/\
/ \/\/
The correct answer is 3 (the last 101), but the above algorithm will get 2 (the first 11). This is because our answer is apparently hidden behind a "high mountain" (i.e., the lowest point in the answer is not lower than the mountain, and the highest point in the answer is not higher than the mountain).
And so we need to ensure that when we run the Procedure Balance_Left_Right (above), there is no "high mountain" hiding the answer. And so the solution is to traverse the array once from the right, try to partition the array into multiple sections where in each section, this property holds: "the number of 1's is always >= the number of 0's, as traversed from the right", and also for each section, it can't be extended to the left anymore.
Then, in each section, when traversed from the left, will have the maximum height at the end of the section, and this is the maximum. And it can be proven that with this property, the method balance_left_right will find the correct answer for this section. So, we just call our balance_left_right method on each section, and then take the maximum answer among those.
Now, you may ask, why it's sufficient to run Balance_Left_Right on each section? This is because the answer requires the property to hold from the left and from the right, and so it must lies inside one of the sections, since each of the section satisfies half of the property.
The algorithm is still O(n) because we only visit each element twice, once from the right, and once from the left.
The last test case will be partitioned as follows:
/|\ |
/ | \|/\/
** ***
where only the sections marked with asterisk (*) are taken.
So the new algorithm is as follows:
Procedure Max_Balance_Left_Right
Partition the input where the number of 1 >= number of 0 from the right (Using Balance_Left from the right, or can call it Balance_right)
Run Balance_Left_Right on each partition
Take the maximum
Here's the code in Python:
def balance_left_right(arr):
lower = 0
upper = -2**32
lower_idx = 0 # Optional
upper_idx = -1 # Optional
result = (0,0,0)
height = 0
length = 0
for idx, num in enumerate(arr):
length += 1
height += 1 if num==1 else -1
if height<lower:
lower = height # Reset the lowest
upper = height # Reset the highest
lower_idx = idx+1 # Optional, record the starting point
length = 0 # Reset the answer
if height>=upper:
upper = height
upper_idx = idx # Optional, record the end point
if length > result[0]: # Take maximum length
result = (length, lower_idx, upper_idx)
return result
def max_balance_left_right(arr):
all_partitions = []
start = 0
end = len(arr)
right_partitions = balance_left(reversed(arr[start:end]))
for right_start, right_end in right_partitions:
all_partitions.append((end-right_end, end-right_start))
result = (0,0,0)
for start, end in all_partitions:
candidate = balance_left_right(arr[start:end])
if result[0] < candidate[0]:
result = (candidate[0], candidate[1]+start, candidate[2]+start)
return result
def balance_left(arr):
lower = 0
start_idx = 0
end_idx = -1
height = 0
result = []
for idx, num in enumerate(arr):
height += 1 if num==1 else -1
if height < lower:
if end_idx != -1:
result.append((start_idx,end_idx))
lower = height
start_idx = idx+1
end_idx = -1
else:
end_idx = idx+1
if end_idx != -1:
result.append((start_idx, end_idx))
return result
test_cases = [
[1,0,1,1,0,1,0,1,0,0],
[0,0,1,0,1,0,0,1,0,1,0,0,1,1,0,1,0,1,0,0,1],
[1,1,1,0,0,0,1,0,0,1,1,0,1,1,0,1,1,0],
[1,1,0,0,1,0,1,0,1,1,0,0,1,0,0],
[1,1,0,0,1,0,1],
[1,1,1,1,1,0,0,0,1,0,1,0,1,1,0,0,1,0,0,1,0,1,1]
]
for test_case in test_cases:
print 'Balance left right:'
print test_case
print balance_left_right(test_case)
print 'Max balance left right:'
print test_case
print max_balance_left_right(test_case)
print
which will print:
Balance left right:
[1, 0, 1, 1, 0, 1, 0, 1, 0, 0]
(8, 0, 7)
Max balance left right:
[1, 0, 1, 1, 0, 1, 0, 1, 0, 0]
(8, 0, 7)
Balance left right:
[0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1]
(6, 12, 17)
Max balance left right:
[0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1]
(6, 12, 17)
Balance left right:
[1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0]
(8, 9, 16)
Max balance left right:
[1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0]
(8, 9, 16)
Balance left right:
[1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0]
(10, 0, 9)
Max balance left right:
[1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0]
(10, 0, 9)
Balance left right:
[1, 1, 0, 0, 1, 0, 1]
(2, 0, 1)
Max balance left right:
[1, 1, 0, 0, 1, 0, 1]
(3, 4, 6)
Balance left right:
[1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1]
(5, 0, 4)
Max balance left right:
[1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1]
(6, 8, 13)
For your eyes enjoyment, the height array for the test cases:
First:
v
/\/\/\
/\/ \
^
Second:
\
\/\/\ v
\/\/\ /\/\/\
\/ \/
^
Third:
v
/\ /\
/ \ /\/
/ \/\ /\/
\/
^
Fourth:
v
/\ /\
/ \/\/\/ \/\
^ \
Fifth:
/\ v
/ \/\/
^
Sixth:
/\ v
/ \ /\
/ \/\/\/ \/\ /
/ ^ \/\/
/
Clarification Regarding the Question
As some of the readers are confused on what exactly OP wants, although it's already stated clearly in the question, let me explain the question by some examples.
First, the task from the question:
And my task is to find the length of a substring which number of nulls is always <= number of ones. And this should always happen while 'scanning' substring from right to left and from left to right
This refers to something like "Catalan Number Ballot Problem" or "Available Change Problem". In the Wiki you can check the "monotonic path" problem, where you can map "move right" as "1" and "move up" as "0".
The problem is to find a subarray of the original array, such that, when the subarray is traversed from left-to-right and right-to-left, this property holds:
The number of 0's seen so far should not exceed the number of 1's seen so far.
For example, the string 1010 holds the property from left-to-right, because if we scan the array from left-to-right, there will always be more 1's than 0's. But the property doesn't hold from right-to-left, since the first character encountered from the right is 0, and so at the beginning we have more 0's (there is one) than 1's (there is none).
For example given by OP, we see that the answer for the string 1011010100 is the first eight characters, namely: 10110101. Why?
Ok, so when we traverse the subarray from left to right, we see that there is always more 1's than 0's. Let's check the number of 1's and 0's as we traverse the array from left-to-right:
1: num(0) = 0, num(1) = 1
0: num(0) = 1, num(1) = 1
1: num(0) = 1, num(1) = 2
1: num(0) = 1, num(1) = 3
0: num(0) = 2, num(1) = 3
1: num(0) = 2, num(1) = 4
0: num(0) = 3, num(1) = 4
1: num(0) = 3, num(1) = 5
We can see that at any point of time the number of 0's is always less than or equal to the number of 1's. That's why the property holds from left-to-right. And the same check can be done from right-to-left.
So why isn't 1011010100 and answer?
Let's see when we traverse the string right-to-left:
0: num(0) = 1, num(1) = 0
0: num(0) = 2, num(1) = 0
1: num(0) = 2, num(1) = 1
...
I didn't put the full traversal because the property has already been violated since the first step, since we have num(0) > num(1). That's why the string 1011010100 doesn't satisfy the constraints of the problem.
You can see also that my "height array" is actually the difference between the number of 1's and the number of 0's, namely: num(1) - num(0). So in order to have the property, we must have the [relative] height positive. That, can be visualized by having the height not less than the initial height.
Here goes my algorithm:
Start from right side:
1. if you find 0 increment the value of count
2. if you find 1 decrement the count
Store these values in an array i.e. v[].
e.g.
a[] = {1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1}
v[] = {0, 1, 0,-1, 0, 1, 0, 1, 2, 1, 2, 1, 0, -1}
Now the problem reduces to find indexes from V i.e. i, j such that v[i] < v[j] and i<j.
proof:
if you see here i=0 and j=11 is the possible answer and values are v[i]=0, v[j]=1.
This means that till j we have one 0 extra in the string and as the v[i]=0 that means from i to j window size the extra 0 is cancelled by putting extra 1. Hence the answer.
Hope it helps. please let me know if you have doubt. Thanks.
(Almost correct, i.e. subtly wrong) linear time solution
with two recodings of the problem (one removed later...), and a sliding window.
Encoding A
You can compress the input to yield the number of subsequent zeros or ones:
+1 -1 +2 -1 +1 -1 +1 -2
This yields encoding A and needs O(n) time.
Encoding B
Now, in encoding A, whenever you encounter two consecutive numbers that sum up to > 0, you compress further. In encoding B, the number in parentheses denotes the length of the substring:
+2(4) -1 +1 -1 +1 -2 ==> +2(6) -1 +1 -2 ==> +2(8) -2
This requires O(n), too. Here, we have the solution immediately: A string of length 8 with two more 1's than 0's. Let's try a more complicated instance (given in encoding A):
+5 -8 +4
Here, the transformation to encoding B doesn't help:
+5(5) -8 +4(4)
Consider also the following instance (encoding B):
+5(9) -6 +4(4) -6 +5(7) -6 +4(6) -6 +5(9)
This sequence will be used to demonstrate the...
Sliding window
First, determine the best solution that starts at the left:
+5 -6 +4 -6 +5 > 0 ==> 9+6+4+6+7=32
Now, extend this to find the best solution that starts at the third position (+4(4)):
+4 -6 +5 -6 +4 > 0 ==> 4+6+7+6+6=29
This solution is not better than the first we have found. Move on:
+5 -6 +4 -6 +5 > 0 ==> 7+6+6+6+9=34
This is the best solution. The algorithm can be implemented in O(n), since head and tail move only forward.
The brief description above doesn't cover all subtleties (negative number at the left in encoding B, head and tail meet, ...). Also, perhaps the recodings are unnecessary and the sliding window can be implemented directly on the 0-1 representation. However, I was able to fully understand the problem only after recoding it.
Getting rid of encoding B
Actually as kindly noted by Millie Smith, "encoding B" might be lossy, meaning that it might lead to inferior solutions in certain (yet to be identified) corner cases. But the sliding window algorithm works just as well on encoding A, so it might be even necessary to skip the conversion to encoding B. (Too lazy to rewrite the explanation of the algorithm...)

four in a row logic by creating AI

I am developing 4 in a row game. in this i am creating AI.
I have used same logic as Four in a row logic.
in my game 0 represents empty slot. 1 represents user slot and 2 for computer slot.
now i want to develop AI such that if user means '1' are three in a row then put 2 to its 4th row.
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 2, 2, 0, 0, 0],
[0, 1, 1, 1, 0, 0, 0]
i want to put 2 on last row 4th column after '1' like [0, 1, 1, 1, 2, 0, 0] and by creating AI then what to do?
The AI could be implemented by using the Minimax algorithm which can be found on Wikipedia under the following link:
http://en.wikipedia.org/wiki/Minimax
Basically, you need a function f to decide for a state of the game whether player 1 has won (value 1) or player 2 has won (value -1) or the game has not ended yet. If the game has not ended, all moves for the current player have to be evaluated by simulating them on the board and recursively calling F again, where the respective other player is active. The value of a possible move will be the maximum of the return values of F (if player 1 is the current player) or the minimum of the return values of F (if player 2 is the current player).
At least this is the rough idea; depending on the programming language used for implementation, the evaluation logic can be implemented independently from the specific game, such that the same code can play four-in-a-row or tic-tac-toe. Furthermore, evaluation can be stopped if a move of value 1 (for player 1) or -1 (for player 2) is found, which is also termed "pruning of the search tree".
use this part of code to prevent creating situations like 0,1,1,1,0 by user in all rows, it will return number of column that computer should play with that:
for(byte i=0;i<6;i++)
{
byte min = (byte) ((i * 7) + 1);
for(int j = 0;j<=2;j++) {
if (boardValues[min+j] == 1 && boardValues[min + j + 1] == 1 && boardValues[min - 1 + j] == 0 && boardValues[min +j + 2] == 0) {
if (i == 5) return (byte) ((min + j - 1)%7);
else if(boardValues[min - 1 + j + 7] != 0 && boardValues[min +j + 2 + 7] != 0)
return (byte) ((min + j - 1)%7);
}
}
}
boardValues is difined like this in my code:
public static byte[] boardValues = new byte[42];
It's maybe too late, but if someone is still interested to know, Here is a series of articles - http://blog.gamesolver.org/ .
It explains the concepts and logic, step by step to make a connect 4 resolver AI.

Resources