Kadane's Algorithm for 2D array with known boundaries - python

I have implemented the Kadane's algorithm for a 2D array in Python 2 with known boundaries, but I'm using the implementation for an online contest and the time it takes is more than the time given.
So that made me think if there is maybe another algorithm similar to Kadane's that has a smaller complexity, or if my code can be optimized in a way. My implementation works for any array with dimensions N x M and a subarray with dimensions maxRows x maxCols.
maxSumSubarray.py
import numpy as np
# returns the maximum sum for the given vector using kadane's algorithm, with
# maxRows maximum members in the sum
def kadane1DwithBounds(maxRows):
global temp
m = s = sum(temp[i] for i in xrange(maxRows))
k = 0
for i in xrange(1, N - maxRows + 1):
s -= temp[k]
s += temp[maxRows + i - 1]
k += 1
m = max(m, s)
return m
# prints the maximum "area" given by the values of an NxM array inside a
# subarray with dimensions maxRows x maxCols. temp holds the latest vector to be
# given to kadane1DwithBounds()
def kadane2DwithBounds(maxRows, maxCols):
global temp
for i in xrange(N):
temp[i] = sum(table[i][j] for j in xrange(maxCols))
m = kadane1DwithBounds(maxRows)
k = 0
for j in xrange(1, M - maxCols + 1):
for i in xrange(N):
temp[i] -= table[i][k]
temp[i] += table[i][maxCols + j - 1]
k += 1
m = max(m, kadane1DwithBounds(maxRows))
print m
line = map(int, raw_input().split())
N = line[0]
M = line[1]
maxRows = line[2]
maxCols = line[3]
table = []
temp = np.empty(N, dtype = int)
for _ in xrange(N):
table.append(map(int, raw_input().split()))
kadane2DwithBounds(maxRows, maxCols)
test.txt
4 8 2 3
1 1 2 3 3 1 1 1
2 2 2 2 2 2 2 2
3 3 3 1 1 3 3 4
0 0 1 1 3 2 2 1
Run with
python maxSumSubarray.py < test.txt
it gives
16
which is correct and is the following rectangle:
2 2 2
3 3 4
I've tried with other dimensions too and I'm pretty sure it works fine. Only problem is time/complexity. Any help would be appreciated! Thanks for your time.

Related

How to find figures with even areas

We have shape with n angles and its coordinates. I need to divide that figure into 2 figures with the same area. Division is performed in parallel to the axis y. The task is to find such x-coordinate, which would comply with the terms.
Test,E.g
4 (n angles)
0 0
0 2
2 2
2 0
The output must be 1
I wrote
n = int(input())
coordinates = []
for i in range(n):
x,y = map(int,input().split())
coordinates.append([x,y])
s = 0
for i in range(len(coordinates)-1):
s += coordinates[i][0]*coordinates[i+1][1]
s -= coordinates[i][1]*coordinates[i+1][0]
s = s/2
x = 0
print(s)
And after that I don't have any ideas what to do next..

How can I recursively divide the grid in my maze?

I am trying to create a maze generator using recursive division. I use this link:
Maze generation - recursive division (how it works?) as my guide as to how to approach the problem.
Here is my code so far:
import random
# Maze: 0 - N : 4 x 4 Grid
# Grid: 0 - (2n + 1) : 9 x 9 Array
# TODO: Now, Find a way to save the previous walls and not just only one at a time
rows = 9
cols = 9
start = 2
end = 7
# -------------------------------------------------------------------------------------
# Lists for all even / odd numbers in given range
evens = [n for n in range(start, end+1) if n % 2 == 0]
odds = [m for m in range(start, end+1) if m % 2 != 0]
# Generate random even/odd integer value for walls/ passages respectively
# Walls: Not sure if 2 variables are necessary-----------------------------------------
wallX = random.choice(evens)
wallY = random.choice(evens)
# Passages
passageX = random.choice(odds)
passageY = random.choice(odds)
#--------------------------------------------------------------------------------------
# Random direction: True = Horizontal Slice, False = Vertical Slice
randomDirection = random.choice([True, False])
arr = [['0' for i in range(cols)] for j in range(rows)]
def displayBoard(arr):
print()
for i in range(len(arr)):
for j in range(len(arr[i])):
# Print just the edges
if i == 0 or i == 8 or j == 0 or j == 8:
print('*', end = ' ')
# Print wall
elif arr[i][j] == 1:
print('.', end = ' ')
else:
print (' ', end = ' ')
print()
# Function choose direction to slice
def chooseDir(arr):
for i in range(len(arr)):
for j in range(len(arr[i])):
# Horizontal Direction Slice
if randomDirection:
arr[wallX][j] = 1
arr[wallX][passageY] = 2
print(arr[i][j], end = ' ')
# Vertical Slice
else:
arr[i][wallY] = 1
arr[passageX][wallY] = 2
print(arr[i][j], end = ' ')
print()
displayBoard(arr)
print()
mazeX = 0
mazeY = 0
# Write the recursive division function:
def divide():
chooseDir(arr)
print()
divide()
What this produces is a grid that is randomly sliced at an even index (creating walls) and creates passages at odd indices.
Output: 1 = wall, 2 = passage made
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 2 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0
* * * * * * * * *
* . *
* . *
* *
* . *
* . *
* . *
* . *
* * * * * * * * *
My issue is that I don't know how to write my recursive function. Do I call division on the two new cells created when a wall is made and continuously divide the "sub cells".
Or I know that a 4 x 4 cell grid will provide an array of 9 x 9 and I will have 16 cells total.
Then I can call division until a certain condition is met, increment to the next cell until all 16 were visited.
In both cases, I am not sure how to represent the new walls/cells created so that I can write the division function. Up until now, I've been using the grid coordinates.
You asked "Do I call division on the two new cells created when a wall is made and continuously divide the "sub cells"". Yes, that is the essence of recursion. Take a big problem and make smaller problem(s). Repeat with the smaller problems. Eventually, the problems are small enough to easily solve. Then put all the small problems back together to solve the original problem.
For the maze, the first wall split the maze into two smaller mazes. Use the same algorithm to split each of them and there are not 4 smaller mazes. Repeat until the sub-mazes are too small to split any more.
Your code that splits the maze should go in a function. If the sub-maze is big enough to split, the function splits the sub-maze and then calls itself on the two smaller sub-mazes.

Returning the product of numbers betweeen max and min in list, and simplify the loop

I have some array elements which were separated by a space,
for ex: -7 5 -1 3 9, 3 14 -9 4 -5 1 -12 4, -5 1 2 3 4 5 6 7 8 -3.
The task was to find the product of numbers which are located between maximum and minimum of them. And I made something to calculate it
n = "-7 5 -1 3 9"
t = [int(i) for i in n.split()] # transform to list
if t.index(max(t)) < t.index(min(t)): # loop to cut numbers which are not
for i in range(len(t)): # between our max and min numberes in list
if t.index(max(t)) > i:
t.pop(i)
for i in range(len(t)):
if t.index(min(t)) < i:
t.pop(i)
elif t.index(min(t)) < t.index(max(t)):
for i in range(len(t)):
if t.index(min(t)) > i:
t.pop(i)
for i in range(len(t)):
if t.index(max(t)) < i:
t.pop(i)
t.pop(t.index(min(t)))
t.pop(t.index(max(t)))
def product(list): # fuction to return product of a list
p = 1
for i in list:
p *= i
return p
print(product(t)) # and print it
It looks a little cumbersome, and I have similar problem, is there any way to simplify that loop. Thank you in advance for your attention.
If you are open to using NumPy, you can solve the problem in literally two lines of code:
import numpy as np
n="-5 1 2 3 4 5 6 7 8 -3"
t = [int(i) for i in n.split()]
t = np.array(t) # Convert the list to a numpy array
t[t.argmin() : t.argmax() + 1].prod() # Get the range and the product
If you have more than one max element and want to go as far as the right-most of them, the code can be modified accordingly:
t[t.argmin() : t.size - t[::-1].argmax()].prod()
You could try something like this
n = "-7 5 -1 3 9"
n_list = n.split(" ")
n_list = list(map(int, n_list)) #In case of python3 use -- n_list = map(int, n_list)
max = max(n_list)
min = min(n_list)
result = 1
for i in range(len(n_list)):
if n_list[i] > min and n_list[i] < max:
result = result * n_list[i]
print(result);
I created a generator, which takes one argument, an iterable and yields values that are within range of min, max of this iterable. The product is computed as usual:
from itertools import chain
def values(iterable):
lst = list(int(i) for i in chain.from_iterable(i.split() for i in n))
_min, _max = min(lst), max(lst)
for i in lst:
if _min < i < _max:
yield i
n = ['7 5 -1 3 9', '3 14 -9 4 -5 1 -12 4', '-5 1 2 3 4 5 6 7 8 -3']
p = 1
for i in values(n):
p *= i
print(p)
Output:
-1234517760000

Find all paths of length 2 in a graph

I've tried to create an algorithm for finding all paths of length 2, but it doesn't seem to work properly:
input_split = input().split(' ')
node_count = int(input_split[0])
input_count = int(input_split[1])
items = np.zeros((node_count, node_count), dtype=np.int32) # matrix of adjacency
for j in range(input_count):
split = input().split(' ')
x = int(split[0]) - 1 # convert 1 based coordinates to 0 based
y = int(split[1]) - 1
items[x][y] = 1
items[y][x] = 1
result = np.linalg.matrix_power(items, 2)
result_sum = int(np.sum(result) / 2) # reverse paths are counted only once
print(result_sum)
Sample input:
6 7
1 2
2 3
3 1
2 4
4 5
5 6
6 2
The result should be 11, but it prints 18.
You're on the right track when calculating the square of the adjacency matrix. After the exponentiation you would get result matrix that looks like this:
[[2 1 1 1 0 1]
[1 4 1 0 2 0]
[1 1 2 1 0 1]
[1 0 1 2 0 2]
[0 2 0 0 2 0]
[1 0 1 2 0 2]]
First you need to exclude all diagonal entries from this matrix, because those denote walks that are not paths, as their starting and ending node is the same. Note that for length 2 that is the only way how nodes can be repeating.
The other entries need to be counted only once, because of symmetry. So only look at the upper right triangle of the matrix.
One way to do it is:
result_sum = 0
for i in range(input_count - 1):
for j in range(i + 1, input_count - 1):
result_sum += result[i][j]
print(result_sum) # prints 11
More Pythonic way, one-liner using numpy.trace():
result_sum = (np.sum(result) - np.trace(result)) // 2
You are calculating walks, which would include walks 6-7-6 (which is not a P2)
this discussion might help:
https://math.stackexchange.com/questions/1890620/finding-path-lengths-by-the-power-of-adjacency-matrix-of-an-undirected-graph

Creating a triangle using a ragged 2D array

i need to use a ragged 2D array to create a triangle like the one shown,
0 0 0 0 0 0
1 1 1 1 1
2 2 2 2
3 3 3
4 4
5
def triangle(n):
for i in range(n):
tri = n
for j in range(n-i):
tri = tri * 10 - n
print tri
i have tried this but it returns,
444445
44445
4445
445
45
Since you made atleast some effort, here it is one way to do it
We only need to iterate over the loop once. Since the index are int, we need to convert to str. Also, they start at 0 so either you iterate from n+1 or use i+1 to print so you get your expected output. You can then multiply how many times you want to print the numbers which is converted to string.
def triangle(n):
for i in range(n):
print (str(i+1) + " ") * (n - i)
Demo

Categories

Resources