Finding a substring, with some additional conditions - algorithm

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...)

Related

Return maximum value of the integer at index k in array

This question was asked during Microsoft interview for intern position, I have no idea how to even approach this.
Array has n positive integers, sum of all elements in the array is at most max_sum, absolute difference between any two consecutive elements in the array is at most 1.
Return maximum value of the integer at index k in array.
Input : n = 3, max_sum = 7, k = 1
Output: 3
In this case let's say array is [2,3,2]
Input: n = 4, max_sum = 6, k = 2
output = 2
In this case let's say array is [1,1,2,1]
This is a brute-force approach. A better solution would be to calculate the values, but I'll leave it to you do figure that out. This is your challenge to get the job, right?
Input: n = 7, max_sum = 34, k = 4
Set all values to 0.
// ↓ k
array = { 0, 0, 0, 0, 0, 0, 0 }, sum = 0
Since we want maximum value at k, with lowest sum, just increment the value to 1.
// ↓ k
array = { 0, 0, 0, 0, 1, 0, 0 }, sum = 1 (+1)
Since consecutive elements must be at most 1 apart, when we increment value at k again, we need to increment the neighboring values too.
// ↓ k
array = { 0, 0, 0, 1, 2, 1, 0 }, sum = 4 (+3)
Repeat, repeatedly.
// ↓ k
array = { 0, 0, 1, 2, 3, 2, 1 }, sum = 9 (+5)
array = { 0, 1, 2, 3, 4, 3, 2 }, sum = 15 (+6)
array = { 1, 2, 3, 4, 5, 4, 3 }, sum = 22 (+7)
array = { 2, 3, 4, 5, 6, 5, 4 }, sum = 29 (+7)
We can't repeat again, because we'd get sum = 29 + 7 = 36 if we did, and that would exceed max_sum = 34.
Result: Max value at k is 6.
There are many ways to distribute the remaining 5 points, to get the exact sum, but showing a solution with the exact sum isn't the goal, so we don't need to do anything about the 5 extra points.
Let's define a as average array value:
a = max_sum / n
Let's find the maximum for k = 0:
max(0) = a + n/2
In this case, all other values of array would decrease, so the last value will be
a - n/2
for k = 1 we can see that maximum will not exceed max(0)-1, so
max(1) = a + n/2 - 1
and so on until k = n/2. for k > n/2 the max value will increase up to a + n/2 at k = n-1, so we have "V"-like curve with minimum at k=n/2, equal to a.
The only thing rest is to properly process border conditions, odd or even n and so on. I hope you got the idea.

Sort algorithms with time complexity in the order of number of elements [duplicate]

This question already has answers here:
How to sort a list with given range in O(n)
(4 answers)
Is there an O(n) integer sorting algorithm?
(6 answers)
Closed 5 years ago.
I am looking for an O(n) sort algorithm where n is the number of elements to sort. I know that highly optimized sorting algorithms are O(n log n) but I was told that under the following condition we can do better. The condition is:
We are sorting numbers in a small enough range, say 0 to 100.
Say we have the following
unsortedArray = [4, 3, 4, 2]
Here is the algorithm:
Step 1) Iterate over the unsortedArray and use each element as the index into a new array we call countingArray. The value we will hold in each position is the count of times that that number appears. Each time we access a position we increment it by 1.
countingArray = [0, 0, 0, 0, 0, ..., 0, 0, 0, 0] // before iteration
countingArray = [0, 0, 0, 0, 1, ..., 0, 0, 0, 0] // after handling 4
countingArray = [0, 0, 0, 1, 1, ..., 0, 0, 0, 0] // after handling 3
countingArray = [0, 0, 0, 1, 2, ..., 0, 0, 0, 0] // after the second 4
countingArray = [0, 0, 1, 1, 2, ..., 0, 0, 0, 0] // after handling 2
We can allocate countingArray in advance because the range of the numbers we wish to sort is limited and known a-priori. In your example countingArray will have 101 elements.
Time complexity of this step is O(n) because you are iterating over n elements from unsortedArray. Inserting them into countingArray has constant time complexity.
Step 2) As shown in the example above countingArray is going to have positions with value 0 where there were no numbers to count in unsortedArray. We are going to skip these positions in the following iteration we will describe.
In countingArray non-zero positions define a number that we want to sort, and the content in that position define the count of how many times that number should appear in the final sortedArray.
We iterate over countingArray and starting at the first position of sortedArray put that number into count number of adjacent positions. This builds sortedArray and takes O(n).
countingArray = [0, 0, 1, 1, 2, ..., 0, 0, 0, 0]
// After skipping the first 2 0s and seeing a count of 1 in position 2
sortedArray = [2, 0, 0, 0]
// After seeing a count of 1 in position 3
sortedArray = [2, 3, 0, 0]
// In position 4 we have a count of 2 so we fill 4 in 2 positions
sortedArray = [2, 3, 4, 4]
=======
Total time complexity is O(n) * 2 = O(n)

Algorithm for generating sequence denoting the sequence of removal of numbers

Given a finite sequence of numbers, in each round, any number whose left neighbour is smaller than itself will be removed. This removal action will continue until nothing can be removed. Each number removed will be labelled with the round it was removed, or 0 if it is never removed.
For example, consider the sequence
0 9 8 7 9 8 7 5
After first round, it becomes,
0 8 7 8 7 5
and after consecutive 4 rounds,
0 7 7 5
0 7 5
0 5
0
Thus the corresponding labels for the numbers are
0 1 2 3 1 2 4 5
How may I generate the sequence of labels in O(N) time by using a stack or queue, when N is the length of the sequence offered? Or may I know the maximum rounds of removing in O(N) time?
Yes it can be done using a single stack, I will describe the solution, and briefly explain why it works later.
Assume the array is A = [0, 9, 8, 7, 9, 8, 7, 5], Ans = [] be the array of corresponding answer. We also maintain an initially empty stack S. The stack will store pairs {A[i], Ans[i]} and we will try to preserve the stack so that it is always strictly increasing on A[i] as follows:
Push {A[0], 0} to S
Loop through array A. For an instance of iteration, let A[i] be current number (Ans[i] not known yet):
2a. Initialize a variable round_to_wait = 0, keep popping the stack S until the top element is smaller than A[i], set rount_to_wait to maximum Ans[x] meanwhile
2b. If the S is empty, then set Ans[i] = 0, else set Ans[i] = round_to_wait + 1
2c. Push {A[i], Ans[i]} to S
Let's do an demo based on your example:
A = [0, 9, 8, 7, 9, 8, 7, 5], Ans = [0, -1, -1, -1, -1, -1, -1, -1], S = [{0,0}]
A[1] = 9 and S.top() already smaller than 9, no element is popped. Ans[1] = round_to_wait + 1 = 0 + 1 = 1, push {9, 1} into S
A = [0, 9, 8, 7, 9, 8, 7, 5], Ans = [0, 1, -1, -1, -1, -1, -1, -1], S = [{0,0}, {9,1}]
A[2] = 8 and we popped element until {0,0} is left. rount_to_wait = 1 as it is the maximum in whole popping process. Ans[2] = round_to_wait + 1 = 1 + 1 = 2, push {8, 2} into S
A = [0, 9, 8, 7, 9, 8, 7, 5], Ans = [0, 1, 2, -1, -1, -1, -1, -1], S = [{0,0}, {8,2}]
Similarly, S = [{0,0}, {7,3}]
Similarly, S = [{0,0}, {7,3}, {9,1}]
Similarly, S = [{0,0}, {7,3}, {8,2}]
Similarly, S = [{0,0}, {7,4}]
Similarly, S = [{0,0}, {5,5}]
And that's it, you have the answer in one loop. As each element at most be pushed and popped one time, the complexity is still O(N)
Why it works is because, Let A[i] be the first element which does not form strictly increasing sequence with S, what does that mean?
That means that, at some point, the top element in S S_top will "block" us from removing A[i]. We have chances (not sufficient condition though) to remove A[i] only if S_top is removed, which means it is at least as soon as Ans[S_top] + 1, and we take the maximum among all such elements.
The special case is that, there is no element smaller than A[i] at all, which means S will eventually be empty, in such case Ans[i] = 0
(PS: I thought I have some memory on this problem on some online judge a few years ago, if that's the source, may you post it out so that I can go and submit to verify the solution?)

Mark M cells on a NxN board randomly with equal probability [duplicate]

This question already has answers here:
Algorithm to select a single, random combination of values?
(7 answers)
Closed 8 years ago.
An interview question:
Given a NxN board with all cells set to 0, mark M (M < NxN) cells to 1. The M cells should be chosen from all cells with equal probability.
E.g. Mark 30 cells in a 10x10 board, then the probability for a cell to be chosen is 0.3.
My idea is to iterate all cells and on each cell compute a random number in range [1-100], mark the cell to 1 if the number is less than or equal to 30.
The interviewer is not impressed by this solution. Any good idea? (You can use any language)
Put 70 zeros (NxN - M) and 30 ones (M) into a vector. Shuffle the vector. Iterate through and map each index k to 2-d indices via i = k / 10 and j = k % 10 for your example (use N as the divisor more generally).
ADDENDUM
After checking out #candu's link, I decided to give that approach a try. Here's an implementation in Ruby:
require 'set'
# implementation of Floyd's uniform subset algorithm for
# values in the range [0,n).
def generateMfromN(m, n)
s = Set.new
((n-m)...n).each {|j| s.add?(rand(j+1)) || s.add(j)}
s.to_a
end
#initialize a 10x10 array of zeros
a = Array.new(10)
10.times {|i| a[i] = Array.new(10,0)}
# create an array of 10 random indices between 0 and 99,
# map each index to 2-d indices, and set the corresponing
# element to 1.
generateMfromN(10,100).each {|index| a[index/10][index%10] = 1}
# show the results
a.each {|v| puts v.to_s}
This produces results such as...
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 1, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
and appears to require only O(M) work for Floyd's algorithm, since on each of M iterations an element always gets added to the set.
If M is bigger than N*N/2, initialize the array with 1's and randomize placement of zeros instead, as suggested by #btilly.
This can be done in expected running time O(m).
First let's deal with the case where we need at most half the board. So m <= n*n/2. For this case we can keep choosing random points and changing their values, throwing away and we chose before, until we have m of them. The probability of throwing away the next random choice is never more than half, so the number of random choices needed is at worst 2 m = O(m).
In the case where we need more than half the board, it takes time O(m) to flip every cell to 1, and then we use the previous solution to find n*n - m cells to turn back to 0.

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