I'm trying to solve the problem of finding the MaxDoubleSliceSum value. Simply, it's the maximum sum of any slice minus one element within this slice (you have to drop one element, and the first and the last element are excluded also). So, technically the first and the last element of the array cannot be included in any slice sum.
Here's the full description:
A non-empty zero-indexed array A consisting of N integers is given.
A triplet (X, Y, Z), such that 0 ≤ X < Y < Z < N, is called a double slice.
The sum of double slice (X, Y, Z) is the total of A[X + 1] + A[X + 2] + ... + A[Y − 1] + A[Y + 1] + A[Y + 2] + ... + A[Z − 1].
For example, array A such that:
A[0] = 3
A[1] = 2
A[2] = 6
A[3] = -1
A[4] = 4
A[5] = 5
A[6] = -1
A[7] = 2
contains the following example double slices:
double slice (0, 3, 6), sum is 2 + 6 + 4 + 5 = 17,
double slice (0, 3, 7), sum is 2 + 6 + 4 + 5 − 1 = 16,
double slice (3, 4, 5), sum is 0.
The goal is to find the maximal sum of any double slice.
Write a function:
def solution(A)
that, given a non-empty zero-indexed array A consisting of N integers, returns the maximal sum of any double slice.
For example, given:
A[0] = 3
A[1] = 2
A[2] = 6
A[3] = -1
A[4] = 4
A[5] = 5
A[6] = -1
A[7] = 2
the function should return 17, because no double slice of array A has a sum of greater than 17.
Assume that:
N is an integer within the range [3..100,000];
each element of array A is an integer within the range [−10,000..10,000].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
Here's my try:
def solution(A):
if len(A) <= 3:
return 0
max_slice = 0
minimum = A[1] # assume the first element is the minimum
max_end = -A[1] # and drop it from the slice
for i in xrange(1, len(A)-1):
if A[i] < minimum: # a new minimum found
max_end += minimum # put back the false minimum
minimum = A[i] # assign the new minimum to minimum
max_end -= minimum # drop the new minimum out of the slice
max_end = max(0, max_end + A[i])
max_slice = max(max_slice, max_end)
return max_slice
What makes me think that this may approach the correct solution but some corners of the problem may haven't been covered is that 9 out 14 test cases pass correctly (https://codility.com/demo/results/demoAW7WPN-PCV/)
I know that this can be solved by applying Kadane’s algorithm forward and backward. but I'd really appreciate it if someone can point out what's missing here.
Python solution O(N)
This should be solved using Kadane’s algorithm from two directions.
ref:
Python Codility Solution
C++ solution - YouTube tutorial
JAVA solution
def compute_sum(start, end, step, A):
res_arr = [0]
res = 0
for i in range(start, end, step):
res = res + A[i]
if res < 0:
res_arr.append(0)
res = 0
continue
res_arr.append(res)
return res_arr
def solution(A):
if len(A) < 3:
return 0
arr = []
left_arr = compute_sum(1, len(A)-1, 1, A)
right_arr = compute_sum(len(A)-2, 0, -1, A)
k = 0
for i in range(len(left_arr)-2, -1, -1):
arr.append(left_arr[i] + right_arr[k])
k = k + 1
return max(arr)
This is just how I'd write the algorithm.
Assume a start index of X=0, then iteratively sum the squares to the right.
Keep track of the index of the lowest int as you count, and subtract the lowest int from the sum when you use it. This effectively lets you place your Y.
Keep track of the max sum, and the X, Y, Z values for that sum
if the sum ever turns negative then save the max sum as your result, so long as it is greater than the previous result.
Choose a new X, You should start looking after Y and subtract one from whatever index you find. And repeat the previous steps, do this until you have reached the end of the list.
How might this be an improvement?
Potential problem case for your code: [7, 2, 4, -18, -14, 20, 22]
-18 and -14 separate the array into two segments. The sum of the first segment is 7+2+4=13, the sum of the second segment is just 20. The above algorithm handles this case, yours might but I'm bad at python (sorry).
EDIT (error and solution): It appears my original answer brings nothing new to what I thought was the problem, but I checked the errors and found the actual error occurs here: [-20, -10, 10, -70, 20, 30, -30] will not be handled correctly. It will exclude the positive 10, so it returns 50 instead of 60.
It appears the askers code doesn't correctly identify the new starting position (my method for this is shown in case 4), it's important that you restart the iterations at Y instead of Z because Y effectively deletes the lowest number, which is possibly the Z that fails the test.
Related
I have two lists for example, [5, 6, 3] and [ 5, 7] and I want to return [6,2,0] which is basically 563+57 = 620 where each element is returned in the new list. In case of carryover, I shall get a bigger list.
I am able to do it with the following approach in python:
a = [5,6,3]
b = [5,7]
str_a = ''.join(map(str, a))
str_b = ''.join(map(str, b))
int(str_a)+int(str_b)
lst = [int(i) for i in str(620)]
lst
It can be extended to multiple lists and looping through the lists. However, can it be done by looping through each elements in the given lists? Is that a prefered method compared to map and join string?
PS: I quickly got some down votes when I posted it. Sorry if I was not clear and I hope it is clear now.
Thanks for your help.
I got requested result with below codes, another approach than what Marcos provided and I was able to find as well. Only additional thing is you need is to pad arrays to maximum length + 1 with numpy pad.
def elementsum2array(arr1, arr2):
'''
1. Make the arrays of same length padding at the beginning/left side with 0's
so that arrays get the same same length of "maximum length + 1" (for carry at the end).
2. Get a new array of length "maximum length + 1".
3. Sum the elements of the arrays from last index to first index together with carry.
4. Fill the new array element with sum % 10.
5. Update carry (sum // 10).
'''
if len(arr1) == 0 and len(arr2) > 0:
return arr2
if len(arr1) > 0 and len(arr2) == 0:
return arr1
if len(arr1) == 0 and len(arr2) == 0:
return []
else:
import numpy as np
maxlen = max(len(arr1), len(arr2))
arr1dif = maxlen - len(arr1) + 1
arr2dif = maxlen - len(arr2) + 1
arr1resized = np.pad(arr1, (arr1dif, 0), 'constant')
arr2resized = np.pad(arr2, (arr2dif, 0), 'constant')
L = len(arr1resized)
arrnew = [0 for num in range(maxlen+1)]
carry = 0
elementsum = 0
for i in range(L-1, -1, -1):
elementsum = (arr1resized[i] + arr2resized[i] + carry)
arrnew[i] = elementsum % 10
#print(arrnew[i])
carry = elementsum // 10
#print(carry)
i=i-1
return arrnew
Example:
arr1 = [3,2,1,0,4,9]
arr2 = [5,1,6,4]
elementsum2array(arr1, arr2)
[0, 3, 2, 6, 2, 1, 3]
This was also done in Java here:
sum of two arrays element wise?
Given a list of size N. Find the number of pairs (i, j) such that A[i] XOR A[j] = x, and 1 <= i < j <= N.
Input : list = [3, 6, 8, 10, 15, 50], x = 5
Output : 2
Explanation : (3 ^ 6) = 5 and (10 ^ 15) = 5
This is my code (brute force):
import itertools
n=int(input())
pairs=0
l=list(map(int,raw_input().split()))
q=[x for x in l if x%2==0]
p=[y for y in l if y%2!=0]
for a, b in itertools.combinations(q, 2):
if (a^b!=2) and ((a^b)%2==0) and (a!=b):
pairs+=1
for a, b in itertools.combinations(p, 2):
if (a^b!=2) and ((a^b)%2==0) and (a!=b):
pairs+=1
print pairs
how to do this more efficiently in a complexity of O(n) in python?
Observe that if A[i]^A[j] == x, this implies that A[i]^x == A[j] and A[j]^x == A[i].
So, an O(n) solution would be to iterate through an associate map (dict) where each key is an item from A and each value is the respective count of the item. Then, for each item, calculate A[i]^x, and see if A[i]^x is in the map. If it is in the map, this implies that A[i]^A[j] == x for some j. Since we have a map with the count of all items that equal A[j], the total number of pairs will be num_Ai * num_Aj. Note that each element will be counted twice since XOR is commutative (i.e. A[i]^A[j] == A[j]^A[i]), so we have to divide the final count by 2 since we've double counted each pair.
def create_count_map(lst):
result = {}
for item in lst:
if item in result:
result[item] += 1
else:
result[item] = 1
return result
def get_count(lst, x):
count_map = create_count_map(lst)
total_pairs = 0
for item in count_map:
xor_res = item ^ x
if xor_res in count_map:
total_pairs += count_map[xor_res] * count_map[item]
return total_pairs // 2
print(get_count([3, 6, 8, 10, 15, 50], 5))
print(get_count([1, 3, 1, 3, 1], 2))
outputs
2
6
as desired.
Why is this O(n)?
Converting a list to a dict s.t. the dict contains the count of each item in the list is O(n) time.
Calculating item ^ x is O(1) time, and calculating whether this result is in a dict is also O(1) time. dict key access is also O(1), and so is multiplication of two elements. We do all this n times, hence O(n) time for the loop.
O(n) + O(n) reduces to O(n) time.
Edited to handle duplicates correctly.
The accepted answer is not giving the correct result for X=0. This code handles that minute error. You can modify it to get answers for other values as well.
def calculate(a) :
# Finding the maximum of the array
maximum = max(a)
# Creating frequency array
# With initial value 0
frequency = [0 for x in range(maximum + 1)]
# Traversing through the array
for i in a :
# Counting frequency
frequency[i] += 1
answer = 0
# Traversing through the frequency array
for i in frequency :
# Calculating answer
answer = answer + i * (i - 1) // 2
return answer
I am trying to solve a problem where:
Given an array of n integers nums and a target, find the number of
index triplets i, j, k with 0 <= i < j < k < n that satisfy the
condition nums[i] + nums[j] + nums[k] < target.
For example, given nums = [-2, 0, 1, 3], and target = 2.
Return 2. Because there are two triplets which sums are less than 2:
[-2, 0, 1] [-2, 0, 3]
My algorithm: Remove a single element from the list, set target = target - number_1, search for doublets such that number_1 + number _2 < target - number_1. Problem solved.
The problem link is https://leetcode.com/problems/3sum-smaller/description/ .
My solution is:
def threeSumSmaller(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
nums = sorted(nums)
smaller = 0
for i in range(len(nums)):
# Create temp array excluding a number
if i!=len(nums)-1:
temp = nums[:i] + nums[i+1:]
else:
temp = nums[:len(nums)-1]
# Sort the temp array and set new target to target - the excluded number
l, r = 0, len(temp) -1
t = target - nums[i]
while(l<r):
if temp[l] + temp[r] >= t:
r = r - 1
else:
smaller += 1
l = l + 1
return smaller
My solution fails:
Input:
[1,1,-2]
1
Output:
3
Expected:
1
I am not getting why is the error there as my solution passes more than 30 test cases.
Thanks for your help.
One main point is that when you sort the elements in the first line, you also lose the indexes. This means that, despite having found a triplet, you'll never be sure whether your (i, j, k) will satisfy condition 1, because those (i, j, k) do not come from the original list, but from the new one.
Additionally: everytime you pluck an element from the middle of the array, the remaining part of the array is also iterated (although in an irregular way, it still starts from the first of the remaining elements in tmp). This should not be the case! I'm expanding details:
The example iterates 3 times over the list (which is, again, sorted and thus you lose the true i, j, and k indexes):
First iteration (i = 0, tmp = [1, -2], t = 0).
When you sum temp[l] + temp[r] (l, r are 0, 1) it will be -1.
It satisfies being lower than t. smaller will increase.
The second iteration will be like the first, but with i = 1.
Again it will increase.
The third one will increase as well, because t = 3 and the sum will be 2 now.
So you'll count the value three times (despite only one tuple can be formed in order of indexes) because you are iterating through the permutations of indexes instead of combinations of them. So those two things you did not take care about:
Preserving indexes while sorting.
Ensuring you iterate the indexes in a forward-fashion only.
Try like this better:
def find(elements, upper_bound):
result = 0
for i in range(0, len(elements) - 2):
upper_bound2 = upper_bound - elements[i]
for j in range(i+1, len(elements) - 1):
upper_bound3 = upper_bound2 - elements[j]
for k in range(j+1, len(elements)):
upper_bound4 = upper_bound3 - elements[k]
if upper_bound4 > 0:
result += 1
return result
Seems like you're counting the same triplet more than once...
In the first iteration of the loop, you omit the first 1 in the list, and then increase smaller by 1. Then you omit the second 1 in the list and increase smaller again by 1. And finally you omit the third element in the list, -2, and of course increase smaller by 1, because -- well -- in all these three cases you were in fact considering the same triplet {1,1,-2}.
p.s. It seems like you care more about correctness than performance. In that case, consider maintaining a set of the solution triplets, to ensure you're not counting the same triplet twice.
There are already good answers , Apart that , If you want to check your algorithm result then you can take help of this in-built funtion :
import itertools
def find_(vector_,target):
result=[]
for i in itertools.combinations(vector_, r=3):
if sum(i)<target:
result.append(i)
return result
output:
print(find_([-2, 0, 1, 3],2))
output:
[(-2, 0, 1), (-2, 0, 3)]
if you want only count then:
print(len(find_([-2, 0, 1, 3],2)))
output:
2
I'm a stumped on how to speed up my algorithm which sums multiples in a given range. This is for a problem on codewars.com here is a link to the problem
codewars link
Here's the code and i'll explain what's going on in the bottom
import itertools
def solution(number):
return multiples(3, number) + multiples(5, number) - multiples(15, number)
def multiples(m, count):
l = 0
for i in itertools.count(m, m):
if i < count:
l += i
else:
break
return l
print solution(50000000) #takes 41.8 seconds
#one of the testers takes 50000000000000000000000000000000000000000 as input
# def multiples(m, count):
# l = 0
# for i in xrange(m,count ,m):
# l += i
# return l
so basically the problem ask the user return the sum of all the multiples of 3 and 5 within a number. Here are the testers.
test.assert_equals(solution(10), 23)
test.assert_equals(solution(20), 78)
test.assert_equals(solution(100), 2318)
test.assert_equals(solution(200), 9168)
test.assert_equals(solution(1000), 233168)
test.assert_equals(solution(10000), 23331668)
my program has no problem getting the right answer. The problem arises when the input is large. When pass in a number like 50000000 it takes over 40 seconds to return the answer. One of the inputs i'm asked to take is 50000000000000000000000000000000000000000, which a is huge number. That's also the reason why i'm using itertools.count() I tried using xrange in my first attempt but range can't handle numbers larger than a c type long. I know the slowest part the problem is the multiples method...yet it is still faster then my first attempt using list comprehension and checking whether i % 3 == 0 or i % 5 == 0, any ideas guys?
This solution should be faster for large numbers.
def solution(number):
number -= 1
a, b, c = number // 3, number // 5, number // 15
asum, bsum, csum = a*(a+1) // 2, b*(b+1) // 2, c*(c+1) // 2
return 3*asum + 5*bsum - 15*csum
Explanation:
Take any sequence from 1 to n:
1, 2, 3, 4, ..., n
And it's sum will always be given by the formula n(n+1)/2. This can be proven easily if you consider that the expression (1 + n) / 2 is just a shortcut for computing the average, or Arithmetic mean of this particular sequence of numbers. Because average(S) = sum(S) / length(S), if you take the average of any sequence of numbers and multiply it by the length of the sequence, you get the sum of the sequence.
If we're given a number n, and we want the sum of the multiples of some given k up to n, including n, we want to find the summation:
k + 2k + 3k + 4k + ... xk
where xk is the highest multiple of k that is less than or equal to n. Now notice that this summation can be factored into:
k(1 + 2 + 3 + 4 + ... + x)
We are given k already, so now all we need to find is x. If x is defined to be the highest number you can multiply k by to get a natural number less than or equal to n, then we can get the number x by using Python's integer division:
n // k == x
Once we find x, we can find the sum of the multiples of any given k up to a given n using previous formulas:
k(x(x+1)/2)
Our three given k's are 3, 5, and 15.
We find our x's in this line:
a, b, c = number // 3, number // 5, number // 15
Compute the summations of their multiples up to n in this line:
asum, bsum, csum = a*(a+1) // 2, b*(b+1) // 2, c*(c+1) // 2
And finally, multiply their summations by k in this line:
return 3*asum + 5*bsum - 15*csum
And we have our answer!
I have 2 demotion list that looks like that:
[[1,2,3,],
[4,5,6],
[7,8,9]]
I'm trying to write a generator that yield the sum of a 'path'.
A 'path' starts from left-top corner and goes only on x+1 and y+1 until it's get to it's last element(the right bottom).
For example, a valid path is 1=>2=>5=>6=>9 (sum=23).
None-valid path could be 1=>2=>5=>**4**=>...
So far I have this code:
my_list = [[0, 2, 5], [1, 1, 3], [2, 1, 1]]
def gen(x, y, _sum):
if x + 1 <= len(my_list):
for i1 in gen(x + 1, y, _sum + my_list[y][x]):
yield _sum
if y + 1 <= len(my_list):
for i2 in gen(x, y + 1, _sum + my_list[y][x]):
yield _sum
yield _sum + my_list[y][x]
g = gen(0, 0, 0)
total = 0
for elm in g:
total += elm
print total
I get the error:
for i2 in gen(x, y+1, _sum+my_list[y][x]):
IndexError: list index out of range
The reason for this error is a simple off-by-one error.*
I think what you wanted here is x <= len(my_list) or, equivalently, x+1 < len(my_list); you've doubled-up the +1-ness, causing you to run past the end of the list.
Consider a concrete case:
len(my_list) is 3. x is 2. So, x+1 <= len(my_list) is 3 <= 3, which is true. So you call yourself recursively with gen(3, …).
In that recursive call, 4 <= 3 is false, so, depending on the value of y, you call either:
gen(x, y + 1, _sum + my_list[y][3]), or
_sum + my_list[y][3]
… either of which will raise an IndexError.
Obviously you need to fix the same problem with y as with x.
You can see it running without errors here.
Of course it doesn't actually print out the right result, because there are other problems in your code. Off the top of my head:
total = + elm replaces whatever's in total with the value of elm. You probably wanted +=, not = + here.
Yielding _sum over and over and ignoring the values yielded by the recursive generators can't possibly be doing any good. Maybe you wanted to yield i1 and i2 instead?
I can't guarantee that those are the only problems in your code, just that they are problems.
* I'm assuming here that this is a silly bug, not a fundamental error—you clearly know that indexes are 0-based, since you called the function with gen(0, 0, 0) rather than gen(1, 1, 0).
If you really wanted to brute-force all permissible paths through an N x M matrix, then simply generate all permutations of N - 1 moves to the right plus M - 1 moves down, then use those moves to sum the values along the path:
from itertools import permutations
def gen_path_sum(matrix):
N, M = len(matrix), len(matrix[0])
for path in permutations([(1, 0)] * (N - 1) + [(0, 1)] * (M - 1)):
sum = matrix[0][0]
x = y = 0
for dx, dy in path:
x += dx; y += dy
sum += matrix[x][y]
yield sum
This'll produce (N + M)! paths; there are 720 such paths for a 3 by 3 matrix.
However, if you are trying to find the maximum path through the matrix, you are going about it the inefficient way.
You can instead calculate the maximum path for any cell in the matrix; it is simply the greatest of the maximum path values of the cell above and to the left, plus value of the current cell. So for the cell in the top left (with no cells above or to the right), the maximum path value is the value of the cell.
You can calculate all those values with a N X M loop:
def max_path_value(matrix):
totals = [row[:] for row in matrix]
for x, row in enumerate(totals):
for y, cell in enumerate(row):
totals[x][y] += max(
totals[x - 1][y] if x else 0,
totals[x][y - 1] if y else 0
)
return totals[-1][-1]
This only takes N X M steps, or 9 steps in total for your 3 by 3 matrix. That's a factor of 80 better than the brute-force approach.
The contrast only increases as your matrix sizes increase; a 10x10 matrix, brute forced, requires examining 2432902008176640000 paths (== 20!), or you can just calculate the maximum path with 100 steps instead.