I was working on a problem where you have to square the numbers in a sorted array on leetcode. Here is the original problem
Given an array of integers A sorted in non-decreasing order, return an array of the squares of each number, also in sorted non-decreasing order.
I am trying to understand the big O for my code and for the code that was given in the solution.
This is my code
def sortedSquare(A):
new_A = []
for num in A:
num = num*num
new_A.append(num)
return sorted(new_A)
print(sortedSquare([-4, -1, 0, 3, 10]))
Here is the code from the solution:
def sortedSquares(self, A):
return sorted(x*x for x in A)
For the solution, the Big O is
NlogN
Where N is the length of the array. I don't understand why it would be logN and not just N for the Big O?
For my solution, I am seeing it as Big O of N because I am just iterating through the entire array.
Also, is my solution a good solution compared to the solution that was given?
Your solution does the exact same thing as the given solution. Both solutions square all the elements and then sort the resultant array, with the leetcode solution being a bit more concise.
The reason why both these solutions are O(NlogN) is because of the use of sorted(). Python's builtin sort is timsort which sorts the array in O(NlogN) time. The use of sorted(), not squaring, is what provides the dominant factor in your time complexity (O(NlogN) + O(N) = O(NlogN)).
Note though that this problem can be solved in O(N) using two pointers or by using the merge step in mergesort.
Edit:
David Eisenstat brought up a very good point on timsort. Timsort aggregates strictly increasing and strictly decreasing runs and merges them. Since the resultant squared array will be first strictly decreasing and then strictly increasing, timsort will actually reverse the strictly decreasing run and then merge them in O(N).
The way complexity works is that the overall complexity for the whole program is the worst complexity for any one part. So, in your case, you have the part that squares the numbers and you have the part that sorts the numbers. So which part is the one that determines the overall complexity?
The squaring part is o(n) because you only touch the elements once in order to square them.
What about the sorting part? Generally it depends on what sorting function you use:
Most sort routines have O(n*log(n)) because they use a divide and conquer algorithm.
Some (like bubble sort) have O(n^2)
Some (like the counting sort) have O(n)
In your case, they say that the given solution is O(n*log(n)) and since the squaring part is O(n) then the sorting part must be O(n*log(n)). And since your code uses the same sorting function as the given solution your sort must also be O(n*log(n))
So your squaring part is O(n) and your sorting part is O(n*log(n)) and the overall complexity is the worst of those: O(n*log(n))
If extra storage space is allowed (like in your solution), the whole process can be performed in time O(N). The initial array is already sorted. You can split it in two subsequences with the negative and positive values.
Square all elements (O(N)) and reverse the negative subsequence (O(N) at worse), so that both sequences are sorted. If one of the subsequences is empty, you are done.
Otherwise, merge the two sequences, in time O(N) (this is the step that uses extra O(N) space).
Related
I am stuck on finding a solution for finding all the contiguous subarrays of a given array in minimum time complexity O(n).
For example:
[1,2,3,4]
Subarrays are:
[1][2][3][4][1,2][2,3][3,4][1,2,3][2,3,4][1,2,3,4]
I have done it with time complexity O(n^2) but for the large inputs taking lot of time and memory.
Are there any specific algorithms for this problem?
There are exactly n(n+1)/2 subarrays, which can be written as A[i..j] for all i and and all j≥i. The algorithm to generate all pairs is immediate (double loop) and cannot be improved.
If you just need to output the pairs (i, j), space O(1) suffices. If you need to store all pairs, O(n²). And if you need to store all subarrays in full, O(n³); in this case, the time also unavoidably grows to O(n³) and there is another nested loop.
Update:
This answer does not take int account the constraint "the sum of those individual subarray results in perfect square root" in the comments, which was added after the fact and cannot be considered part of the question.
Given a list of integers a1,a2,...,an, write an algorithm that checks if there is a pair ai,aj such that ai-aj= M. The time complexity of the algorithm should be O(nlogn) or better.
As far as I am concerned, when the problem is ai+aj=M, this problem is very easy to solve. But I am in trouble now when the condition is ai- aj=M.
You can solve this using two divide and conquer algorithms.
First, sort the set using merge sort, which is O(logn).
Then, one-by-one, you can look at an element, ai, and see if M-ai, which will be aj, is an element. Since the array is sorted, you can run a binary search, which is also a divide and conquer algorithm and runs in O(logn). In the worst case, you will need to do this n times, once for every element in the list.
Therefore, the running time of this algorithm is O(logn + n*logn) = O(nlogn)
Hey so I'm just really stuck on this question.
I need to devise an algorithm (no need for code) that sorts a certain partially sorted array into a fully sorted array. The array has N real numbers and the first N-[N\sqrt(N)] (the [] denotes the floor of this number) elements are sorted, while are the rest are not. There are no special properties to the unsorted numbers at the end, in fact I'm told nothing about them other than they're obviously real numbers like the rest.
The kicker is time complexity for the algorithm needs to be O(n).
My first thought was to try and sort only the unsorted numbers and then use a merge algorithm, but I can't figure out any sorting algorithm that would work here in O(n). So I'm thinking about this all wrong, any ideas?
This is not possible in the general case using a comparison-based sorting algorithm. You are most likely missing something from the question.
Imagine the partially sorted array [1, 2, 3, 4564, 8481, 448788, 145, 86411, 23477]. It contains 9 elements, the first 3 of which are sorted (note that floor(N/sqrt(N)) = floor(sqrt(N)) assuming you meant N/sqrt(N), and floor(sqrt(9)) = 3). The problem is that the unsorted elements are all in a range that does not contain the sorted elements. It makes the sorted part of the array useless to any sorting algorithm, since they will stay there anyway (or be moved to the very end in the case where they are greater than the unsorted elements).
With this kind of input, you still need to sort, independently, N - floor(sqrt(N)) elements. And as far as I know, N - floor(sqrt(N)) ~ N (the ~ basically means "is the same complexity as"). So you are left with an array of approximately N elements to sort, which takes O(N log N) time in the general case.
Now, I specified "using a comparison-based sorting algorithm", because sorting real numbers (in some range, like the usual floating-point numbers stored in computers) can be done in amortized O(N) time using a hash sort (similar to a counting sort), or maybe even a modified radix sort if done properly. But the fact that a part of the array is already sorted doesn't help.
In other words, this means there are sqrt(N) unsorted elements at the end of the array. You can sort them with an O(n^2) algorithm which will give a time of O(sqrt(N)^2) = O(N); then do the merge you mentioned which will also run in O(N). Both steps together will therefore take just O(N).
I had this exercice in an exam which stated:
Find an algorithm which can search for the highest number in an
unsorted list and have a Big-Oh complexity of O(log(N)).
The only searching algorithm with a log n complexity that I have found is the binary search algorithm but that one requires my list/array to be sorted.
Is there such an algorithm?
This is a trick question. It has not been stated that the list has N elements. So, you can use a change of variable, and replace N with 2K. Now, solve the problem with a linear algorithm on a list with K elements.
If we assume there are N elements in the list, a possible solution would be to use N parallel computing elements [ CE0 .. CEN ]. In the base case of the algorithm, we let each computing element CEi in [ CEN/2 .. CEN ] compare list values x2i-N and x2i-N+1. Each computing element reports the larger of their two assigned values to CEi/2. The iterative steps of the algorithm is that each computing element CEk that receives two reported values reports the largest to CEk/2. This iterative logic continues until CE0 processes a report from itself. Instead of reporting to itself again, it outputs the result.
If parallel computation is ruled out, then there is no solution to the problem.
No, there is no such algorithms. In a unsorted list, find a highest number require to browse through all elements.
So, no algorithm better than O(n) exists!
The best one can do is O(n) time in an unsorted array.
But instead of simply looking through the whole list you can apply a partition() routine (from the quicksort algorithm) and instead of recursing on the lower half of the partition you can recurse on the upper half and keep partitioning until the largest element is found. This takes O(n) time.
Check out for detailed explanation:
http://en.wikipedia.org/wiki/Quickselect
How to find the kth largest element in an unsorted array of length n in O(n)?
Hope it helped! :)
So if you use quick sort to sort an array you can do it in O(nlogn) using quicksort and then once you sort it, you can insert new elements into the array in O(logn) with a binary-search-esque algorithm.
My question is, is there a way to prove that if you can insert into a sorted array in O(logn) time, then that means that the sorting algorithm would have had to be at least O(nlogn)?
In other words, is there a relationship between the two algorithms' running times?
No: it would be possible to use bubblesort (O(n²)) to sort the array. After that, it would still be possible to use the same algorithm to insert at O(log(n)) time.
Well, the fact that insertion which maintains order is O(log n) means that a sort operation can be performed in O(n log n) simply by inserting each element in turn into the array. This however is probably the opposite of what you're really asking; it proves that there is an O(n log n) sort, but doesn't disprove the possibility of a faster sort.
First off, some sorting algorithms, which require special conditions, have a potentially lower time complexity. For instance Counting Sort which has complexity of O(n+k) (where k is the highest number in the array) or Radix Sort with the complexity of O(n*k) (where k is the maximal number of digits in the arrays elements).
The bound of O(nlogn) applies to comparison algorithms.
Second, to answer the question, no (sadly). The relation between insertion and sorting is the other way around, just like davmac said.
The reason that the lower bound on comparison is that you require at least nlogn comparisons to find the right order. See This wiki page on comparison sort algorithms for more details. Just note that the prof has nothing to do with insertion (the prof does not assume any insertions actually).