So, I am stuck on a question and I am not sure what I am doing wrong with my code.
Question is- Given an array of integers, find the longest subarray where the absolute difference between any two elements is less than or equal to .
Example a = [1,1,2,2,4,4,5,5,5]
There are two subarrays meeting the criterion: and .
The maximum length subarray has elements.
[1,1,2,2] and [4,4,5,5,5]
Returns
int: the length of the longest subarray that meets the criterion
or visit the link Hackerrank Problem
def pickingNumbers(a):
a.sort()
answer = 0
flag = False
for i in range(len(a)-1,1,-1):
count = 0
temp = [list(l) for l in list(itertools.combinations(a,i))]
for j in temp:
for k in range(len(j)-1):
if abs( j[k+1] - j[k] ) <= 1:
count +=1
if count == len(j):
answer = len(j)
break
Note that the statement asks you to to find a subarray, not subsequence. A subarray is a continuous chain of elements from the parent array. Here by sorting the array you are destroying the parent array's order whenever the array given to you is ascending. Hence your program will give wrong output
Related
Struggling to wrap my head around this.
Maximum Subarray
Easy
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
A subarray is a contiguous part of an array.
Example 1:
Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Example 2:
Input: nums = [1]
Output: 1
Example 3:
Input: nums = [5,4,-1,7,8]
Output: 23
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
subarray1=[]
subarray2=[]
for n in nums:
subarray1.append(sum(nums[nums.index(n):]))
nums2=nums[::-1]
subarray2.append(sum(nums2[nums.index(n):]))
para1=subarray1.index(max(subarray1))
para2=len(nums)-subarray2.index(max(subarray2))
ans=sum(nums[para1:para2])
if sum(nums)>ans :
ans=sum(nums)
if len(nums)==2 and sum(nums)< nums[0] or nums[1] :
ans=max(nums)
return ans
I'm don't understand the iterative logic and the answers from vids are coming up wrong.
My logic is to create an array summing the input array from both sides and use the index of max values on those 2 arrays to figure out the maximum sum sub array parameters.
My answer is supposedly wrong when copied onto leet code https://leetcode.com/problems/maximum-subarray/
Been trying for hours, it's marked as easy. Im sure there is an easy iterative way of doing it but everything I've search is wrong so far.
There is a standard logic to many of these problems. Assume you know what subarray with the largest total is nums[:n - 1]. Then what is the subarray with the largest total you can find for the subarray nums[:n]?
There are two possibilities:
The new answer doesn't contain nums[n-1]. In that case, it has to be the same answer as the old answer
The new answer does contain nums[n-1].
So. . .
The actual algorithm is that you iteratively go through the array, repeatedly adding a new element to the array, and keeping track of two answers:
What is the subarray with the largest total
What is the subarray with the largest total containing the last element.
(This answer may be the same as the previous.)
When you then add a new element to the end of the array:
The subarray with the largest total is either (a) the previous largest total or (b) the previous largest total containing the last element plus the new last element or (c) just the last element. Pick the one with the largest total.
The subarray with the largest total containing the last element is the larger of (b) or (c) above.
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
for i in range(1, len(nums)):
if nums[i-1] > 0:
nums[i] += nums[i-1]
return max(nums)
This is a 2 pass O(n) time complexity solution with constant space.
How it works:
We add each element to its predecessor, provided the predecessor is greater than 0 (greater or equal would also do). The Idea is this: If negative numbers have managed to take it below 0, we discard the prefix and don't care about them anymore. But if some positive value is remaining, we add it since it's better than nothing.
At the end we look for the max value.
To make it one pass, you could just have a best value that at each iteration takes the max. Then you wouldn't need to loop over the array at the end again to take the max.
This is by the way Kadane's algorithm, if you are interested to further read about it.
You can use the Kadane's algorithm to solve this problem in O(n) time and space (and constant extra space). It is a simple dynamic programming algorithm:
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
max_sum = -10**4
current_sum = 0
for n in nums:
current_sum = n if n > current_sum+n else current_sum+n
if current_sum > max_sum:
max_sum = current_sum
return max_sum
Here's my solution, although it exceeds time limit when the input list has a lot of elements. My idea is to try the sum of every sublist and update the max sum accordingly. There's a faster, but more complex approach by using "divide and conquer" method: https://leetcode.com/problems/maximum-subarray/discuss/1849465/Divide-and-Conquer-Approach-with-Python
My solution (works in 200/209 cases because of Time Limit Exceeded):
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
max_sum = - 10 ** 4
for i in range(len(nums)):
for j in range(i + 1, len(nums) + 1):
s = sum(nums[i:j])
if max_sum < s:
max_sum = s
return max_sum
I've been studying python algorithm and would like to solve a problem that is:
A positive integer array A and an integer K are given.
Find the largest even sum of the array A with K elements.
If not possible, return -1.
For example, if there is an array A= [1,2,3,4,4,5] and K= 3,
the answer is 12 (5+4+3),
which is the largest even sum with K (3) elements.
However, if A= [3, 3, 3] and K= 1,
the answer is -1 because it cannot make an even sum with one element.
I tried to exclude every minimum odd from the array, but it failed when K=n in the while loop.
Is there any simple way to solve this problem? I would sincerely appreciate if you could give some advice.
Sort the array and "take" the biggest K elements.
If it's already even sum - you are done.
Otherwise, you need to replace exactly one element, replace an even element you have chosen with an odd one you have not, or the other way around. You need the difference between the two elements to be minimized.
A naive solution will check all possible ways to do that, but that's O(n^2). You can do better, by checking the actual two viable candidates:
The maximal odd element you did not choose, and the minimal
even element you have chosen
The maximal even element you did not choose and the minimal odd element you have chosen.
Choose the one that the difference between the two elements is minimal. If no such two elements exist (i.e. your k=3, [3,3,3] example) - there is no viable solution.
Time complexity is O(nlogn) for sorting.
In my (very rusty) python, it should be something like:
def FindMaximalEvenArray(a, k):
a = sorted(a)
chosen = a[len(a)-k:]
not_chosen = a[0:len(a)-k]
if sum(chosen) % 2 == 0:
return sum(chosen)
smallest_chosen_even = next((x for x in chosen if x % 2 == 0), None)
biggest_not_chosen_odd = next((x for x in not_chosen[::-1] if x % 2 != 0), None)
candidiate1 = smallest_chosen_even - biggest_not_chosen_odd if smallest_chosen_even and biggest_not_chosen_odd else float("inf")
smallest_chosen_odd = next((x for x in chosen if x % 2 != 0), None)
biggest_not_chosen_even = next((x for x in not_chosen[::-1] if x % 2 == 0), None)
candidiate2 = smallest_chosen_odd - biggest_not_chosen_even if smallest_chosen_odd and biggest_not_chosen_even else float("inf")
if candidiate1 == float("inf") and candidiate2 == float("inf"):
return -1
return sum(chosen) - min(candidiate1, candidiate2)
Note: This can be done even better (in terms of time complexity), because you don't actually care for the order of all elements, only finding the "candidates" and the top K elements. So you could use Selection Algorithm instead of sorting, which will make this run in O(n) time.
Could anyone explain exactly what's happening under the hood to make the recursive approach in the following problem much faster and efficient in terms of time complexity?
The problem: Write a program that would take an array of integers as input and return the largest three numbers sorted in an array, without sorting the original (input) array.
For example:
Input: [22, 5, 3, 1, 8, 2]
Output: [5, 8, 22]
Even though we can simply sort the original array and return the last three elements, that would take at least O(nlog(n)) time as the fastest sorting algorithm would do just that. So the challenge is to perform better and complete the task in O(n) time.
So I was able to come up with a recursive solution:
def findThreeLargestNumbers(array, largest=[]):
if len(largest) == 3:
return largest
max = array[0]
for i in array:
if i > max:
max = i
array.remove(max)
largest.insert(0, max)
return findThreeLargestNumbers(array, largest)
In which I kept finding the largest number, removing it from the original array, appending it to my empty array, and recursively calling the function again until there are three elements in my array.
However, when I looked at the suggested iterative method, I composed this code:
def findThreeLargestNumbers(array):
sortedLargest = [None, None, None]
for num in array:
check(num, sortedLargest)
return sortedLargest
def check(num, sortedLargest):
for i in reversed(range(len(sortedLargest))):
if sortedLargest[i] is None:
sortedLargest[i] = num
return
if num > sortedLargest[i]:
shift(sortedLargest, i, num)
return
def shift(array, idx, element):
if idx == 0:
array[0] = element
return array
array[0] = array[1]
array[idx-1] = array[idx]
array[idx] = element
return array
Both codes passed successfully all the tests and I was convinced that the iterative approach is faster (even though not as clean..). However, I imported the time module and put the codes to the test by providing an array of one million random integers and calculating how long each solution would take to return back the sorted array of the largest three numbers.
The recursive approach was way much faster (about 9 times faster) than the iterative approach!
Why is that? Even though the recursive approach is traversing the huge array three times and, on top of that, every time it removes an element (which takes O(n) time as all other 999 elements would need to be shifted in the memory), whereas the iterative approach is traversing the input array only once and yes making some operations at every iteration but with a very negligible array of size 3 that wouldn't even take time at all!
I really want to be able to judge and pick the most efficient algorithm for any given problem so any explanation would tremendously help.
Advice for optimization.
Avoid function calls. Avoid creating temporary garbage. Avoid extra comparisons. Have logic that looks at elements as little as possible. Walk through how your code works by hand and look at how many steps it takes.
Your recursive code makes only 3 function calls, and as pointed out elsewhere does an average of 1.5 comparisons per call. (1 while looking for the min, 0.5 while figuring out where to remove the element.)
Your iterative code makes lots of comparisons per element, calls excess functions, and makes calls to things like sorted that create/destroy junk.
Now compare with this iterative solution:
def find_largest(array, limit=3):
if len(array) <= limit:
# Special logic not needed.
return sorted(array)
else:
# Initialize the answer to values that will be replaced.
min_val = min(array[0:limit])
answer = [min_val for _ in range(limit)]
# Now scan for smallest.
for i in array:
if answer[0] < i:
# Sift elements down until we find the right spot.
j = 1
while j < limit and answer[j] < i:
answer[j-1] = answer[j]
j = j+1
# Now insert.
answer[j-1] = i
return answer
There are no function calls. It is possible that you can make up to 6 comparisons per element (verify that answer[0] < i, verify that (j=1) < 3, verify that answer[1] < i, verify that (j=2) < 3, verify that answer[2] < i, then find that (j=3) < 3 is not true). You will hit that worst case if array is sorted. But most of the time you only do the first comparison then move to the next element. No muss, no fuss.
How does it benchmark?
Note that if you wanted the smallest 100 elements, then you'd find it worthwhile to use a smarter data structure such as a heap to avoid the bubble sort.
I am not really confortable with python, but I have a different approach to the problem for what it's worth.
As far as I saw, all solutions posted are O(NM) where N is the length of the array and M the length of the largest elements array.
Because of your specific situation whereN >> M you could say it's O(N), but the longest the inputs the more it will be O(NM)
I agree with #zvone that it seems you have more steps in the iterative solution, which sounds like an valid explanation to your different computing speeds.
Back to my proposal, implements binary search O(N*logM) with recursion:
import math
def binarySearch(arr, target, origin = 0):
"""
Recursive binary search
Args:
arr (list): List of numbers to search in
target (int): Number to search with
Returns:
int: index + 1 from inmmediate lower element to target in arr or -1 if already present or lower than the lowest in arr
"""
half = math.floor((len(arr) - 1) / 2);
if target > arr[-1]:
return origin + len(arr)
if len(arr) == 1 or target < arr[0]:
return -1
if arr[half] < target and arr[half+1] > target:
return origin + half + 1
if arr[half] == target or arr[half+1] == target:
return -1
if arr[half] < target:
return binarySearch(arr[half:], target, origin + half)
if arr[half] > target:
return binarySearch(arr[:half + 1], target, origin)
def findLargestNumbers(array, limit = 3, result = []):
"""
Recursive linear search of the largest values in an array
Args:
array (list): Array of numbers to search in
limit (int): Length of array returned. Default: 3
Returns:
list: Array of max values with length as limit
"""
if len(result) == 0:
result = [float('-inf')] * limit
if len(array) < 1:
return result
val = array[-1]
foundIndex = binarySearch(result, val)
if foundIndex != -1:
result.insert(foundIndex, val)
return findLargestNumbers(array[:-1],limit, result[1:])
return findLargestNumbers(array[:-1], limit,result)
It is quite flexible and might be inspiration for a more elaborated answer.
The recursive solution
The recursive function goes through the list 3 times to fins the largest number and removes the largest number from the list 3 times.
for i in array:
if i > max:
...
and
array.remove(max)
So, you have 3×N comparisons, plus 3x removal. I guess the removal is optimized in C, but there is again about 3×(N/2) comparisons to find the item to be removed.
So, a total of approximately 4.5 × N comparisons.
The other solution
The other solution goes through the list only once, but each time it compares to the three elements in sortedLargest:
for i in reversed(range(len(sortedLargest))):
...
and almost each time it sorts the sortedLargest with these three assignments:
array[0] = array[1]
array[idx-1] = array[idx]
array[idx] = element
So, you are N times:
calling check
creating and reversing a range(3)
accessing sortedLargest[i]
comparing num > sortedLargest[i]
calling shift
comparing idx == 0
and about 2×N/3 times doing:
array[0] = array[1]
array[idx-1] = array[idx]
array[idx] = element
and N/3 times array[0] = element
It is difficult to count, but that is much more than 4.5×N comparisons.
I have a function match that takes in a list of numbers and a target number and I want to write a function that finds within the array two numbers that add to that target.
Here is my approach:
>>> def match(values, target=3):
... for i in values:
... for j in values:
... if j != i:
... if i + j == target:
... return print(f'{i} and {j}')
... return print('no matching pair')
Is this solution valiant? Can it be improved?
The best approach would result in O(NlogN) solution.
You sort the list, this will cost you O(NlogN)
Once the list is sorted you get two indices, the former points to the first element, the latter -- to the latest element and you check to see if the sum of the elements matches whatever is your target. If the sum is above the target, you move the upper index down, if the sum is below the target -- you move the lower index up. Finish when the upper index is equal to the lower index. This operation is linear and can be done in O(N) time.
All in all, you have O(NlogN) for the sorting and O(N) for the indexing, bringing the complexity of the whole solution to O(NlogN).
There is room for improvement. Right now, you have a nested loop. Also, you do not return when you use print.
As you iterate over values, you are getting the following:
values = [1, 2, 3]
target = 3
first_value = 1
difference: 3 - 1 = 2
We can see that in order for 1 to add up to 3, a 2 is required. Rather than iterating over the values, we can simply ask 2 in values.
def match(values, target):
values = set(values)
for value in values:
summand = target - value
if summand in values:
break
else:
print('No matching pair')
print(f'{value} and {summand}')
Edit: Converted values to a set since it has handles in quicker than if it were looking it up in a list. If you require the indices of these pairs, such as in the LeetCode problem you should not convert it to a set, since you will lose the order. You should also use enumerate in the for-loop to get the indices.
Edit: summand == value edge case
def match(values, target):
for i, value in enumerate(values):
summand = target - value
if summand in values[i + 1:]:
break
else:
print('No matching pair')
return
print(f'{value} and {summand}')
I need help with a certain problem.Suppose you are given a sorted array "A", which has "N" elements and two integers "X" and "Y". Now you are asked two find the number of elements in "A" you have to replace with "X" such that the sum of the array "A" is less than "Y". The given problem can be easily solved in O(n^2) using the following technique.(Only the code snippet for this is specific operation).
sum = None
count = None
for i in range(N):
for j in range(i):
A[j] = X
count += 1
for k in range(N):
sum += A[k]
if sum==Y:
print(count)
count = 0
break
But I want to do this in a more efficient way,can someone suggest a more efficient way?
Thanks In Advance
Since your array is sorted you can:
calculate the sum of your array (O(n))
check if saved_sum<=Y is satisfied (O(1))
Start at the last/first position (depending on where the largest value is)
3.1 check if that value is larger than X, if not it's not possible to reduce the sum of A any further
3.2 replace by X and decrease saved_sum by value-x
3.3 check if saved_sum <= Y, if not repeat at 3.1 with 2nd largest value in A
Whole thing runs in O(n) since A is sorted and largest/next largest can be found in O(1)