How to analyze the growth of the following code? - java

I already know that the worst case complexity is N, and the best case is Mlog(M) but I just don't see how. Can anybody explain to me why this is the case and what different inputs would cause each case?
public static Iterable<Integer> topM(int[] a, int M){
int N = a.length;
MinPQ<Integer> pq = new MinPQ<Integer>(M+1);
for(int i = 0; i < N; i++){
if(pq.size() < M)
pq.insert(a[i]);
if(pq.min() <= a[i]){
pq.insert(a[i]);
pq.delMin();
}
}
return pq;
}

The complexity is O(Nlog(M)). The worst case is when the array is sorted in a ascending order, in this case each element is inserted to the queue.
The best case is when the array is sorted in a descending order, in this case only the first M elements are inserted. The complexity in the best case is O(N+Mlog(M)).
p.s. the first comment is correct, the second if should be else if.

Related

Finding big O recursion

I'm trying to figure out what is Big O and big Omega from the following piece of code down below.
This code inputs an array of ints, and sorts them in ascending order.
The worst case would be all in descending order {5,4,3,2,1}
,and the best case would be ascending order {1,2,3,4,5}.
static int counter = 0;
static int counter1 = 0;
static int counter2 = 0;
public static int[] MyAlgorithm(int[]a) {
int n = a.length;
boolean done = true;
int j = 0;
while(j<=n-2) {
counter++;
if(a[j]>a[j+1]) {
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
done = false;
}
j = j+1;
}
j = n-1;
while(j>=1) {
counter1++;
if(a[j]<a[j-1]) {
int temp = a[j-1];
a[j-1] = a[j];
a[j] = temp;
done = false;
}
j = j-1;
}
if(!done) {
counter2++;
MyAlgorithm(a);
}
return a;
}
Worst case for each while loop i got was n-1, and for the recursion it was n/2.
Best case is n-1 while loops, and zero recursion
So my big Omega is (n) ( no recursion )
but for Big O, here is the confusing part for me, since there are n/2 recursion calls, does this mean i do N X N (because of n/2 recursion) big O (n^2)? or does it stay big O(n)???
As you said the Omega is Omega(n). In case all numbers in the array a are already in sorted order the code iterates over the array twice, once per while loop. This are n steps O(1) times.
In the worst case you are correct in assuming O(n^2). As you saw, an array sorted in reverse order produces such a worst case scenario. We can also produce a worst case scenario by having a sorted array in increasing order and then only swap the first and last number. Then each run of MyAlgorithm moves that last/first number two positions. After n/2 steps (runs of MyAlgorithm) the numbers reach their final position. Hence, O(n/2 * n) = O(n^2).
Small side note, sorting in general is in O(n log n), so you can sort something only under some circumstances in O(n).

Sum of two numbers equal to the given number

I have an array with positive integers in random order. A number x
from the list is given ,we need to find any two numbers in the list
having sum equal to x.Running time must be less than n^2.
{edit}
What I did is that , I put all the numbers less than half of x in one array and greater than half of x in another array and all greater than x are discarded and then the idea is that the required two numbers must from the two arrays (not from a single array) and by iterating I can get the two numbers.
Now for the worst case I am little confuse is that approach is good? or if anyone guide me something more better than this also can we achieve log n or n *log n ?
Your solution is both wrong, and in O(n^2).
It is wrong since consider x=5 and arr=[1,2,3,5] - the two numbers needed are from one array, not from both.
What if arr=[3,3,6], x=6, you will place both 3s in one list (not greater than x/2 for example), and will fail to find 3+3=6.
Your algorithm runs in O(n^2), because assume exactly half of the elements are greater than x1, and half are smaller than x. Then, the number of combinations you have to check are (n/2*n/2) /2 = n^2/8
To solve it in O(nlogn), think what happens if you sort the data, given a number arr[i], can you find efficiently if there is a number x-arr[i] in the now sorted array?
You can even enhance the above to O(n) average case by placing the elements in a hash-set, and now, given an number y, can you find efficiently if x-y is also in the set?
EDIT:
Stroked out parts are not relevant anymore since OP editted the question, added a new cause of concern instead.
(1) than x/2 in the editted question.
Here is O(n) solution for finding the first pair of indices of array which sums to the expected target. The solution will stop when it finds the first 2 indices that sum to target, if you need all the pairs that add up to target then instead of using int[] result, you can use ArrayList or even a Map, process the complete array and return it with all the pairs of indices. There is an obvious assumption that the Map's hashcode function is really good and there are not much collisions so that map operations perform in O(1) time.
import java.util.*;
public class Solution {
public static void main(String[] args) {
int[] array = new int[] {1,2,4,7,12,67,12,5,9,1,10};
System.out.println(Arrays.toString(sum(array, 68)));
}
public static int[] sum(int[] array, int target) {
int[] result = new int[2];
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
// n iterations
for (int index = 0; index < array.length; index++) {
// constant
if (map.containsKey(target - array[index])) {
result[1] = index;
// constant
result[0] = map.get(target - array[index]);
return result;
}
// constant
map.put(array[index], index);
}
return result;
}
}
Here you go,
Sort the array using merge sort (Time complexity: n logn). Take two pointers/counters, say i & j, one starts from index 0 and another from n-1 (assuming n size of array is n).
if array[i]+array[j]=sum
return;
else if (array[i]+array[j]<sum) i++;
else j--;
Do it until i>j.
Overall time complexity: n logn
/* Time Complexity = O(n)-since HashMap operations take O(1) time*/
public static ArrayList<Integer> twoSum(int[] arr , int target){
if (arr == null){
throw new IllegalArgumentException();
}
ArrayList<Integer> targetHolder = new ArrayList<>();
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0 ; i < arr.length ; i++){
if (map.containsKey(arr[i])){
int index = map.get(arr[i]);
targetHolder.add(index+1);
targetHolder.add(i+1);
}
else{
map.put(target-arr[i], i);
}
}
return targetHolder;
}
public static void main(String[] args) {
int[] A = {1,2,3,4,5,6};
System.out.println(twoSum(A, 6));
}
}
public void function(int[] array, int sum){
for(int i = 0; i < array.length/2; i ++){
for(int j = array.length-1;; j--){
if(array[i]+array[j] < sum) break;
if(array[i]+array[j] == sum) System.out.println(array[i]+" + "+array[j]+" = "+sum);
}
}
}

running time of longest non-decreasing segment in an array

I have a method in java that finds the longest non-decreasing segment in an array.
The method works, however, as part of the assignment, I need to find the running time of size n elements using the method in terms of O(f(n))(i.e upper bound) and Ω(g(n))(i.e lower bound). Can someone help me?
thanks in advance!!
public int maxAscent(int A[])
{
int num = 0;
int count = 1;
int i;
for(i = 0; i < A.length-1; i++)
if(A[i] <= A[i+1])
count++;
else
{
if(count > num)
num = count;
count = 1;
}
if(count > num)
num = count;
return num;
}
The upper and lower bound, as well as the Big O have to do with the loops. The questions to ask are which loops do you have in your code? How many times does each loop run in the worst case and best case scenarios? If a loop contains another loop, you multiply their best cases and their worst cases.
For your particular program, there is one loop, and it goes from 0 to n-1. There is no early out so your best case, worst case, and average case all have the same value.
That would be "n" operations, so O(n), Ω(n) and ø(n).

How to return the smallest integers from array?

I have an array int[] a= {5,3,1,2} and I want to make a method that picks out the "k" smallest numbers and return an array with the k smallest integers in ascending order. But when I run this code I get the output: [1,3].
I know the code skips some numbers somehow, but I cant twist my brain to fix it.
Any ideas?
EDIT: Without sorting the original array.
public static int[] nrSmallest(int[] a, int k) {
if(k <1 || k>a.length)
throw new IllegalArgumentException("must be at least 1");
int[] values= Arrays.copyOf(a, k);
Arrays.sort(values);
int counter= 0;
for(int i= k; i < a.length; i++) {
if(a[i]< values[counter]) {
for(int j= k-1; j> counter; j--) {
values[j]= values[j-1];
}
values[counter]= a[i];
}
if(counter< k) counter++;
}
return values;
}
EDIT: Joop Eggen solved this for me. Scroll down to see answer. Thanks!
As already pointed out in the comments, simply return a part of the sorted array.
public static int[] nrSmallest(int[] a, int k) {
// check parameters..
// copy all so we don't sort a
int[] sorted = Arrays.copyOf(a, a.length);
Arrays.sort(sorted);
return Arrays.copyOf(sorted, Math.min(k, sorted.length));
}
If you can't modify the original array, this is typically done with some type of priority queue, often a binary heap.
The method that you use in your example is O(n^2), and uses O(k) extra space. Sorting the original array and selecting the top k items is O(n log n). If you copy the array and then sort it, it uses O(n) extra space.
Using a heap is O(n log k), and requires O(k) extra space.
There is an O(n) solution that involves manipulating the original array (or making a copy of the array and manipulating it). See Quickselect.
My own testing shows that Quickselect is faster in the general case, but Heap select is faster when the number of items to be selected (k) is less than 1% of the total items (n). See my blog post, When theory meets practice. That comes in quite handy when selecting, say, the top 100 items from a list of two million.
(Corrected) To keep your code:
for (int i= k; i < a.length; i++) {
if (a[i] < values[counter]) { // Found small value
// Insert sorted
for (int j = k-1; j >= 0; j--) {
if (j == 0 || a[i] > values[j-1]) { // Insert pos
// Move greater ones up.
for (int m = k - 1; m > j; m--) {
values[m] = values[m - 1];
}
values[j] = a[i]; // Store
break; // Done
}
}
}
}
int[] values= Arrays.copyOf(a, k); this line is wrong. you are copying only k elements. but you are suppose to copy all elements and then sort the array.
First sort the array and then return the sorted part of the array upto k.
public static int[] nrSmallest(int[] a, int k) {
if(k <1 || k>a.length)
throw new IllegalArgumentException("must be at least 1");
Arrays.sort(a);
return Arrays.copyOf(a,k);
}
You could use the "pivoting" idea of quicksort,
The pivot denotes the "rank" of that number in the array, so your end goal would be having a pivot at index "k", which will result in a subarray less than the Kth element, in other words first K smallest numbers (not exactly sorted).

Finding duplicate element in an array?

I saw a interview question as follows:
One number in array is duplicating.Find it
Simple solution is as follows:
for(int i=0;i<n;i++){
{
dup = false;
for(j=0;j<n;j++){
if(i!=j && a[i]= a[j]){
dup = true;
}
if(dup == true)
return a[i]
}
}
But I want to implement it in O(n log(n)) and in O(n) time. How can i do it?
Sort the array (that can be done in the first O (n Log n) then the comparison just has to be done for the adjacent elements. Or just put the array into a hash table and stop if you find the first key with an exsting entry.
I'm answering to "Finding duplicate element in an array?"
You search for i and j from 0 to < n, and later you check for j != i. Instead you could form your loops like this:
for (int i=0; i<n-1; i++)
{
for (j=i+1; j<n; j++)
{
if (a[i] == a[j])
{
return i;
}
}
}
return -1;
Repeatedly setting dup=false is nonsense. Either dup is still false, or it was true, then you left the code with 'return'.
Writing the previous answers in actual code (Java):
O(n log n) time:
Arrays.sort(arr);
for (int i = 1; i < arr.length; i++)
if (arr[i] == arr[i - 1])
return arr[i];
throw new Exception(); // error: no duplicate
O(n) time:
Set<Integer> set = new HashSet<Integer>();
for (int i = 0; i < arr.length; i++) {
if (set.contains(arr[i]))
return arr[i];
set.add(arr[i]);
}
throw new Exception(); // error: no duplicate
Reference java.util.TreeSet which is implemented Red-Black tree underlying, it's O(n*log(n)).
I recommend to use the hash-map (assuming no collisions) to solve it.
private boolean hasDuplicate(int[] arr) {
Map<Integer, Boolean> map = new HashMap();
// find the duplicate element from an array using map
for (int i = 0; i < arr.length; i++) {
if(map.containsKey(arr[i])) {
return true;
} else {
map.put(arr[i], true);
}
}
return false;
}
Time complexity : O(n)
Space complexity : O(n)
Another approach is sorting and comparing and but the sorting adds extra overhead.
By using collections we can go for below code snippet -
Set<String> set = new HashSet<String>();
for (String arrayElement : arr) {
if (!set.add(arrayElement)) {
System.out.println("Duplicate Element is : " + arrayElement);
}
}
Find O(n) complexity solution as below -
int ar[]={0,1,2,3,0,2,3,1,0,2};
Set <Integer>mySet=new HashSet<>();
for(int n:ar){
if(!mySet.add(n)){
System.out.println(" "+n);
}
}
And another process with lesser space complexity O(N) and possibly O(n Log n) --
public void duplicateElementSolution(int ar[]){
Arrays.sort(ar);
for(int i=0;i<(ar.length-1);i++){
if(ar[i]==ar[i+1]){
System.out.println(" "+ar[i]);
}
}
}
(The question in its current form is a little confusing - my answer is assuming that the question is about finding two numbers in an array that sum to a given value)
Since the given array is unsorted, I am assuming that we are not allowed to sort the array (i.e. the given order of the array cannot be changed).
The simplest solution IMHO is to iterate over each number x and check if I-x occurs anywhere in the arrays. This is essentially what your O(n^2) solution is doing.
This can be brought down to O(n) or O(nlogn) by making the search faster using some sort of fast set data structure. Basically, as we iterate over the array, we query to see if I-x occurs in the set.
Code (in Python):
l=[1,2,3,4,5,6,7,8,9]
seen=set()
I=11
for item in l:
if I-item in seen:
print "(%d,%d)"%(item,I-item)
seen.add(item)
The complexity of the solution depends on the insert/lookup complexity of the set data structure that you use. A hashtable based implementation has a O(1) complexity so it gives you a O(n) algorithm, while a tree based set results in a O(nlogn) algorithm.
Edit:
The equivalent data structure to Python's set would be stl::set in C++ and TreeSet/HashSet in Java. The line I-x in seen would translate to seen.contains(I-x) in Java and seen.find(I-x)==seen.end() in C++.

Categories