Competition practise task (Python) - python

Not sure if it's the best title. The explanation of what the program is suposed to do is below, my version only works with the first example but it doesn't work in the second when you get for example 1 1 3 1 1 2 because i can't figure out a good way to handle so much variations especially if K is bigger than 3 and the limit is 50. My version:
N, K, M = map(int, input().split())
niz = list(map(int, input().split()))
nizk = list(range(1, K+1))
izlazi = []
for r in range(0, M):
operacija = list(map(int, input().split()))
index = 0
if operacija[0] == 2:
nizkk = []
for z in range(0, len(nizk)):
if nizk[z] in niz:
continue
else:
izlazi.append(-1)
break
for p in range(0, N):
if niz[p] not in nizkk:
nizkk.append(niz[p])
nizkk.sort()
if nizkk == nizk:
index = p
izlazi.append(index+1)
break
else:
continue
else:
index, repl = map(int, operacija[1:])
niz[index - 1] = repl
print(izlazi)
In the first line of the input there should be N, K, M (1 <= N, M <= 100k, 1 <= K <= 50, you don't need to actually check this the numbers that are tested will always be in those ranges). In the second line of input you put a list of numbers which are the lenght of N you entered earlier. M is the number of operations you will do in the following lines of input. There can be 2 operations. If you enter 1 p v(p = index of number you want to replace, v the number you replace it with) or if you enter 2 it needs to find the shortest array of numbers defined by range(1, K+1) in the list of numbers you entered in line 2 and possibly changed with operation 1. If it doesn't exist it should output -1 if it does it should output lenght of numbers in the array you look in(numbers can be like 2, 1, 3 if you're looking for 1, 2, 3, also if you're looking for 1, 2, 3 etc and you have 2, 1, 1, 3 as the shortest one that is the solution and it's lenght is 4). Also the replacement operation doesnt count from 0 but from 1. So watch out when managing lists.
These are the examples you can input in the program ulaz = input, izlaz = ouput:

I have the following idea:
Min length sequence either starts from first element or does not contain first element and hence equals to min length of the same sequence without first element.
So we have recursion here.
For sequence [1,1,3,2,1,1] and [1,2,3] we will have:
Min length from start element [1,1,3,2,1,1] is 4
Min length from start element __[1,3,2,1,1] is 3
Min length from start element ____[3,2,1,1] is 3
Min length from start element ______[2,1,1] is -1
Can stop here.
Result is minimum for [4,3,3] = 3
You have already implemented the part for min length, if it starts from the first element. Need now extract it as a function and create a recursive function.
Some metacode:
function GetMinLength(seq)
{
minLengthFromFirstElement = GetMinLenthFromFirstElement(seq)
minLengthFromRest = GetMinLength(seq[1:]) //recusive call
return Min(minLengthFromFirstElement, minLengthFromRest )//-1 results should not count, add extra code to handle it
}
Unfortunately I don't know python, but I can provide code on F# in case you need it.
EDIT:
Try this:
N, K, M = map(int, input().split())
niz = list(map(int, input().split()))
nizk = list(range(1, K+1))
izlazi = []
def GetMinLengthStartingFromFirstElement(seq):
nizkk = []
for z in range(0, len(seq)):
if seq[z] in nizk:
continue
else:
return -1
for p in range(0, len(seq)):
if seq[p] not in nizkk:
nizkk.append(seq[p])
nizkk.sort()
if nizkk == nizk:
index = p
return index+1
else:
continue
return -1
def GetMinLength(seq):
if len(seq) == 0:
return -1
else:
curMinLength = GetMinLengthStartingFromFirstElement(seq)
if curMinLength == -1:
return -1
minLengthFromRest = GetMinLength(seq[1:])
if minLengthFromRest > -1:
return min(curMinLength,minLengthFromRest)
else:
return curMinLength;
for r in range(0, M):
operacija = list(map(int, input().split()))
index = 0
if operacija[0] == 2:
minLength = GetMinLength(niz)
izlazi.append(minLength)
else:
index, repl = map(int, operacija[1:])
niz[index - 1] = repl
print(izlazi)

Related

Stuck in writing python list reduction program

I am stuck in writing the python code for below problem, can anyone help to find the issue with the code is much appreciated.
List Reduction:
You are given a list of integers L having size N and an integer K. You can perform the following operation on the list at most k times:
Pick any two elements of the list.
Multiply any element by 2.
Divide the other element by 2, taking the ceiling if element is odd.
Note: that after such an operation, the list is changed and the changed list will be used in subsequent operations.
You need to minimize the sum of all elements present in the list after performing at most k such operations.
Input Format:
First line contains N K as described above.
The second line contains N space separated integers, representing the list initially,
Output Format:
Print the minimum possible sum of all elements in the list at the end, after performing at most k operations.
Code:
def solve (X, arr):
Sum = 0
largestDivisible, minimum = -1, arr[0]
for i in range(0,N):
Sum += arr[i]
if(arr[i]%X == 0 and largestDivisible < arr[i]):
largestDivisible = arr[i]
if arr[i] < minimum:
minimum = arr[i]
if largestDivisible == -1:
return Sum
sumAfterOperation = (Sum-minimum-largestDivisible+(X*minimum)+(largestDivisible//X))
return min(Sum,sumAfterOperation)
N=5
X =2
#map(int, input().split())
arr = [10, 7, 4, 2, 1]
#list(map(int, input().split()))
out_ = solve(X, arr)
print (out_)
output: 20
expected output: 19
Not optimal program.
Idea: Multiplying the minimal element and dividing the maximal element gives sequence with minimal total sum. Do you want process negative numbers? Does K take negative values?
K = int(input())
arr = list(map(int, input().split()))
for _ in range(K):
arr.sort()
arr[0] *= 2
arr[-1] = arr[-1] // 2 + arr[-1] % 2
print(sum(arr))
More effective solution.
K = int(input())
arr = list(map(int, input().split()))
for _ in range(K):
mn, mx = min(arr), max(arr)
mn_i = arr.index(mn)
if mn != mx:
mx_i = arr.index(mx)
else:
mx_i = arr.index(mx, mn_i+1)
arr[mn_i] *= 2
arr[mx_i] = arr[mx_i] // 2 + arr[mx_i] % 2
print(sum(arr))
And algorithmic solution.
K = int(input())
arr = list(map(int, input().split()))
for _ in range(K):
mn, mx = 0, 0
for i, x in enumerate(arr):
if x < arr[mn]:
mn = i
if x >= arr[mx]:
mx = i
arr[mn] *= 2
arr[mx] = arr[mx] // 2 + arr[mx] % 2
print(sum(arr))

Similarity Measure in Python

I am working on this coding challenge named Similarity Measure. Now the problem is my code works fine for some test cases, and failed due to the Time Limit Exceed problem. However, my code is not wrong, takes more than 25 sec for input of range 10^4.
I need to know what I can do to make it more efficient, I cannot think on any better solution than my code.
Question goes like this:
Problems states that given an array of positive integers, and now we have to answer based upon the Q queries.
Query: Given two indices L,R, determine the maximum absolute difference of index of two same elements lies between L and R
If in a range, there are no two same inputs then return 0
INPUT FORMAT
The first line contains N, no. of elements in the array A
The Second line contains N space separated integers that are elements of the array A
The third line contains Q the number of queries
Each of the Q lines contains L, R
CONSTRAINTS
1 <= N, Q <= 10^4
1 <= Ai <= 10^4
1 <= L, R <= N
OUTPUT FORMAT
For each query, print the ans in a new line
Sample Input
5
1 1 2 1 2
5
2 3
3 4
2 4
3 5
1 5
Sample Output
0
0
2
2
3
Explanation
[2,3] - No two elements are same
[3,4] - No two elements are same
[2,4] - there are two 1's so ans = |4-2| = 2
[3,5] - there are two 2's so ans = |5-3| = 2
[1,5] - there are three 1's and two 2's so ans = max(|4-2|, |5-3|, |4-1|, |2-1|) = 3
Here is my algorithm:
To take the input and test the range in a different method
Input will be L, R and the Array
For difference between L and R equal to 1, check if the next element is equal, return 1 else return 0
For difference more than 1, loop through array
Make a nested loop to check for the same element, if yes, store the difference into maxVal variable
Return maxVal
My Code:
def ansArray(L, R, arr):
maxVal = 0
if abs(R - L) == 1:
if arr[L-1] == arr[R-1]: return 1
else: return 0
else:
for i in range(L-1, R):
for j in range(i+1, R):
if arr[i] == arr[j]:
if (j-i) > maxVal: maxVal = j-i
return maxVal
if __name__ == '__main__':
input()
arr = (input().split())
for i in range(int(input())):
L, R = input().split()
print(ansArray(int(L), int(R), arr))
Please help me with this. I really want to learn a different and a more efficient way to solve this problem. Need to pass all the TEST CASES. :)
You can try this code:
import collections
def ansArray(L, R, arr):
dct = collections.defaultdict(list)
for index in range(L - 1, R):
dct[arr[index]].append(index)
return max(lst[-1] - lst[0] for lst in dct.values())
if __name__ == '__main__':
input()
arr = (input().split())
for i in range(int(input())):
L, R = input().split()
print(ansArray(int(L), int(R), arr))
Explanation:
dct is a dictionary that for every seen number keeps a list of indices. The list is sorted so lst[-1] - lst[0] will give maximum absolute difference for this number. Applying max to all this differences you get the answer. Code complexity is O(R - L).
This can be solved as O(N) approximately the following way:
from collections import defaultdict
def ansArray(L, R, arr) :
# collect the positions and save them into the dictionary
positions = defaultdict(list)
for i,j in enumerate(arr[L:R+1]) :
positions[j].append(i)
# create the list of the max differences in index
max_diff = list()
for vals in positions.values() :
max_diff.append( max(vals) - min(vals) )
# now return the max element from the list we have just created
if len(max_diff) :
return max(max_diff)
else :
return 0

How to optimize this code to reduce execution time?

The question is here:
https://www.hackerrank.com/challenges/equal-stacks/problem
I am getting a termination error due to time out!
Please help me out.
Algorithm explanation:
Step I.
get the 3 array and reverse them, create a new array out of an existing array with each element is sum of all the previous elements. eg: [3,2,1,1,1] -> [1,1,1,2,3] -> [1,2,3,5,8]
So the 3 new array formed would be [1,2,3,5,8] [2,5,9] [1,5,6,7]
Step II.
Again reverse the array [8,5,3,2,1] [9,5,2] [7,6,5,1]
Step III.
Take the smallest array i.e. [9,5,2] traverse the smallest array and search element in the other 2 array - if the element is existing in other 2 array, STOP there and return the number.
Eg. Here I start with elem - 9 : Which is not existing in other 2 array. Next I start with elem - 5 : it is existing in other 2 array.
Hence the answer is 5.
import os
import sys
def equalStacks(h1, h2, h3):
new_h1=[]
new_h2=[]
new_h3=[]
h1=list(reversed(h1))
h2=list(reversed(h2))
h3=list(reversed(h3))
new_h1.append(h1[0])
new_h2.append(h2[0])
new_h3.append(h3[0])
bol=False
ans=-1
for i in range(len(h1)-1):
new_h1.append(new_h1[i]+h1[i+1])
for i in range(len(h2)-1):
new_h2.append(new_h2[i]+h2[i+1])
for i in range(len(h3)-1):
new_h3.append(new_h3[i]+h3[i+1])
low=min([n1,n2,n3])
if low==n1:
for i in list(reversed(new_h1)):
if (i in list(reversed(new_h2))) and (i in list(reversed(new_h3))):
bol=True
ans=i
break
else:
pass
elif low==n2:
for i in list(reversed(new_h2)):
if (i in list(reversed(new_h1))) and (i in list(reversed(new_h3))):
bol=True
ans=i
break
else:
pass
else:
for i in list(reversed(new_h2)):
if (i in list(reversed(new_h1))) and (i in list(reversed(new_h3))):
bol=True
ans=i
break
else:
pass
if bol==True:
return(print(i))
else:
return(print(0))
if __name__ == '__main__':
n1N2N3 = input().split()
n1 = int(n1N2N3[0])
n2 = int(n1N2N3[1])
n3 = int(n1N2N3[2])
h1 = list(map(int, input().rstrip().split()))
h2 = list(map(int, input().rstrip().split()))
h3 = list(map(int, input().rstrip().split()))
result = equalStacks(h1, h2, h3)
I am getting a timeout error....please help me to optimize this code.
If the stacks aren't the same height, then at least one is shorter than the tallest one. The shortest one can't be made taller, so the tallest one must be made shorter.
Pop an item off the tallest stack.
Repeat until they are all the same height.
One possible solution with itertools:
data = '''
3 2 1 1 1
4 3 2
1 1 4 1
'''
from itertools import accumulate, chain, groupby
# prepare the data
data = [[*map(int, line.split())] for line in data.splitlines() if line.strip()]
max_height = 0
for v, g in groupby( sorted(chain(*[accumulate(stack[::-1]) for stack in data]), reverse=True) ):
if sum(1 for _ in g) == 3:
max_height = v
break
print(max_height)
Prints:
5
Simple solution.
Ping me if you are not able to understand.
Here simply apply greedy approach to remove the minimum height cylinder from stack one by one until we get maximum equal height.
def equalStacks(h1, h2, h3):
h1.reverse()
h2.reverse()
h3.reverse()
i = sum(h1)
j = sum(h2)
k = sum(h3)
while i != 0 or j !=0 or k!= 0:
x = min(i,j,k)
if i > x:
i -= h1.pop()
if j > x :
j -= h2.pop()
if k > x:
k -= h3.pop()
if i == j and j == k:
return i
return 0

Unable to get solution correct for submission

It is a sample problem for practice (here), and is not getting accepted due to it giving 'wrong answer'. It is compiling fine, but might be for different test inputs failing on submission.
I just request comment for the same, as hope that the issue must be small.
The problem statement is:
The program should accept first line of input as no. of strings, s.t. it is less than 10. And the next lines should contain one string each of length less than 100 characters. Need find occurrence of "gfg" in the strings.
If no occurrence is found, -1 should be returned.
#code
t = int(input())
if t > 10 or t<0:
exit()
arr = [[0] for i in range(t)]
total = [[-1] for i in range(t)]
for i in range(t):
arr[i] = [k for k in input().split()[:1]]
for j in arr[i]:
total[i] = j.count("gfg")
if total[i]==0: total[i]=-1
print (total[i])
t = int(input())
if t not in range(10):
exit()
else:
pass
total = []
for i in range(t):
line = input()[:100]
if line.count("gfg") == 0:
total.append(-1)
else:
total.append(line.count("gfg"))
print('\n'.join(map(str, total)))
SOLUTION FOR YOUR TASK:
t = int(input())
total = []
for i in range(1, t + 1):
line = input()
if len(line)<=100:
count = 0
for i in range(0, len(line) - 3 + 1):
if line[i:i + 3] == "gfg":
count += 1
if count != 0:
total.append(count)
else:
total.append(-1)
for i in total:
print (i)
NOTE: your submitting was failing because of special cases
For example:
in string gfgfg, your substring "gfg" occurres 2 times, and in that case you can't use the string count() method
how you can see ,here line[i:i + 3] I am moving index by index and checking next 3 values (because your substing "gfg" have length 3)
You are erasing the value of total[i] each time you iterate in the last loop :
>>> for j in arr[i]:
>>> total[i] = j.count("gfg")
>>> if total[i]==0:
>>> total[i]=-1
>>> print (total[i])
Do you want to count the occurences in each word or in the whole sentence ? Because then you just have to write :
>>> for i in range(t):
>>> n_occ = input().count("gfg")
>>> if n_occ != 0:
>>> total[i] = n_occ
If there's no occurence you don't have to do anything because the value in total is -1 already.
Also, write:
>>> total = [-1]*t
not:
>>> total = [[-1] for i in range(t)]

Merge Sort Index Error

def merge (seq, p, q, r):
# n1: length of sub-array [p..q]
n1 = q - p + 1
# n2: length of sub-array [q+1 ..r]
n2 = r - q
# Left and Right arrays
left_arr = []
right_arr = []
for i in xrange(0, n1):
left_arr.append( seq[p+i] )
for j in xrange(0, n2):
right_arr.append( seq[q+j+1] )
j=0
i=0
for k in xrange(p,r+1):
if left_arr[i]<= right_arr[j]:
seq[k]=left_arr[i]
i+=1
else:
seq[k]=right_arr[j]
j+=1
return seq
s = [2,4,5,7,1,2,3,6]
p = 0
q = 3
r = 7
print merge(s,p,q,r)
How it works:
A unsorted sequence s is taken, along with the index numbers where the sequence has to be merged. (p=initial, r = final, q=middle)
Now, left_arr and right_arr are [p,q], [q+1, r] respectively
we take left_arr and right_arr initial values (i=0, j=0). We iterate over the sequence seq...
while iterating we are replacing the values of seq with the sorted values...
The above function is able to sort till last number "7".. at the end, its showing "IndexError". I can use exception handling to catch it and fix but I think... for merge sort, its too much.. Can anyone help me in fixing the code as easy as possible.
I am learning Algorithms.. (following book: Introduction to Algorithms by Thomas H. Cormen)
the problem is that at the last iteration i will be equal to 4 and you are trying to access left_arr[5] which does not exist. you should add a stopping condition when i or j become larger then the size of the corresponding array, and then add all the remaining elements in the other array to seq.
Here is a code that works:
def merge (seq, p, q, r):
# n1: length of sub-array [p..q]
n1 = q - p + 1
# n2: length of sub-array [q+1 ..r]
n2 = r - q
# Left and Right arrays
left_arr = seq[p:n1] #here
right_arr = seq[n1:r+1] #here
j=0
i=0
for k in xrange(p, r+1):
if left_arr[i]<= right_arr[j]:
seq[k]=left_arr[i]
i+=1
if i > n1-1: #here
break
else:
seq[k]=right_arr[j] #here
j+=1
if j > n2-1:
break
if i >= len(left_arr): #from here down
seq[k+1:] = right_arr[j:]
elif j >= len(right_arr):
seq[k+1:] = left_arr[i:]
return seq
s = [2,4,5,7,1,1,1,1]
p = 0
q = 3
r = 7
print merge(s,p,q,r)
I have marked with comments the places where I have edited your code.
The problem with your code is that you're looping over xrange(p, r+1), so during that loop in some iteration the value of either i or j might become equal the value of len(left) or len(right), causing the IndexError eventually.
def merge(seq,p,q,r):
left=seq[p:q+1] #a better way to fetch the list
right=seq[q+1:]
i=0
j=0
#you shuldn't loop over the length of seq as that might make the value of either i or j
# greater than the length of left or right lists respectively.
# so you should only loop until one of the lists is fully exhausted
while i<len(left) and j<len(right):
if left[i] <= right[j] :
seq[i+j]=left[i]
i+=1
else:
seq[i+j]=right[j]
j+=1
#now the while loop is over so either right or left is fully traversed, which can be
#find out my matching the value of j and i with lenghts of right and left lists respectively
if j == len(right):
seq[i+j:]=left[i:] #if right is fully traversed then paste the remaining left list into seq
elif i==len(left): #this is just vice-versa of the above step
seq[i+j:]=right[j:]
print seq
s = [2,4,5,7,1,2,3,6]
p = 0
q = 3
r = 7
merge(s,p,q,r)
output:
[1, 2, 2, 3, 4, 5, 6, 7]
You didn't check the array index while iterating left_arr and right_arr.
You should merge the left part of either array when another array ends.
for k in xrange(p,r+1):
if left_arr[i]<= right_arr[j]:
seq[k]=left_arr[i]
i+=1
else:
seq[k]=right_arr[j]
j+=1
# --------------- add this ----------------
# if any array ends, merge the left elements of the other array
if i >= len(left_arr):
seq[k:] = right_arr[j:]
break
elif j >= len(right_arr):
seq[k:] = left_arr[i:]
break
# --------------- end ----------------
return seq

Categories