Find number of ‘+’ formed by all ones in a binary matrix - python-3.x

The question I have is similar to the problem found here: https://www.geeksforgeeks.org/find-size-of-the-largest-formed-by-all-ones-in-a-binary-matrix/
The difference is the '+' must have all other cells in the matrix to be zeros. For example:
00100
00100
11111
00100
00100
This will be a 5x5 matrix with 2 '+', one inside another.
Another example:
00010000
00010000
00010000
11111111
00010000
00010010
00010111
00010010
This matrix is 8x8, and will have 3 '+', one of it is the small 3x3 matrix in the bottom right, and the other 2 is formed from the 5x5 matrix, one inside another, similar to the first example.
Using the code from the link above, I can only get so far:
M = [[0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 0, 1, 0, 1, 1, 1], [0, 0, 0, 1, 0, 0, 1, 0]]
R = len(M)
N = len(M)
C = len(M[0])
left = [[0 for k in range(C)] for l in range(R)]
right = [[0 for k in range(C)] for l in range(R)]
top = [[0 for k in range(C)] for l in range(R)]
bottom = [[0 for k in range(C)] for l in range(R)]
for i in range(R):
top[0][i] = M[0][i]
bottom[N - 1][i] = M[N - 1][i]
left[i][0] = M[i][0]
right[i][N - 1] = M[i][N - 1]
for i in range(R):
for j in range(1,R):
if M[i][j] == 1:
left[i][j] = left[i][j - 1] + 1
else:
left[i][j] = 1
if (M[j][i] == 1):
top[j][i] = top[j - 1][i] + 1
else:
top[j][i] = 0
j = N - 1 - j
if (M[j][i] == 1):
bottom[j][i] = bottom[j + 1][i] + 1
else:
bottom[j][i] = 0
if (M[i][j] == 1):
right[i][j] = right[i][j + 1] + 1
else:
right[i][j] = 0
j = N - 1 - j
n = 0
for i in range(N):
for j in range(N):
length = min(top[i][j], bottom[i][j], left[i][j], right[i][j])
if length > n:
n = length
print(n)
Currently, it returns the output of the longest side of the '+'. The desired output would be the number of '+' in the square matrix.
I am having trouble checking for all other cells in the matrix to be zeros, and finding a separate '+' if there is one in the entire matrix.
Any help is greatly appreciated.

I don't want to spoil the fun of solving this problem, so rather than a solution, here are some hints:
Try to write a sub-routine (a function), that given a square matrix as input, decides whether this input matrix is a '+' or not (say the function returns a '1' if it is a '+' and a '0' otherwise).
Modify the function from 1. so that you can give it as input a submatrix of the full matrix (in which you want to count '+'). More specifically, the input could be the coordinate of the upper left entry of the submatrix and its size. The return value should be the same as for 1.
Can you write a loop that examines all the submatrices of your given matrix and counts the ones that are '+' using the function from 2.?
Here are some minor remarks: The algorithm that this leads to runs in polynomial time (in the dimension of the input matrix), so basically it shouldn't take to long.
I haven't thought about it too much, but probably the algorithm can be made more efficient.
Also, you should maybe think about whether or not you count a '1' that is surrounded by '0's as a '+' or not.

Related

Generate all n-bit binary bit patterns in order of their sum

I need a generator that yields every bit pattern of n bits in order of their sum (and more). For example for n=3,
1. sum([0, 0, 0]) = 0 ✓
2. sum([1, 0, 0]) = 1 ✓
3. sum([0, 1, 0]) = 1 ✓
4. sum([1, 1, 0]) = 2 ⨯ should be swapped with 5.
5. sum([0, 0, 1]) = 1 ⨯
6. sum([1, 0, 1]) = 2 ✓
7. sum([0, 1, 1]) = 2 ✓
8. sum([1, 1, 1]) = 3 ✓
Note that even though 3 and 5 have the same sum, 5 should be generated after 3. The correct order would have been, 000, 100, 010, 001, 110, 101, 011, 111. The idea here is that if this (2ⁿ, n) dimension matrix was multiplied by a (n, 1) vector that is sorted in ascending order than the product would be sorted as well. Eliminating the need to sort this product will help in optimising an experiment I am trying to run.
Here is my rather inefficient and incomplete attempt,
def forwards(n):
ls = [0]*n
for i in range(n):
for j in range(n-i):
copy = list(ls)
copy[j] = 1
yield copy
ls[-(i+1)] = 1
As you can see, this does get the order right but misses some patterns.
Here is another somewhat efficient but wrong order attempt.
def forwards(n):
for i in range(1 << n):
yield [(i >> k) & 1 for k in range(n)]
This one generates all patterns but in the wrong (shown in the example above) order.
I need this function to be efficient so solutions where a string is generated and then characters are converted to integers are discouraged.
Lastly, I am working in Python 3.9. You can use Numpy.
I believe this gives you the order you want:
First, sort in ascending order by number of 1's
Next, sort in descending order by lexicographical order
from itertools import combinations
def forwards(n):
for one_bits in range(n + 1):
for combination in combinations(range(n), one_bits):
yield [1 if x in combination else 0 for x in range(n)]
for x in forwards(4):
print("{}, one bits = {}, binary value = {}".format(x, sum(x), sum(x[i] * 2**(3 - i) for i in range(4))))
This works by handling the first condition in the first for loop for one_bits in range(n + 1):, and generating all possible N-sized combinations of indices between 0 and n - 1, and then those indices are set to 1, else 0.
This prints
[0, 0, 0, 0], one bits = 0, binary value = 0
[1, 0, 0, 0], one bits = 1, binary value = 8
[0, 1, 0, 0], one bits = 1, binary value = 4
[0, 0, 1, 0], one bits = 1, binary value = 2
[0, 0, 0, 1], one bits = 1, binary value = 1
[1, 1, 0, 0], one bits = 2, binary value = 12
[1, 0, 1, 0], one bits = 2, binary value = 10
[1, 0, 0, 1], one bits = 2, binary value = 9
[0, 1, 1, 0], one bits = 2, binary value = 6
[0, 1, 0, 1], one bits = 2, binary value = 5
[0, 0, 1, 1], one bits = 2, binary value = 3
[1, 1, 1, 0], one bits = 3, binary value = 14
[1, 1, 0, 1], one bits = 3, binary value = 13
[1, 0, 1, 1], one bits = 3, binary value = 11
[0, 1, 1, 1], one bits = 3, binary value = 7
[1, 1, 1, 1], one bits = 4, binary value = 15

Finding maximal submatrix of all 1's - missing argument error

Program that finds the maximal rectangle containing only 1's of a binary matrix with the maximal histogram problem.
I am trying to do some tests on a code
def maximalRectangle(self, matrix):
if not matrix or not matrix[0]:
return 0
n = len(matrix[0])
height = [0] * (n + 1)
ans = 0
for row in matrix:
for i in range(n):
height[i] = height[i] + 1 if row[i] == '1' else 0
stack = [-1]
for i in range(n + 1):
while height[i] < height[stack[-1]]:
h = height[stack.pop()]
w = i - 1 - stack[-1]
ans = max(ans, h * w)
stack.append(i)
return ans
# Driver Code
if __name__ == '__main__':
matrix = [[0, 1, 0, 1],
[0, 1, 0, 1],
[0, 1, 1, 1],
[1, 1, 1, 1]]
print(maximalRectangle(matrix))
I get TypeError: maximalRectangle() missing 1 required positional argument: 'matrix' error
Solved by removing self and changing the print statement to:
print(maximalRectangle([
["1","0","1","0","0"],
["1","1","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]]))

calculate the sum of the intervals based on the binary array

I have two matrix:
Binary A = [[1, 0, 1, 0], [0, 0, 1, 0]];
Matrix of values B = [[100, 200, 300, 400], [400, 300, 100, 200]];
I want to calculate the sum of the intervals that are formed by the rows of the matrix A. For my exmpl. result will be follow: R = [[300, 0, 700, 0], [0, 0, 300, 0]] (generally, it is not necessary to set zeros [[300, 700], [300]] - it's right solution too)
I already wrote the code, but very very terrible (although it works correctly)
def find_halfsum(row1, row2):
i = 0
result = []
count = 0
for j in range(len(row1)):
if row1[j] == 1 and count == 0:
i = j
count += 1
elif row1[j] == 1:
count += 1
if count == 2:
if j == i + 1:
result.append(row2[i])
else:
result.append(sum(row2[i:j]))
i = j
count = 1
if j == len(row1) - 1:
result.append(sum(row2[i:j + 1]))
return result
Someone knows beautiful solutions (which will be faster)(preferably with the help of a numpy)?
Thanks
Not familiar with python, but I don't think you need that many lines
define halfSum(matrixA, matrixB):
sum = 0;
for i in range(len(matrixA)):
if matrixA[i] == 1:
sum += matrixB[i]
return sum;
You can use numpy.add.reduceat:
>>> A = np.array([[1, 0, 1, 0], [0, 0, 1, 0]])
>>> B = np.array([[100, 200, 300, 400], [400, 300, 100, 200]])
>>>
>>> [np.add.reduceat(b, np.flatnonzero(a)) for a, b in zip(A, B)]
[array([300, 700]), array([300])]

Dynamic Programming: Tabulation of a Recursive Relation

The following recursive relation solves a variation of the coin exchange problem. Count the number of ways in which we can sum to a required value, while keeping the number of summands even:
def count_even(coins, num_coins, req_sum, parity):
if req_sum < 0:
return 0
if req_sum == 0 and not parity:
return 1
if req_sum == 0 and parity:
return 0
if num_coins == 0:
return 0
count_wout_high_coin = count_even(coins, num_coins - 1, req_sum, parity)
count_with_high_coin = count_even(coins, num_coins, req_sum - coins[num_coins - 1], not parity)
return count_wout_high_coin + count_with_high_coin
This code would yield the required solution if called with parity = False.
I am having issues implementing a tabulation technique to optimize this algorithm. On a first attempt I tried to follow the same pattern as for other DP problems, and took the parity as another parameter to the problem, so I coded this triple loop:
def count_even_tabulation(S, m, n):
if m <= 0 or n < 0:
return 0
if n == 0:
return 1
table = [[[0 for x in range(m)] for x in range(n + 1)] for x in range(2)]
for j in range(m):
table[0][0][j] = 1
table[1][0][j] = 0
for p in range(2):
for i in range(1, n + 1):
for j in range(m):
y = table[p][i][j - 1] if j >= 1 else 0
x = table[1 - p][i - S[j]][j] if i - S[j] >= 0 else 0
table[p][i][j] = x + y
return table[0][n][m - 1]
However, this approach is not creating the right tables for parity equal to 0 and equal to 1:
[1, 1, 1]
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
[1, 1, 1]
[0, 1, 1]
[0, 0, 1]
[0, 0, 0]
How can I adequately implement a tabulation approach for the given recursion relation?

2D List having unequal row/column lengths specified from list

num_row = 3
num_col = [2, 4, 8]
# columns, row
list_2d = [[0 for i in range(num_row)] for j in num_col]
#list_2d = [[0 for i in range(num_row)] for j in num_col[:]] # SyntaxError: invalid syntax
#list_2d = [[0 for i in range(num_row)] for num_col[:]] #SyntaxError: invalid syntax
#list_2d = [[0 for i in range(num_row)] for j in num_col[j]] #IndexError: list index out of range
print('\nlist_2d:')
for i in list_2d:
print(i)
print('\nnum_col:')
for j in num_col[:]:
print(j)
My goal is to declare/initialize a list of list where the number of row elements is provided by an array (i.e., the first element of the array gives the number of columns in the first row, the second element of the array gives the number of columns in the second row, etc.). For the life of me, I cannot figure out how to accomplish this.
What I get:
list_2d:
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
num_col:
2
4
8
What I want:
[0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
[[0 for i in range(j)] for j in num_col]
num_row will always be three, you want to use j instead
Another way would be to use *. Here's an example
>>> [0]*10
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Applying the same, you could also do this as follows:
num_col = [2,4,8]
result = [[0]*j for j in num_col]

Resources