Calculate trapped water in a structure - python

Supposed my input is [1, 4, 2, 5, 1, 2, 3] . Then we can create a
structure like this:
...X...
.X.X...
.X.X..X
.XXX.XX
XXXXXXX
1425123
When water is poured over the top at all places and allowed to runoff,
it will remain trapped at the 'O' locations:
...X...
.XOX...
.XOXOOX
.XXXOXX
XXXXXXX
1425123
we have to find a total number of trapped 'O' in a given list.
My program is able to give me the correct output but when I run it
against different test cases, it gives me a memory error. Is there any way I can reduce the space complexity of this program?
def answer(heights):
row = len(heights)
col = max(heights)
sum = 0
matrix = [['X' for j in range(i)] for i in heights]
for i in range(col):
rainWater = []
for j in range(row):
try:
rainWater.append(matrix[j][i])
except IndexError:
rainWater.append('0')
sum += ''.join(rainWater).strip('0').count('0')
return sum
print answer([1, 4, 2, 5, 1, 2, 3])
The list array will have at least 1 element and at most 9000 elements. Each element will have a value of at least 1, and at most 100000.
Inputs:
(int list) heights = [1, 4, 2, 5, 1, 2, 3]
Output:
(int) 5
Inputs:
(int list) heights = [1, 2, 3, 2, 1]
Output:
(int) 0

This can be solved in linear time with linear memory requirements in the following way:
def answer(heights):
minLeft = [0] * len(heights)
left = 0
for idx, h in enumerate(heights):
if left < h:
left = h
minLeft[idx] = left
minRight = [0] * len(heights)
right = 0
for idx, h in enumerate(heights[::-1]):
if right < h:
right = h
minRight[len(heights) - 1 - idx] = right
water = 0
for h, l, r in zip(heights, minLeft, minRight):
water += min([l, r]) - h
return water
The arrays minLeft and minRight contain the highest level at which water can be supported at a place in the array if there was a wall of infinite size on the right or left side respectively. Then at each index, total water that can be contained is the minimum of the water levels supported by the left and the right side - height of the floor.
This question deals with this problem in higher dimension (relating it to the Watershed problem in image processing): The Maximum Volume of Trapped Rain Water in 3D

The code's in c#. O(N) time, O(1) space. Using two pointers, and 2 integer variable to track. Can't figure out a more optimized way for this question.
public int Trap(int[] height) {
if(height == null || height.Length == 0)
return 0;
int max = 0;
int vol = 0;
int left = 0;
int right = height.Length - 1;
while(left<= right)
{
if(height[left] < height[right])
{
max = Math.Max(max,height[left]);
vol = vol + (max-height[left]);
left++;
}
else
{
max = Math.Max(max,height[right]);
vol = vol + (max-height[right]);
right--;
}
}
return vol;
}

You could solve this problem with a single loop (the following example is written in Java):
public static int trapw(int[] check) {
int sum = 0, ml = 0, mr = 0, clen = 0;
if ((clen = check.length-1) <= 1)
return 0;
int[] r = new int[clen+1];
for (int k = 0, lidx = clen; k <= clen; k++, lidx = clen - k) {
ml = Math.max(ml, check[k]); mr = Math.max(mr, check[lidx]);
if (k < lidx) {
r[k] = ml; r[lidx] = mr;
} else if (lidx == k) {
// Middlepoint
r[k] = Math.min(ml, mr); sum += Math.max(r[k] - check[k], 0);
} else {
r[k] = Math.max((Math.min(ml, r[k]) - check[k]), 0);
r[lidx] = Math.max((Math.min(mr, r[lidx]) - check[lidx]), 0);
sum += r[k] + r[lidx];
}
}
return sum;
}

Related

N-Queens II using backtracking is slow

The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two queens attack each other.
Given an integer n, return the number of distinct solutions to the n-queens puzzle.
https://leetcode.com/problems/n-queens-ii/
My solution:
class Solution:
def totalNQueens(self, n: int) -> int:
def genRestricted(restricted, r, c):
restricted = set(restricted)
for row in range(n): restricted.add((row, c))
for col in range(n): restricted.add((r, col))
movements = [[-1, -1], [-1, 1], [1, -1], [1, 1]]
for movement in movements:
row, col = r, c
while 0 <= row < n and 0 <= col < n:
restricted.add((row, col))
row += movement[0]
col += movement[1]
return restricted
def gen(row, col, curCount, restricted):
count, total_count = curCount, 0
for r in range(row, n):
for c in range(col, n):
if (r, c) not in restricted:
count += 1
if count == n: total_count += 1
total_count += gen(row + 1, 0, count, genRestricted(restricted, r, c))
count -= 1
return total_count
return gen(0, 0, 0, set())
It fails at n=8. I can't figure out why, and how to have less iterations. It seems I am already doing the minimum iterations possible.
The restricted set seems wasteful, both time- and space-wise. At the end of the successful recursion, n levels deep it grows to n^2 size, which drives the total complexity to O(n^3). And it is not really needed. It is much easier to check the availability of the square by looking at the queens already placed (please forgive the chess lingo; file stand for vertical, and rank for horizontal):
def square_is_safe(file, rank, queens_placed):
for queen_rank, queen_file in enumerate(queens_placed):
if queen_file == file: # vertical attack
return false
if queen_file - file == queen_rank - rank: # diagonal attack
return false
if queen_file - file == rank - queen_rank: # anti-diagonal attack
return false
return true
to be used in
def place_queen_at_rank(queens_placed, rank):
if rank == n:
total_count += 1
return
for file in range(0, n):
if square_is_safe(file, rank, queens_placed):
queens_placed.append(file)
place_queen_at_rank(queens_placed, rank + 1)
queens_placed.pop()
And there is a plenty of room for the optimization. For example, you may want to special-case the first rank: due to a symmetry, you only need to inspect a half of it (cutting execution time by the factor of 2).
You can avoid checking for horizontal conflicts by only placing one queen per row. This also allows you to reduce the size of the diagonal conflict matrix by only flagging subsequent rows. Using a simple boolean flag list for column conflicts is also a time saver (as opposed to flagging multiple entries in a matrix)
here's an example as a generator of solutions:
def genNQueens(size=8):
# setup queen coverage from each position {position:set of positions}
reach = { (r,c):[] for r in range(size) for c in range(0,size) }
for R in range(size):
for C in range(size):
for h in (1,-1): # diagonals on next rows
reach[R,C].extend((R+i,C+h*i) for i in range(1,size))
reach[R,C] = [P for P in reach[R,C] if P in reach]
reach.update({(r,-1):[] for r in range(size)}) # for unplaced rows
# place 1 queen on each row, with backtracking
cols = [-1]*size # column of each queen (start unplaced)
usedCols = [False]*(size+1) # column conflict detection
usedDiag = [[0]*(size+1) for _ in range(size+1)] # for diagonal conflicts
r = 0
while r >= 0:
usedCols[cols[r]] = False
for ur,uc in reach[r,cols[r]]: usedDiag[ur][uc] -= 1
cols[r] = next((c for c in range(cols[r]+1,size)
if not usedCols[c] and not usedDiag[r][c]),-1)
usedCols[cols[r]] = True
for ur,uc in reach[r,cols[r]]: usedDiag[ur][uc] += 1
r += 1 if cols[r]>=0 else -1 # progress or backtrack
if r<size : continue # continue until all rows placed
yield [*enumerate(cols)] # return result
r -= 1 # backtrack to find more
output:
from timeit import timeit
for n in range(3,13):
t = timeit(lambda:sum(1 for _ in genNQueens(n)), number=1)
c = sum(1 for _ in genNQueens(n))
print(f"solutions for {n}x{n}:", c, "time:",f"{t:.4g}")
solutions for 3x3: 0 time: 0.000108
solutions for 4x4: 2 time: 0.0002044
solutions for 5x5: 10 time: 0.0004365
solutions for 6x6: 4 time: 0.0008741
solutions for 7x7: 40 time: 0.003386
solutions for 8x8: 92 time: 0.009881
solutions for 9x9: 352 time: 0.03402
solutions for 10x10: 724 time: 0.1228
solutions for 11x11: 2680 time: 0.5707
solutions for 12x12: 14200 time: 2.77
For n ≤ 9 (the bound in the linked puzzle), it's enough to enumerate all valid positions for rooks and verify that there are no attacking diagonal moves.
import itertools
def is_valid(ranks):
return not any(
abs(f1 - f2) == abs(r1 - r2)
for f1, r1 in enumerate(ranks)
for f2, r2 in enumerate(ranks[:f1])
)
def count_valid(n):
return sum(map(is_valid, itertools.permutations(range(n))))
print(*(count_valid(i) for i in range(1, 10)), sep=",")
Just one change (remove r loop in gen) can make your solution AC.
The main reason is that your gen has argument row, and it will call itself using row + 1, so there is no need to iterate using for r in range(row, n):. It's unnecessary. Just Removing it, your solution is quite acceptable.(we need to need add else before nested call)
Following is the result:
Before change:
1 1 1.8358230590820312e-05
2 0 5.7697296142578125e-05
3 0 0.00036835670471191406
4 2 0.0021448135375976562
5 10 0.02212214469909668
6 4 0.23602914810180664
7 40 3.0731561183929443
After change:
1 1 1.6450881958007812e-05
2 0 3.1948089599609375e-05
3 0 0.0001366138458251953
4 2 0.0002281665802001953
5 10 0.0008234977722167969
6 4 0.0028502941131591797
7 40 0.01242375373840332
8 92 0.05443763732910156
9 352 0.2279810905456543
It just uses 0.4% time of original version for the n = 7 case, and n = 8 can absolutely work.
class Solution:
def totalNQueens(self, n: int) -> int:
def genRestricted(restricted, r, c):
restricted = set(restricted)
for row in range(n): restricted.add((row, c))
for col in range(n): restricted.add((r, col))
movements = [[-1, -1], [-1, 1], [1, -1], [1, 1]]
for movement in movements:
row, col = r, c
while 0 <= row < n and 0 <= col < n:
restricted.add((row, col))
row += movement[0]
col += movement[1]
return restricted
def gen(row, col, curCount, restricted):
count, total_count = curCount, 0
for c in range(col, n):
if (row, c) not in restricted:
count += 1
if count == n: total_count += 1
else: total_count += gen(row + 1, 0, count, genRestricted(restricted, row, c))
count -= 1
return total_count
return gen(0, 0, 0, set())
if __name__ == '__main__':
import time
s = Solution()
for i in range(1, 8):
t0 = time.time()
print(i, s.totalNQueens(i), '\t', time.time() - t0)
Of course, there are other enhancements can be made. But this is the biggest one.
For instance, you updated and created a new restricted/forbidden points after adding each point.
BTW, I don't agree #user58697 for restricted, it's necessary based on your solution, as you need to clone and update to get a new one to avoid restore it in the recursive call loop.
BTW, following is my solution, just for your reference:
class Solution:
def solveNQueens_n(self, n): #: int) -> List[List[str]]:
cols = [-1] * n # index means row index
self.res = 0
usedCols = set() # this and cols can avoid vertical and horizontal conflict
def dfs(r): # current row to fill in
def valid(c):
for r0 in range(r):
# (r0, c0), (r1, c1) in the (back-)diagonal, |r1 - r0| = |c1 - c0|
if abs(c - cols[r0]) == abs(r - r0):
return False
return True
if r == n: # valid answer
self.res += 1
return
for c in range(n):
if c not in usedCols and valid(c):
usedCols.add(c)
cols[r] = c
dfs(r + 1)
usedCols.remove(c)
cols[r] = -1
dfs(0)
return self.res
In this kind of problem, you have to focus on the algorithm first, not on the code.
In the following, I will focus on the algorithm, just giving an example in C++ to illustrate it.
One main issue is to be able to detect fast if a given position is already controlled or not by an existing Queen.
One simple possibility is to index the diagonals (for 0 to 2N-1), and to keep track in a array if the corresponding diagonals, antidiagonals or the columns are already controlled. Any way to index the diagonals or the antidiagonals will do the jobs. For a given (row, column) point, I use:
diagonal index = row + column
antidiagonal index = n-1 + col - row
In addition, I use a simple symmetry: it is only necessary to calculate the number of possibilities
for a row index from 0 to n/2-1 (or n/2 if n is odd).
It is certainy possible to speed it up a little bit, by using other symmmetries. However, as it is, it looks quite fast enough for n values less or equal to 9.
Result:
2 : 0 time : 0.001 ms
3 : 0 time : 0.001 ms
4 : 2 time : 0.001 ms
5 : 10 time : 0.002 ms
6 : 4 time : 0.004 ms
7 : 40 time : 0.015 ms
8 : 92 time : 0.05 ms
9 : 352 time : 0.241 ms
10 : 724 time : 0.988 ms
11 : 2680 time : 5.55 ms
12 : 14200 time : 31.397 ms
13 : 73712 time : 188.12 ms
14 : 365596 time : 1046.43 ms
Here is the code in C++. As the code is quite simple, you should easily be able to convert it in Python.
#include <iostream>
#include <chrono>
constexpr int N_MAX = 14;
constexpr int N_DIAG = 2*N_MAX + 1;
class Solution {
public:
int n;
int Col[N_MAX] = {0};
int Diag[N_DIAG] = {0};
int AntiDiag[N_DIAG] = {0};
int totalNQueens(int n1) {
n = n1;
if (n <= 1) return n;
int count = 0;
for (int col = 0; col < n/2; ++col) {
count += sum_from (0, col);
}
count *= 2;
if (n%2) count += sum_from (0, n/2);
return count;
}
int sum_from (int row, int col) {
if (Col[col]) return 0;
int diag = row + col;
if (Diag[diag]) return 0;
int antidiag = n-1 + col - row;
if(AntiDiag[antidiag]) return 0;
if (row == n-1) return 1;
int count = 0;
Col[col] = 1;
Diag[diag] = 1;
AntiDiag[antidiag] = 1;
for (int k = 0; k < n; ++k) {
count += sum_from (row+1, k);
}
Col[col] = 0;
Diag[diag] = 0;
AntiDiag[antidiag] = 0;
return count;
}
};
int main () {
int n = 1;
while (n++ < N_MAX) {
auto start = std::chrono::high_resolution_clock::now();
Solution Sol;
std::cout << n << " : " << Sol.totalNQueens (n) << " time : ";
auto diff = std::chrono::high_resolution_clock::now() - start;
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(diff).count();
std::cout << double(duration)/1000 << " ms" << std::endl;
}
return 0;
}
Ok, one thing I missed was that each row must have a queen. Very important observation. gen method has to be modified like this:
def gen(row, col, curCount, restricted):
if row == n: return 0
count, total_count = curCount, 0
for c in range(col, n):
if (row, c) not in restricted:
if count + 1 == n: total_count += 1
total_count += gen(row + 1, 0, count + 1, genRestricted(restricted, row, c))
return total_count
It beats only ~20% submissions, so it's not perfect at all. Far from it.

Given an array of integers, find the length of the largest subarray such that atleast 1 number (from the first k numbers) is not present in it

Problem: We're given an array of integers with integers ranging from 1 to k. It is not necessary that all the k integers are present.
Eg. k = 3 and Array = [1,2,1,1,2]
Find the length of the largest subarray such that atleast one integer from 1 to k is absent.
Example: For k = 3 and array = [1,2,1,1,2], Answer = 5
For k = 2 and array = [1,2,1,1,2], Answer = 2.
My code:
def ans(A, n, k): #A is the array and n is the length
d = {}
if k > n:
return n
for i in range(n):
if A[i] in d:
d[A[i]].append(i)
else:
d[A[i]] = [i]
max_diff = 0
if len(d) != k:
return n
for j in d:
r = len(d[j])
if r == 1:
diff = max(n-d[j][-1]-1, d[j][0])
else:
diff = max(d[j][0], r - d[j][-1]-1)
for i in range(r-1):
diff = max(diff, d[j][i+1] - d[j][i]-1)
max_diff = max(max_diff, diff)
return max_diff
However, the code gives runtime error and wrong answers for some hidden test cases. What is the possible error? And the possible test cases which are giving wrong answers?
Explanation for diff : Basically for each number in the array, it is finding the stretchs i.e. the interval lengths in which that partcular element is not present. For the second example, d becomes {1:[0,2,3], 2:[1,4]}. In case of two, there exists a subarray without two on index 0 i.e. length =1 so, diff would be 1. Then there is no two in the subarray from index 2 to 3 (inclusive). Thus, diff = 2.
EDIT: Taking in consideration the comments, I've made a few changes in the code and it no longer gives a runtime error but I still have Wrong Answer on some hidden test cases.
Problem link in case you want to try: https://www.codechef.com/LRNDSA02/problems/NOTALLFL
The code gives a wrong answer for the input:
k = 2
array = [1, 2, 2, 1, 2, 2, 2, 2, 2]
The change should be in the 18th line
i.e. instead of
diff = max(d[j][0], r - d[j][-1]-1)
It should be
diff = max(d[j][0], n - d[j][-1]-1)
It's a tiny mistake but caused failure for a lot of test cases.
Consider the below:
target = #, all other numbers = -.
A = { - - - # - # # - - - - - - # - # - - - - - - - - - - - }
If we want to find the subarray that does not contain #, we can treat the entire array as being enclosed by #, such that:
A` = { # - - - # - # # - - - - - - # - # - - - - - - - - - - - # }
Then, it's just a matter of - tracking the last encountered position of #, and the largest difference between 2 consecutive occurrences of #. # could be any number between 1..k, so it could be tracked by an array of size "k".
C++ code would be something like (please test for off-by-1 error as I expect it to be there:
int subarr(int* A, size_t n, int k)
{
if (n < k)
{
return n;
}
size_t max = 0;
std::vector<size_t> lastPos(k);
for (size_t i = 0; i < lastPos.size(); i++)
{
lastPos[i] = -1;
}
// Find the longest subArray when excluding a single digit of the digits present.
for (size_t i = 0; i < n; i++)
{
if ((i - lastPos[A[i]]) > max)
{
max = i - lastPos[A[i]];
}
lastPos[A[i]] = i;
}
// Check for last
for (size_t i = 0; i < lastPos.size(); i++)
{
if ((i - lastPos[A[i]]) == -1)
{
return n;
}
}
return max - 1;
}

how to make a sum of submatrices

i need to make for every sub-matrix the sum of the values.
for example if i have [[1,1,2],[2,3,4]] the resulting matrix will be:
M[0][0] = 1 M[0][1] = 1+1 = 2 M[0][2] = 1+1+2 = 4
M[1][0] = 1+2 = 3 M[1][1] = 1+1+2+3 = 7 M[1][2] = 1+1+2+2+3+4 = 13
or
M = [[1,2,4],[3,7,13]]
and i made this code
`N = []
M = []
summ = 0
n= list(map(int, input().split()))
while n != []:
N.append(n)
n = list(map(int, input().split()))
for i in range(len(N)):
M.append([0 for i in range(len(N[0]))])
summ = 0
for j in range(len(N[0])):
summ += N[i][j]
M[i][j] = M[i-1][j] + summ `
the problem is that when the matrix is big becomes reeeeally slow.
i need to solve a 100x100 matrix at max in 0.5 sec
can anybody help me? WITHOUT IMPORTING PACKAGES!!
`
For speed, you really want to be using NumPy which will be significantly faster than base Python in addition to giving cleaner code for matrices. From your small example, you can use numpy.cumsum() twice across different axes:
import numpy as np
arr = np.array([[1,1,2],[2,3,4]])
out = arr.cumsum(axis=1).cumsum(axis=0)
print(out)
Gives:
array([[ 1, 2, 4],
[ 3, 7, 13]], dtype=int32)
Side note: on Windows, the default int type is 32 Bit and cumsum() is liable to silently overflow on large matrices/large numbers so you'll probably want arr = np.array([[1,1,2],[2,3,4]]).astype(np.int64) if on Windows.
Timings:
arr = np.arange(10000).reshape(100, 100)
%timeit out = arr.cumsum(axis=1).cumsum(axis=0)
56.3 µs ± 4.96 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
So, thousands of times faster than your requirement.
We can compute the sum of all sub-matrix by using a dp matrix. In this we compute the prefix sum of the given matrix.We create a new matrix and store the prefix sum and then use the formula
tlx: Top left x coordinate
tly: Top Left y coordinate
brx: Bottom right x coordinate
bry: Bottom Right y coordinate
Sum between (tlx, tly) and (brx, bry) :
sum += dp[brx][bry] - dp[tlx - 1][bry] - dp[brx][tly - 1] + dp[tlx - 1][tly - 1];
Let me explain:
We first have a given matrix suppose Arr :
#define n 3
int row(n), col(n), sum(0);
int arr[row][col] = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
Then we will create a prefix matrix with one size greater and we will fill all values as 0 initially.
int dp[row + 1][col + 1];
memset(dp, 0, sizeof(dp));
Then will create our prefix matrix by:
Copy first row from our arr to dp
for (int j = 1; j < col + 1; j++){dp[1][j] = arr[0][j - 1];}
Run a loop and add values of first row of dp to second col of arr and store it in second col of dp
for (int i = 2; i < row + 1; i++)
{
for (int j = 1; j < col + 1; j++)
{
dp[i][j] += dp[i - 1][j] + arr[i - 1][j - 1];
}
}
Repeat this process till you fill the complete dp.
Then run a loop through col in which we will add each col to their next col and save it just like we create prefix array.
for (int i = 0; i < row + 1; i++) {
for (int j = 1; j < row + 1; j++)
{
dp[i][j] += dp[i][j - 1];
}
}
Now your dp (Prefix Matrix is ready).
arr : {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
dp : 0 0 0 0
0 1 3 6
0 5 12 21
0 12 27 45
We took one extra size for our dp array and put value 0 in the first row and col because with this it will be easier for us to use the formula which I mentioned at above.
We divide matrices into rectangles and with the help of top left position and bottom right position we calculate the occurrences in the given matrix.
Now we just have to iterate through each position from top left to bottom right and continuously add the sum and then print it.
for (int tlx = 1; tlx < row + 1; tlx++){
for (int tly = 1; tly < col + 1; tly++){
for (int brx = tlx; brx < row + 1; brx++){
for (int bry = tly; bry < col + 1; bry++){
sum += (dp[brx][bry]) - (dp[tlx - 1][bry]) - (dp[brx][tly - 1]) + (dp[tlx - 1][tly - 1]);
}
}
}
}
OUTPUT: 500

Primitive Calculator - Dynamic Approach

I'm having some trouble getting the correct solution for the following problem:
Your goal is given a positive integer n, find the minimum number of
operations needed to obtain the number n starting from the number 1.
More specifically the test case I have in the comments below.
# Failed case #3/16: (Wrong answer)
# got: 15 expected: 14
# Input:
# 96234
#
# Your output:
# 15
# 1 2 4 5 10 11 22 66 198 594 1782 5346 16038 16039 32078 96234
# Correct output:
# 14
# 1 3 9 10 11 22 66 198 594 1782 5346 16038 16039 32078 96234
# (Time used: 0.10/5.50, memory used: 8601600/134217728.)
def optimal_sequence(n):
sequence = []
while n >= 1:
sequence.append(n)
if n % 3 == 0:
n = n // 3
optimal_sequence(n)
elif n % 2 == 0:
n = n // 2
optimal_sequence(n)
else:
n = n - 1
optimal_sequence(n)
return reversed(sequence)
input = sys.stdin.read()
n = int(input)
sequence = list(optimal_sequence(n))
print(len(sequence) - 1)
for x in sequence:
print(x, end=' ')
It looks like I should be outputting 9 where I'm outputting 4 & 5 but I'm not sure why this isn't the case. What's the best way to troubleshoot this problem?
You are doing a greedy approach.
When n == 10, you check and see if it's divisible by 2 assuming that's the best step, which is wrong in this case.
What you need to do is proper dynamic programming. v[x] will hold the minimum number of steps to get to result x.
def solve(n):
v = [0]*(n+1) # so that v[n] is there
v[1] = 1 # length of the sequence to 1 is 1
for i in range(1,n):
if not v[i]: continue
if v[i+1] == 0 or v[i+1] > v[i] + 1: v[i+1] = v[i] + 1
# Similar for i*2 and i*3
solution = []
while n > 1:
solution.append(n)
if v[n-1] == v[n] - 1: n = n-1
if n%2 == 0 and v[n//2] == v[n] -1: n = n//2
# Likewise for n//3
solution.append(1)
return reverse(solution)
One more solution:
private static List<Integer> optimal_sequence(int n) {
List<Integer> sequence = new ArrayList<>();
int[] arr = new int[n + 1];
for (int i = 1; i < arr.length; i++) {
arr[i] = arr[i - 1] + 1;
if (i % 2 == 0) arr[i] = Math.min(1 + arr[i / 2], arr[i]);
if (i % 3 == 0) arr[i] = Math.min(1 + arr[i / 3], arr[i]);
}
for (int i = n; i > 1; ) {
sequence.add(i);
if (arr[i - 1] == arr[i] - 1)
i = i - 1;
else if (i % 2 == 0 && (arr[i / 2] == arr[i] - 1))
i = i / 2;
else if (i % 3 == 0 && (arr[i / 3] == arr[i] - 1))
i = i / 3;
}
sequence.add(1);
Collections.reverse(sequence);
return sequence;
}
List<Integer> sequence = new ArrayList<Integer>();
while (n>0) {
sequence.add(n);
if (n % 3 == 0&&n % 2 == 0)
n=n/3;
else if(n%3==0)
n=n/3;
else if (n % 2 == 0&& n!=10)
n=n/2;
else
n=n-1;
}
Collections.reverse(sequence);
return sequence;
Here's my Dynamic programming (bottom-up & memoized)solution to the problem:
public class PrimitiveCalculator {
1. public int minOperations(int n){
2. int[] M = new int[n+1];
3. M[1] = 0; M[2] = 1; M[3] = 1;
4. for(int i = 4; i <= n; i++){
5. M[i] = M[i-1] + 1;
6. M[i] = Math.min(M[i], (i %3 == 0 ? M[i/3] + 1 : (i%3 == 1 ? M[(i-1)/3] + 2 : M[(i-2)/3] + 3)));
7. M[i] = Math.min(M[i], i%2 == 0 ? M[i/2] + 1: M[(i-1)/2] + 2);
8. }
9. return M[n];
10. }
public static void main(String[] args) {
System.out.println(new PrimitiveCalculator().minOperations(96234));
}
}
Before going ahead with the explanation of the algorithm I would like to add a quick disclaimer:
A DP solution is not reached at first attempt unless you have good
experience solving lot of DP problems.
Approach to solving through DP
If you are not comfortable with DP problems then the best approach to solve the problem would be following:
Try to get a working brute-force recursive solution.
Once we have a recursive solution, we can look for ways to reduce the recursive step by adding memoization, where in we try remember the solution to the subproblems of smaller size already solved in a recursive step - This is generally a top-down solution.
After memoization, we try to flip the solution around and solve it bottom up (my Java solution above is a bottom-up one)
Once you have done above 3 steps, you have reached a DP solution.
Now coming to the explanation of the solution above:
Given a number 'n' and given only 3 operations {+1, x2, x3}, the minimum number of operations needed to reach to 'n' from 1 is given by recursive formula:
min_operations_to_reach(n) = Math.min(min_operations_to_reach(n-1), min_operations_to_reach(n/2), min_operations_to_reach(n/3))
If we flip up the memoization process and begin with number 1 itself then the above code starts to make better sense.
Starting of with trivial cases of 1, 2, 3
min_operations_to_reach(1) = 0 because we dont need to do any operation.
min_operations_to_reach(2) = 1 because we can either do (1 +1) or (1 x2), in either case number of operations is 1.
Similarly, min_operations_to_reach(3) = 1 because we can multiply 1 by 3 which is one operation.
Now taking any number x > 3, the min_operations_to_reach(x) is the minimum of following 3:
min_operations_to_reach(x-1) + 1 because whatever is the minimum operations to reach (x-1) we can add 1 to it to get the operation count to make it number x.
Or, if we consider making number x from 1 using multiplication by 3 then we have to consider following 3 options:
If x is divisible by 3 then min_operations_to_reach(x/3) + 1,
if x is not divisible by 3 then x%3 can be 1, in which case its min_operations_to_reach((x-1)/3) + 2, +2 because one operation is needed to multiply by 3 and another operation is needed to add 1 to make the number 'x'
Similarly if x%3 == 2, then the value will be min_operations_to_reach((x-2)/3) + 3. +3 because 1 operation to multiply by 3 and then add two 1s subsequently to make the number x.
Or, if we consider making number x from 1 using multiplication by 2 then we have to consider following 2 options:
if x is divisible by 2 then its min_operations_to_reach(x/2) + 1
if x%2 == 1 then its min_operations_to_reach((x-1)/2) + 2.
Taking the minimum of above 3 we can get the minimum number of operations to reach x. Thats what is done in code above in lines 5, 6 and 7.
def DPoptimal_sequence(n,operations):
MinNumOperations=[0]
l_no=[]
l_no2=[]
for i in range(1,n+1):
MinNumOperations.append(None)
for operation in operations:
if operation==1:
NumOperations=MinNumOperations[i-1]+1
if operation==2 and i%2==0:
NumOperations=MinNumOperations[int(i/2)]+1
if operation==3 and i%3==0:
NumOperations=MinNumOperations[int(i/3)]+1
if MinNumOperations[i]==None:
MinNumOperations[i]=NumOperations
elif NumOperations<MinNumOperations[i]:
MinNumOperations[i]=NumOperations
if MinNumOperations[i] == MinNumOperations[i-1]+1:
l_no2.append((i,i-1))
elif MinNumOperations[i] == MinNumOperations[int(i/2)]+1 and i%2 == 0:
l_no2.append((i,int(i/2)))
elif MinNumOperations[i] == MinNumOperations[int(i/3)]+1 and i%3 == 0:
l_no2.append((i,int(i/3)))
l_no.append((i,MinNumOperations[i]-1))
#print(l_no)
#print(l_no2)
x=MinNumOperations[n]-1
#print('x',x)
l_no3=[n]
while n>1:
a,b = l_no2[n-1]
#print(a,b)
if b == a-1:
n = n-1
#print('1111111111111')
#print('n',n)
l_no3.append(n)
elif b == int(a/2) and a%2==0:
n = int(n/2)
#print('22222222222222222')
#print('n',n)
l_no3.append(n)
elif b == int(a/3) and a%3==0:
n = int(n/3)
#print('333333333333333')
#print('n',n)
l_no3.append(n)
#print(l_no3)
return x,l_no3
def optimal_sequence(n):
hop_count = [0] * (n + 1)
hop_count[1] = 1
for i in range(2, n + 1):
indices = [i - 1]
if i % 2 == 0:
indices.append(i // 2)
if i % 3 == 0:
indices.append(i // 3)
min_hops = min([hop_count[x] for x in indices])
hop_count[i] = min_hops + 1
ptr = n
optimal_seq = [ptr]
while ptr != 1:
candidates = [ptr - 1]
if ptr % 2 == 0:
candidates.append(ptr // 2)
if ptr % 3 == 0:
candidates.append(ptr // 3)
ptr = min(
[(c, hop_count[c]) for c in candidates],
key=lambda x: x[1]
)[0]
optimal_seq.append(ptr)
return reversed(optimal_seq)
private int count(int n, Map<Integer, Integer> lookup) {
if(lookup.containsKey(n)) {
return lookup.get(n);
}
if(n==1) {
return 0;
} else {
int result;
if(n%2==0 && n%3==0) {
result =1+
//Math.min(count(n-1, lookup),
Math.min(count(n/2, lookup),
count(n/3, lookup));
} else if(n%2==0) {
result = 1+ Math.min(count(n-1, lookup),
count(n/2, lookup));
} else if(n%3==0) {
result = 1+ Math.min(count(n-1, lookup), count(n/3, lookup));
} else {
result = 1+ count(n-1, lookup);
}
//System.out.println(result);
lookup.put(n, result);
return result;
}
}

Pascal's triangle

I am looking for a Pascals triangle using python script
I have done till here and have no idea how to add on
numstr= raw_input("please enter the height:")
height = int( )
tri = []
row1 = [1]
row2 = [1, 1]
tri.append(row1)
tri.append(row2)
while len(tri) < height:
You would have to take the last row there is in the triangle and create the next one like this:
Put a 1 at the start of the new row
For every number in the last row except the last, calculate the sum of the number and its right neighbor and put it into the new row
Put another 1 at the end of the new row
You could also calculate the new numbers using binomial coefficients, though that's likely a little more work to get right.
Here's the correct way to make pascal's triangle.
http://ptri1.tripod.com/
http://en.wikipedia.org/wiki/Pascal%27s_triangle
Actually, the next row is crossed axis sum of last row. For example, if the last row is [1, 1], the next row would be:
[1, 1]
+ [1, 1]
-----------
= [1, 2, 1]
[1, 2, 1]
+ [1, 2, 1]
--------------
= [1, 3, 3, 1]
So, the loop body can be like this:
tri.append(map(lambda x, y: x + y, [0] + tri[-1], tri[-1] + [0]))
try the scipy pascal module:
from scipy.linalg import pascal
pascal(6, kind='lower')
output:
array([[ 1, 0, 0, 0, 0, 0],
[ 1, 1, 0, 0, 0, 0],
[ 1, 2, 1, 0, 0, 0],
[ 1, 3, 3, 1, 0, 0],
[ 1, 4, 6, 4, 1, 0],
[ 1, 5, 10, 10, 5, 1]], dtype=uint64)
here is my solution to generate a pascal triangle
def factorial(x):
return 1 if x == 0 else x * factorial(x - 1)
def triangle(n):
return [[factorial(i) / (factorial(j) * factorial(i - j)) for j in range(i + 1)] for i in range(n)]
This is python code for Pascal's triangle:
# python code for Pascal's Triangle
# printPascal() function for printing pascal's triangle.
def printPascal(N):
# declaring 2 array
arr = [1]
temp = []
print("pascal's triangle of", N, "Rows...")
# calculating next rows.
for i in range(N):
# printing current row.
print("rows", i+1, end=" : ")
for j in range(len(arr)):
print(arr[j], end=' ')
print()
# calculating next rows.
temp.append(1)
for j in range(len(arr)-1):
temp.append(arr[j] + arr[j + 1])
temp.append(1)
# copy next row to current row.
arr = temp
# initialize temp to empty array.
temp = []
# Driver code
N = 9
printPascal(N)
For more details:https://algorithmdotcpp.blogspot.com/2021/07/print-n-rows-of-pascals-triangle-in-cpp-and-python.html
// C++ code for pascal triangle
#include<stdio.h>
#include<ctype.h>
#include<conio.h>
#include<time.h>
#include<stdlib.h>
long unsigned int Factorial(long unsigned int Number)
{
long unsigned int Fact=0;
if (Number==0)
return (long unsigned int) 1;
else
{ Fact=Number*Factorial(Number-1);
return Fact;
}
}
long unsigned int Combination(long unsigned int num1,long unsigned int num2)
{
long unsigned int Comb,num3;
long unsigned int Factor1, Factor2,Factor3;
Factor1=Factorial(num1);
Factor2=Factorial(num2);
num3=num1-num2;
Factor3=Factorial(num3);
Comb=Factor1/(Factor2*Factor3);
return(Comb);
}
int main()
{
long unsigned int i,j,Num=0;
long unsigned int **Matrix;
clrscr();
printf(" %d\n " ,sizeof(long unsigned int));
printf("Enter Index of Square Matrix Num =: ");
scanf ("%lu",&Num);
Matrix=(long unsigned int **) malloc(Num*Num*sizeof(long unsigned int *));
for( i=0;i<Num;i++)
{ for (j=0;j<Num;j++)
{ *(*(Matrix+i)+j)=0;
}
}
for(i=0;i<Num;i++)
{ for(j=0;j<=i;j++)
{ printf(" %lu " , *(*(Matrix+i)+j)); }
printf("\n");
}
for(i=0;i<Num;i=i+1)
{
for(j=0;j<=i;j=j+1)
{
*(*(Matrix+i)+j)=Combination(i,j);
}
printf("\n");
}
for(i=0;i<Num;i++)
{
for(j=0;j<=i;j++)
{
// printf(" \n %lu %lu \n",i,j);
printf(" %lu ",*(*(Matrix+i)+j) );
}
printf("\n");
}
getch();
return(0);
}
C# solution:
public IList<IList<int>> Generate(int numRows) {
var result = new List<IList<int>>();
var item1 = new List<int>();
item1.Add(1);
result.Add(item1);
if (numRows == 1)
return result;
var item2 = new List<int>();
item2.Add(1);
item2.Add(1);
result.Add(item2);
if (numRows == 2)
return result;
var i = 2;
while (i != numRows)
{
var data = result.Last().ToArray();
var n = data.Length;
var item = new int[n + 1];
item[0] = 1;
item[n] = 1;
for (var x = 1; x < n; x++)
item[x] = data[x - 1] + data[x];
result.Add(item);i++;
}
return result;
}

Categories