Repetition of function when called [duplicate] - python

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 2 years ago.
Below is my code
n = 4
m = 4
figures = [1,2,2]
def almostTetris(n, m, figures):
grid = [[0] * m] * n
def shape1(count):
for i in range(n):
for j in range(m):
if grid[i][j] == 0:
print(grid[i][j])
print(grid[1][0])
print(grid[2][0])
print(grid[3][0])
grid[i][j] = count
print(grid[i][j])
print(grid[1][0])
print(grid[2][0])
print(grid[3][0])
return
def shape2(count):
for i in range(n):
for j in range(m - 2):
if grid[i][j] == 0 and grid[i][j + 1] == 0 and grid[i][j + 2] == 0:
grid[i][j] = grid[i][j + 1] = grid[i][j + 2] = count
return
for i in range(len(figures)):
if figures[i] == 1:
shape1(i + 1)
elif figures[i] == 2:
shape2(i + 1)
return grid
print(almostTetris(n, m, figures))
and this is what I got printed out:
0
0
0
0
1
1
1
1
[[1, 2, 2, 2], [1, 2, 2, 2], [1, 2, 2, 2], [1, 2, 2, 2]]
My question is how does grid[i][j] = count convert all numbers in the first column to 1 (the value of count)?
I thought that because i and j are all 0, only the first element would change to 1.

When I was first learning python I struggled with this too. The problem is in this line
grid=[[0]*m]*n
Because it doesn't create an nxm grid of 0s,
it actually copies the object: [[0]*m] n times to create the 2d array. Therefore if you mutate one of the values in this object, the other n object instances get edited too. Try something along the lines of
grid = [[0]*m for _ in range(n)]

Related

Cut a sequence of length N into subsequences such that the sum of each subarray is less than M and the cut minimizes the sum of max of each part

Given an integer array sequence a_n of length N, cut the sequence into several parts such that every one of which is a consequtive subsequence of the original sequence.
Every part must satisfy the following:
The sum of each part is not greater than a given integer M
Find a cut that minimizes the sum of the maximum integer of each part
For example:
input : n = 8, m = 17 arr = [2, 2, 2, 8, 1, 8, 2, 1]
output = 12
explanation: subarrays = [2, 2, 2], [8, 1, 8], [2, 1]
sum = 2 + 8 + 2 = 12
0 <= N <= 100000
each integer is between 0 and 1000000
If no such cut exists, return -1
I believe this is a dynamic programming question, but I am not sure how to approach this.
I am relatively new to coding, and came across this question in an interview which I could not do. I would like to know how to solve it for future reference.
Heres what I tried:
n = 8
m = 17
arr = [2, 2, 2, 8, 1, 8, 2, 1]
biggest_sum, i = 0, 0
while (i < len(arr)):
seq_sum = 0
biggest_in_seq = -1
while (seq_sum <= m and i < len(arr)):
if (seq_sum + arr[i] <= m ):
seq_sum += arr[i]
if (arr[i] > biggest_in_seq):
biggest_in_seq = arr[i]
i += 1
else:
break
biggest_sum += biggest_in_seq
if (biggest_sum == 0):
print(-1)
else:
print(biggest_sum)
This givens the result 16, and the subsequences are: [[2, 2, 2, 8, 1], [8, 2, 1]]
Problem is that you are filling every sequence from left to right up to the maximum allowed value m. You should evaluate different options of sequence lengths and minimize the result, which in the example means that the 2 8 values must be in the same sequence.
a possible solution could be:
n = 8
m = 17
arr = [2, 2, 2, 8, 1, 8, 2, 1]
def find_solution(arr, m, n):
if max(arr)>m:
return -1
optimal_seq_length = [0] * n
optimal_max_sum = [0] * n
for seq_start in reversed(range(n)):
seq_len = 0
seq_sum = 0
seq_max = 0
while True:
seq_len += 1
seq_end = seq_start + seq_len
if seq_end > n:
break
last_value_in_seq = arr[seq_end - 1]
seq_sum += last_value_in_seq
if seq_sum > m:
break
seq_max = max(seq_max, last_value_in_seq)
max_sum_from_next_seq_on = 0 if seq_end >= n else optimal_max_sum[seq_end]
max_sum = max_sum_from_next_seq_on + seq_max
if seq_len == 1 or max_sum < optimal_max_sum[seq_start]:
optimal_max_sum[seq_start] = max_sum
optimal_seq_length[seq_start] = seq_len
# create solution list of lists
solution = []
seg_start = 0
while seg_start < n:
seg_length = optimal_seq_length[seg_start]
solution.append(arr[seg_start:seg_start+seg_length])
seg_start += seg_length
return solution
print(find_solution(arr, m, n))
# [[2, 2, 2], [8, 1, 8], [2, 1]]
Key aspects of my proposal:
start from a small array (only last element), and make the problem array grow to the front:
[1]
[2, 1]
[8, 2, 1]
etc.
for each of above problem arrays, store:
the optimal sum of the maximum of each sequence (optimal_max_sum), which is the value to be minimized
the sequence length of the first sequence (optimal_seq_length) to achieve this optimal value
do this by: for each allowed sequence length starting at the beginning of the problem array:
calculate the new max_sum value and add it to previously calculated optimal_max_sum for the part after this sequence
keep the smallest max_sum, store it in optimal_max_sum and the associated seq_length in optimal_seq_length

Converting repetitive if statements into a loop

I have this code:
#!/usr/bin/python3
def contract(e, i, c, n):
l = len(e)
grid = [[0 for i in range(i + 1)] for x in range(l)]
for num1, row1 in enumerate(grid):
row1[0] = e[num1] #add exponents
for num2, row2 in enumerate(grid):
if 0 <= num2 < n[0]:
grid[num2][1] = c[num2]
if n[0] <= num2 < n[0] + n[1]:
grid[num2][2] = c[num2]
if n[0] + n[1] <= num2 < n[0] + n[1] + n[2]:
grid[num2][3] = c[num2]
for g in grid:
print(g)
e = [0, 1, 2, 3]
i = 3
c = [4, 5, 6, 7]
n = [1, 2, 1]
contract(e, i, c, n)
The idea of this code is that I have a 2 dimensional grid that has dimensions len(e) x (i + 1). The first column contains exponents e. The rest of the columns should contain coefficients c in such a way that n determines the positions of the coefficients in the grid. For example, since n[0] = 1, column 1, row 0 in the grid contains number 4. The next element in n is 2, so the next column in the grid (column 2) should contain 2 numbers, meaning numbers 5 and 6 in rows below the row that I used previously (meaning rows 1 and 2 because row 0 is already used). n[2] = 1 so grid[3][3] = 7, etc.
I implemented this with repetitive if-statements and the code works fine, the output is as it should be:
[0, 4, 0, 0]
[1, 0, 5, 0]
[2, 0, 6, 0]
[3, 0, 0, 7]
However, I would like to make an extensible program that can do this for any number of coefficients and exponents. How can I convert those repetitive if statements to a single loop?
I would convert it into a for loop that keeps track of the sum of the elements seen so far, adjusting the corresponding element if the inequality holds for that iteration:
for num2, row2 in enumerate(grid):
total = 0
for n_idx, n_elem in enumerate(n):
if total <= num2 < total + n_elem:
grid[num2][n_idx + 1] = c[num2]
total += n_elem
I would advise against using sum() in this loop, as it recomputes the sum from scratch on each iteration, which isn't very efficient.
Use a loop that sums successive slices of the n list.
for num2, row2 in enumerate(grid):
for idx in range(len(n)):
if sum(n[:idx]) <= num2 < sum(n[:idx+1]):
grid[num2][idx+1] = c[num2]
This is a direct mapping of the code you wrote to a loop, and reasonable if n doesn't get too large. BrokenBenchmark's answer is optimized to take advantage of the fact that the sum of each slice is the sum of the previous slice plus the current element.

How does mentioned output get? please explain the code

arr = [1, 2, 3, 4, 5, 6]
for i in range(1, 6):
arr[i - 1] = arr[i]
for i in range(0, 6):
print(arr[i], end = " ")
Answer is :2 3 4 5 6 6
This is your code:
arr = [1, 2, 3, 4, 5, 6]
for i in range(1, 6):
arr[i - 1] = arr[i]
for i in range(0, 6):
print(arr[i], end = " ")
arr is a list comprised of 6 integers.
In your first for loop, i will vary from 1 to 5 (inclusive).
Python lists are accessed using base-0 - i.e., the first element is at index zero, the second at 1 and so on.
Therefore your loop is moving every element to the position (index) that immediately precedes it. Nothing is moved into index 5
if you are refering to get the following result : 2 3 4 5 6 1
then you should rearrange the following way:
for i in range(0, 6):
arr[i-1] = arr[i]
that way, you start with arr[-1] = arr[0], so 6 will be replaced with 1 and so the code goes on

Printing given pattern using for loop

I have written the following code and it runs but I am using 4 for loops and I would like to know if there is more effective way to write this code.
n = int(input('Please Enter the highest number \n'))
col = 2*n-1
for i in range(1, n+1):
for j in range(1, col+1):
if j >= i and j <= col-i+1:
print(n-i+1, end=' ')
elif j < i:
print(n+1-j, end=' ')
else:
print(j+1-n, end=' ')
print()
for i in range(n-1, 0, -1):
for j in range(1, col+1):
if j >= i and j <= col - i + 1:
print(n-i+1, end=' ')
elif j < i:
print(n + 1 - j, end=' ')
else:
print(j + 1 - n, end=' ')
print()
You could find the position relative to the center (di, dj), and then use its largest component as the label for that cell:
n = int(input('Please Enter the highest number \n'))
col = 2 * n
for i in range(1, col):
row = []
for j in range(1, col):
di, dj = abs(n-i), abs(n-j)
row.append(max(di,dj) + 1)
print(' '.join(str(x) for x in row))
Problem Definition
Breaking this down into a few logical obsevations.
We have a grid of numbers that appears symmetrical.
However, the middle row / middle column are only repeated once, this is
important.
Therefore it is more similar to looking down on a pyramid
from above, where 1 represents the highest point, and 4 / n the
lowest.
So we know that to follow DRY principle, we only need to generate one corner of the pyramid, and then we simply copy it to the other 3 corners.
Solution
(assuming use of pure python 3.x only, without libraries such as numpy)
def print_pyramid(n=4):
"""Print a symmetrical pyramid of numbers descending from n"""
# Calculate bottom half of grid
bottom = []
for j in range(n):
row = [max(i, j + 1) for i in range(1, n + 1)]
row = row[::-1][:-1] + row
bottom.append(row)
# Invert bottom to get top
rows = bottom[::-1][:-1] + bottom
# Print formatted
for row in rows:
row_str = [str(i) for i in row]
print(f"{' '.join(row_str)}")
print_pyramid(4)
This is definitely not the most efficient method (see recursive functions), but it is fairly quick and pythonic.
Explanation
Bottom Right corner
First we generate an array of numbers, 1 => n:
[i for i in range(1, n + 1)]
[1, 2, 3, 4]
Then we loop n times to generate this for each row (j), but replace any values lower than j using max:
for j in range(n):
row = [max(i, j+1) for i in range(1,n+1)]
[1, 2, 3, 4]
[2, 2, 3, 4]
[3, 3, 3, 4]
[4, 4, 4, 4]
Bottom Left Corner (~mirror image)
First we select the row elements in reverse with slice notation [::-1]
Then we remove the last element [:-1]
row = [max(i, j+1) for i in range(1,n+1)]
row[::-1][:-1]
[4, 3, 2]
[4, 3, 2]
[4, 3, 3]
[4, 4, 4]
Top Half
Now we create the top half using the same slicing technique to reverse and select from our existing nested array.
bottom[::-1][:-1]
[4, 4, 4, 4, 4, 4, 4]
[4, 3, 3, 3, 3, 3, 4]
[4, 3, 2, 2, 2, 3, 4]
Finally, we print our full array with string formatting
for row in rows:
row_str = [str(i) for i in row]
print(f"{' '.join(row_str)}")
4 4 4 4 4 4 4
4 3 3 3 3 3 4
4 3 2 2 2 3 4
4 3 2 1 2 3 4
4 3 2 2 2 3 4
4 3 3 3 3 3 4
4 4 4 4 4 4 4
P.S. Please don't cheat on your homework assignments ;)
Since the inner loops are identical, you could join the two outer loops into one, e.g. by chaining the two ranges:
from itertools import chain
...
for i in chain(range(1, n + 1), range(n - 1, 0, -1)):
...
The condition can be simplified like this:
i <= j <= col - i + 1

Dynamic Programming - Primitive Calculator Python [duplicate]

This question already has an answer here:
Dynamic programming for primitive calculator
(1 answer)
Closed 6 years ago.
This assignment aims to implement a dynamic programming approach to a primitive calculator that can only add 1, multiply by 2 and multiply by 3. So with an input of n determine the minimum number of operations to reach n. I've implemented a very naive dp or what I think is a dp approach. It is not working. I have no-one else to ask. For an input of n = 5 the output of the below is: ([0, 1, 2, 2, 3, 4], [1, 1, 2, 3, 4, 5]) whereas there are two correct outputs for the list numbers = [1, 2, 4, 5] or [1, 3, 4, 5]. Some help would be greatly appreciated.
def DPmin_operations(n):
numbers = []
minNumOperations = [0]*(n+1)
numOps = 0
numbers.append(1)
for k in range(1,n+1):
minNumOperations[k] = 10000
# for *3 operator
if k % 3 == 0:
numOps = minNumOperations[k//3] + 1
if numOps < minNumOperations[k]:
minNumOperations[k] = numOps
numbers.append(k)
# for *2 operator
elif k % 2 == 0:
numOps = minNumOperations[k//2] + 1
if numOps < minNumOperations[k]:
minNumOperations[k] = numOps
numbers.append(k)
# for + 1 operator
elif k >= 1:
numOps = minNumOperations[k - 1] + 1
if numOps < minNumOperations[k]:
minNumOperations[k] = numOps
numbers.append(k)
return (minNumOperations, numbers)
Note that the elif blocks should really be if blocks. Currently, you're using a greedy algorithm of always trying to divide by 3; if that fails, then trying to divide by 2; if that fails, then subtracting 1. It's possible that a number is divisible by 6 so that all three options are possible, and yet dividing by 2 is more optimal then dividing by 3.
As for getting your list of numbers, do that at the end. Store all possible parents, then work backwards from your goal to see how you got there.
def dp_min_ops(n):
all_parents = [None] * (n + 1)
all_min_ops = [0] + [None] * n
for k in range(1, n + 1):
curr_parent = k - 1
curr_min_ops = all_min_ops[curr_parent] + 1
if k % 3 == 0:
parent = k // 3
num_ops = all_min_ops[parent] + 1
if num_ops < curr_min_ops:
curr_parent, curr_min_ops = parent, num_ops
if k % 2 == 0:
parent = k // 2
num_ops = all_min_ops[parent] + 1
if num_ops < curr_min_ops:
curr_parent, curr_min_ops = parent, num_ops
all_parents[k], all_min_ops[k] = curr_parent, curr_min_ops
numbers = []
k = n
while k > 0:
numbers.append(k)
k = all_parents[k]
numbers.reverse()
return all_min_ops, numbers
print(dp_min_ops(5)) # ([0, 1, 2, 2, 3, 4], [1, 3, 4, 5])
print(dp_min_ops(10)) # ([0, 1, 2, 2, 3, 4, 3, 4, 4, 3, 4], [1, 3, 9, 10])

Categories