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
Related
Write a function that takes an array/list of numbers and returns a number.
See the examples and try to guess the pattern:
even_odd([1,2,6,1,6,3,1,9,6]) => 393
even_odd([1,2,3]) => 5
even_odd([0,2,3]) => 3
even_odd([1,0,3]) => 3
even_odd([3,2]) => 6
def even_odd(arr):
count = 0
index = 0
length = len(arr)
while index < length:
for num in range(len(arr)):
if arr[index] % 2 != 0:
count += arr[index]
index += 1
else:
count *= arr[index]
index += 1
return count
So basically the pattern is multiply the first 2 numbers and add the third and I set it to where for each index value if it it was the first number I would add it to the count to keep track and then multiply it with the second number and then add the third. I passed 3/4 sample cases except for one which was the first one ---> even_odd([1,2,6,1,6,3,1,9,6]) => 393. I am just wondering what is the flaw with my logic and does anyone have a better way to solve this that is efficient and clean.
Your question is a challenge on Codewars (https://www.codewars.com/kata/559e708e72d342b0c900007b), so maybe you should use this platform to discuss solutions with other competitiors, instead of Stackoverflow.
The main point of this challange is to investigate the calculated pattern and not the code itself.
If you know the required pattern, the code is easy (Spoiler!):
def even_odd(arr):
num = 0
for i, e in enumerate(arr):
if (i % 2) == 0:
num += e
else:
num *= e
return num
This produces the desired results:
from operator import add, mul
def even_odd(nums):
acc = nums[0] # accumulator
ops = [mul, add]
i = 0
for num in nums[1:]:
acc = ops[i](acc, num)
i = 1 - i # alternates between the two operators
return acc
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
I have a list of numbers. Now if I set a fixed value V, is it possible for python to divide the list into several groups such that each group's sum is not smaller than V (get those groups as many as possible)?
Ex: if the list is [1,2,3,4,5] and the V is 6, then the result should be [[1,5],[2,3,4]]. Dividing the group means you cannot use the same original item more than once.
There's no limitation on how many items each sublist can contain and also the numbers are not in order (can be some random numbers). Could someone help me out? So far my solution is sum up all the combinations and compare the sums. But I'm pretty sure there should be a more effective solution. Thanks!
My solution: I kinda use this first and do the rest job by my mind, so it doesn't worth a further development.
import itertools
import math
stuff = list(range(10))
v = 6
for L in range(0, len(stuff)+1):
for subset in itertools.combinations(stuff, L):
if math.fsum(subset) > v:
print(subset,math.fsum(subset))
My solution has O(n^2) time complexity. You can sort list in ascending order. Then iterate over list from the end. As You want max number of subsets, then each value greater then V added to array. In other case collect values from right and left corners while achieve sum of subset equals to V:
def get_value_in_dict(d):
return d.get(list(d)[0])
# Implementation for a list of dictionaries like [{'apple':1},{'pear':22},{'hat':23},{'glass':44}]
def sum_up_to_value(stuff, val):
new_stuff = []
sorted_stuff = list(sorted(stuff, key=lambda el: get_value_in_dict(el)))
n = len(stuff)
pointer_r = n - 1
pointer_l = 0
queue = list()
while pointer_r >= pointer_l:
if get_value_in_dict(sorted_stuff[pointer_r]) >= val:
new_stuff.append([sorted_stuff[pointer_r]])
else:
subsum = get_value_in_dict(sorted_stuff[pointer_r])
substuff = []
while pointer_l < pointer_r and subsum < val:
# get from queue
while len(queue) and subsum < val:
temp = queue.pop(0)
subsum += get_value_in_dict(temp)
substuff.append(temp)
# get from input
else:
if subsum < val:
subsum += get_value_in_dict(sorted_stuff[pointer_l])
substuff.append(sorted_stuff[pointer_l])
pointer_l += 1
substuff.append(sorted_stuff[pointer_r])
# returns back smallest elements
while subsum - get_value_in_dict(substuff[0]) >= val:
temp = substuff.pop(0)
queue.append(temp)
subsum -= get_value_in_dict(substuff[0])
if subsum < val:
# add substuff to last element of new_stuff
temp = new_stuff.pop()
new_stuff.append(temp + substuff)
else:
new_stuff.append(substuff)
pointer_r -= 1
return new_stuff # list(map(lambda el: sorted(el, key=lambda el_d: get_value_in_dict(el_d)), new_stuff)) for sorted by value elements in resulting list
If you sort your list, this should get you the desired result, although it's not very beautiful as I have to admit:
stuff = range(10)
l = len(stuff)
v = 6
new_stuff = []
i = 0
active = True
while active:
sub_stuff = []
subsum = 0
while subsum<v:
if i>(l-1):
active = False
break
el = stuff[i]
sub_stuff.append(el)
subsum += el
i += 1
else:
new_stuff.append(sub_stuff)
It just goes through your list and sums element until their sum is 6 or higher and then appends a list of those elements to new_stuff and goes on to find the next list.
Try a test list like:
import numpy as np
stuff = sorted(np.random.randint(0,10,100))
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)
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