I was doing this example (https://www.learnhowtoprogram.com/computer-science/big-o-notation-and-binary-trees/big-o-practice) and the answer they gave was O(N^2). The reason being - quote, "there is a for loop inside a while loop." This is true but isn't the time comp of assigning array[index1] = array[index2]; and array[index2] = temporaryValue; n. Wouldn't that take big-O to n^3.
function sortByValue(array){
function swap(array, index1, index2){
let temporaryValue = array[index1];
array[index1] = array[index2];
array[index2] = temporaryValue;
}
let count = 1;
while (count < array.length) {
let swapCount = 0;
for (let i=0; i<array.length-count; i++) {
if (array[i] > array[i+1]) {
swap(array, i, i+1);
swapCount++;
}
}
count++;
}
return array;
}
No, the time complexity of
array[index1] = array[index2];
array[index2] = temporaryValue;
is O(1). Accessing or assigning to an array element is constant time (O(1)), and each of these lines is just assigning a single value to another variable. It follows that the entire swap function is O(1). Then, since there is one loop nested inside one other loop that each can take up to array.length iterations, the sortByValue function is O(n^2).
Related
The Question:
Write a function:
class Solution {
public int solution(int[] A) {...}
}
that, given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A.
For example:
Given A = [1, 3, 6, 4, 1, 2], the function should return 5.
Given A = [1, 2, 3], the function should return 4.
Given A = [−1, −3], the function should return 1.
Assume that:
N is an integer within the range [1..100,000]; each element of array A is an integer within the range [−1,000,000..1,000,000].
Complexity:
expected worst-case time complexity is O(N); expected worst-case space complexity is O(N) (not counting the storage required for input arguments).
May I know why I get so low score to answer the question?
My solution below:
public static int solution(int[] A) {
int returnInt = 1;
int maxInt = 0;
if (A.length == 0)
return returnInt;
for (int i = 0; i < A.length; i++)
{
if (A[i] > maxInt)
maxInt = A[i];
}
if (maxInt < returnInt)
return returnInt;
return maxInt % 2 == 0
? maxInt - 1
: maxInt + 1;
}
The solution has only one for loop, I do not understand why I get a very low score.
You can use HashSet<int> exists to store all positive items of A; then you can check if number 1..exists.Count is in exists.
C# code:
public static int solution(int[] A) {
if (A is null || A.Length <= 0)
return 1;
var exists = new HashSet<int>();
foreach (int item in A)
if (item > 0)
exists.Add(item);
for (int i = 1; i <= exists.Count; ++i)
if (!exists.Contains(i))
return i;
return exists.Count + 1;
}
In the worst case we have
Time complexity: O(n), providing that we have good hash function: foreach loop is O(n) - adding to hash set is O(1), for (int i = 1; i <= exists.Count; ++i) is O(n) as well - Contains is O(1) in case of hash set
Space complexity: O(n) (hash set)
If we can allow ourselves to get slightly worse time complexity - O(n * log(n)) we can have O(1) space complexity only:
C# code:
public static int solution(int[] A) {
if (A is null || A.Length <= 0)
return 1;
Array.Sort(A);
for (int i = 0, prior = 0; i < A.Length; prior = Math.Clamp(A[i++], 0, A.Length))
if (A[i] > 0 && A[i] != prior + 1)
return prior + 1;
return Math.Clamp(A[A.Length - 1] + 1, 1, A.Length);
}
OP's performance is "low" certainly because it is producing the wrong answers.
return maxInt % 2 == 0 ? maxInt - 1 : maxInt + 1; makes little sense.
Simplify algorithm.
given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A.
Recognize that between values [1...N+1], there must be at least 1 value not in A[]. A[] has, at most, N different values. Pigeonhole principle
Cost O(N) time, O(N) more space solution, no hash table, no BST:
Form an array B[N+1] of T/F values - set all to false. Index this array [1...N+1]. Cost O(N) time, O(N) more space.
Walk array A. For each A[i], test if A[i] <= N (and A[i] >= 1). If A[i] in range, set B[A[i]] = true. Cost O(N) time.
Walk array B. Find the first B[i] that is false, i is the answer. Cost O(N) time.
Sample C code:
size_t LowestMissingPositive(size_t N, const int A[N]) {
unsigned char Used[N + 1];
memset(Used, 0, sizeof Used);
for (size_t i = 0; i < N; i++) {
if (A[i] >= 1 && (unsigned) A[i] <= N) {
Used[A[i] - 1] = 1;
}
}
for (size_t i = 0; i <= N; i++) {
if (!Used[i]) {
return i + 1;
}
}
// Code never expected to get here.
return N + 1;
}
Note: "each element of array A is an integer within the range [−1,000,000..1,000,000]" is not really an important stipulation other than the type of A[] needs to handle the range. E.g. at least a 21-bit wide integer type.
Create a list L with all integers from A which are bigger than 0. O(n)
Sort L. O(n lg(n))
If L is empty, return 1. If L[0] is not 1, return 1.
Iterate through L. If L[i] != i, return i. O(n)
Total complexity = O(n + n lg(n)) = O(n lg(n)).
What is the total running time of the following code:
I concluded that this code takes O(N log N) times to perform, when the class is being created the loop takes O(N) time to perform, where this for-loop below takes log n time. But I am not completely sure about it, thats why I am asking here.
Z z = new Z(N);
for (int i = 0; i < N-1; i = i+2)
z.update(i,i+1);
Class Z:
public class Z
{
int[] next, prev;
Z(int N)
{
prev = new int[N];
next = new int[N];
for (int i = 0; i<N; ++i)
// put element i in a list of its own
{
next[i] = i;
prev[i] = i;
}
}
int first(int i)
// return first element of list containing i
{
while (i != prev[i]) i = prev[i];
return i;
}
int last(int i)
// return last element of list containing i
{
while (i != next[i]) i = next[i];
return i;
}
void update(int i, int j)
{
int f = first(j);
int l = last(i);
next[l] = f;
prev[f] = l;
}
boolean query(int i, int j)
{
return last(i) == last(j);
}
}
The total running time is only O(N).
The constructor's loop has O(N) steps.
It creates the next/prev arrays as [0, 1, ..., N].
z.update(i,i+1) takes only O(1) time. Since you only call update() once for each i=i and j=i+1, first(j) and last(i) will return j and i, respectively.
It is not possible to analyze the expected complexity of first() and last() under general conditions, as they could easily contain infinite loops (for instance, if called with 0 when next=[1,0]). However, in the example given, they will always skip the while loop entirely, as each call to these functions is on an index that has not yet been modified.
Your for loop takes O(N) time. You run it a total of N/2 times and because you ignore the constant this is N. Total runtime O(N^2). There is no logarithm.
Here is my analysis:
Z z = new Z(N); // O(n)
for (int i = 0; i < N-1; i = i+2) // O(n)
z.update(i,i+1); // O(1)
Hence, the total running time will be O(n).
int first(int i)
{
while (i != prev[i]) i = prev[i]; // O(1), i will always equal prev[i]
// for any input n > 0
return i;
}
int last(int i)
{
while (i != next[i]) i = next[i]; // O(1), i will always equal next[i]
// for any input n > 0
return i;
}
void update(int i, int j)
{
int f = first(j); // O(1)
int l = last(i); // O(1)
next[l] = f; // O(1)
prev[f] = l; // O(1)
}
public static LinkedList third(int[] array){
LinkedList retval = null;
for (int i = 0; i < 999 && i < array.length; i = i + 1) {
retval = new LinkedList(array[i], retval);
}
return retval;
}
Why this code gives big-O = O(1) ?
Because the loop will be executed maximally 999 times which is a constant value therefore You can think of it as it's O(999) = O(1) = O(c), where c is a constant value.
If the value of i wouldn't be limited by 999, the loop would be executed array.length times and the complexity would be O(n), where n is the size of input array.
Magnitude Pole: An element in an array whose left hand side elements are lesser than or equal to it and whose right hand side element are greater than or equal to it.
example input
3,1,4,5,9,7,6,11
desired output
4,5,11
I was asked this question in an interview and I have to return the index of the element and only return the first element that met the condition.
My logic
Take two MultiSet (So that we can consider duplicate as well), one for right hand side of the element and one for left hand side of the
element(the pole).
Start with 0th element and put rest all elements in the "right set".
Base condition if this 0th element is lesser or equal to all element on "right set" then return its index.
Else put this into "left set" and start with element at index 1.
Traverse the Array and each time pick the maximum value from "left set" and minimum value from "right set" and compare.
At any instant of time for any element all the value to its left are in the "left set" and value to its right are in the "right set"
Code
int magnitudePole (const vector<int> &A) {
multiset<int> left, right;
int left_max, right_min;
int size = A.size();
for (int i = 1; i < size; ++i)
right.insert(A[i]);
right_min = *(right.begin());
if(A[0] <= right_min)
return 0;
left.insert(A[0]);
for (int i = 1; i < size; ++i) {
right.erase(right.find(A[i]));
left_max = *(--left.end());
if (right.size() > 0)
right_min = *(right.begin());
if (A[i] > left_max && A[i] <= right_min)
return i;
else
left.insert(A[i]);
}
return -1;
}
My questions
I was told that my logic is incorrect, I am not able to understand why this logic is incorrect (though I have checked for some cases and
it is returning right index)
For my own curiosity how to do this without using any set/multiset in O(n) time.
For an O(n) algorithm:
Count the largest element from n[0] to n[k] for all k in [0, length(n)), save the answer in an array maxOnTheLeft. This costs O(n);
Count the smallest element from n[k] to n[length(n)-1] for all k in [0, length(n)), save the answer in an array minOnTheRight. This costs O(n);
Loop through the whole thing and find any n[k] with maxOnTheLeft <= n[k] <= minOnTheRight. This costs O(n).
And you code is (at least) wrong here:
if (A[i] > left_max && A[i] <= right_min) // <-- should be >= and <=
Create two bool[N] called NorthPole and SouthPole (just to be humorous.
step forward through A[]tracking maximum element found so far, and set SouthPole[i] true if A[i] > Max(A[0..i-1])
step backward through A[] and set NorthPole[i] true if A[i] < Min(A[i+1..N-1)
step forward through NorthPole and SouthPole to find first element with both set true.
O(N) in each step above, as visiting each node once, so O(N) overall.
Java implementation:
Collection<Integer> magnitudes(int[] A) {
int length = A.length;
// what's the maximum number from the beginning of the array till the current position
int[] maxes = new int[A.length];
// what's the minimum number from the current position till the end of the array
int[] mins = new int[A.length];
// build mins
int min = mins[length - 1] = A[length - 1];
for (int i = length - 2; i >= 0; i--) {
if (A[i] < min) {
min = A[i];
}
mins[i] = min;
}
// build maxes
int max = maxes[0] = A[0];
for (int i = 1; i < length; i++) {
if (A[i] > max) {
max = A[i];
}
maxes[i] = max;
}
Collection<Integer> result = new ArrayList<>();
// use them to find the magnitudes if any exists
for (int i = 0; i < length; i++) {
if (A[i] >= maxes[i] && A[i] <= mins[i]) {
// return here if first one only is needed
result.add(A[i]);
}
}
return result;
}
Your logic seems perfectly correct (didn't check the implementation, though) and can be implemented to give an O(n) time algorithm! Nice job thinking in terms of sets.
Your right set can be implemented as a stack which supports a min, and the left set can be implemented as a stack which supports a max and this gives an O(n) time algorithm.
Having a stack which supports max/min is a well known interview question and can be done so each operation (push/pop/min/max is O(1)).
To use this for your logic, the pseudo code will look something like this
foreach elem in a[n-1 to 0]
right_set.push(elem)
while (right_set.has_elements()) {
candidate = right_set.pop();
if (left_set.has_elements() && left_set.max() <= candidate <= right_set.min()) {
break;
} else if (!left.has_elements() && candidate <= right_set.min() {
break;
}
left_set.push(candidate);
}
return candidate
I saw this problem on Codility, solved it with Perl:
sub solution {
my (#A) = #_;
my ($max, $min) = ($A[0], $A[-1]);
my %candidates;
for my $i (0..$#A) {
if ($A[$i] >= $max) {
$max = $A[$i];
$candidates{$i}++;
}
}
for my $i (reverse 0..$#A) {
if ($A[$i] <= $min) {
$min = $A[$i];
return $i if $candidates{$i};
}
}
return -1;
}
How about the following code? I think its efficiency is not good in the worst case, but it's expected efficiency would be good.
int getFirstPole(int* a, int n)
{
int leftPole = a[0];
for(int i = 1; i < n; i++)
{
if(a[j] >= leftPole)
{
int j = i;
for(; j < n; j++)
{
if(a[j] < a[i])
{
i = j+1; //jump the elements between i and j
break;
}
else if (a[j] > a[i])
leftPole = a[j];
}
if(j == n) // if no one is less than a[i] then return i
return i;
}
}
return 0;
}
Create array of ints called mags, and int variable called maxMag.
For each element in source array check if element is greater or equal to maxMag.
If is: add element to mags array and set maxMag = element.
If isn't: loop through mags array and remove all elements lesser.
Result: array of magnitude poles
Interesting question, I am having my own solution in C# which I have given below, read the comments to understand my approach.
public int MagnitudePoleFinder(int[] A)
{
//Create a variable to store Maximum Valued Item i.e. maxOfUp
int maxOfUp = A[0];
//if list has only one value return this value
if (A.Length <= 1) return A[0];
//create a collection for all candidates for magnitude pole that will be found in the iteration
var magnitudeCandidates = new List<KeyValuePair<int, int>>();
//add the first element as first candidate
var a = A[0];
magnitudeCandidates.Add(new KeyValuePair<int, int>(0, a));
//lets iterate
for (int i = 1; i < A.Length; i++)
{
a = A[i];
//if this item is maximum or equal to all above items ( maxofUp will hold max value of all the above items)
if (a >= maxOfUp)
{
//add it to candidate list
magnitudeCandidates.Add(new KeyValuePair<int, int>(i, a));
maxOfUp = a;
}
else
{
//remote all the candidates having greater values to this item
magnitudeCandidates = magnitudeCandidates.Except(magnitudeCandidates.Where(c => c.Value > a)).ToList();
}
}
//if no candidate return -1
if (magnitudeCandidates.Count == 0) return -1;
else
//return value of first candidate
return magnitudeCandidates.First().Key;
}
What is the (a) worst case, (b) best case, and (c) average case complexity of the following function which does bubble sorting
for i=1 to n-1 do
for j=i to n-1 do
if x[j]>x[j+1] then
temp=x[j]
x[j]=x[j+1]
x[j+1]=temp
end {if}
end {for}
end {for}
How would you justify the complexity?
The worst case is O(n2).
The average case is also O(n2).
The worst case too is O(n2), even though the code inside the if statement will not get executed in this case. The quadratic complexity is due to the fact that the two for loops will execute completely in all the three cases irrespective of the content of the list.
Thats true with below BubbleSort algorithm as well, since while is O(n) as well.
public static void BubbleSort( int [ ] num )
{
int j;
boolean flag = true;
int temp;
while ( flag )
{
flag= false;
for( j=0; j < num.length -1; j++ )
{
if ( num[ j ] > num[j+1] )
{
temp = num[ j ]; //swap elements
num[ j ] = num[ j+1 ];
num[ j+1 ] = temp;
flag = true; //shows a swap occurred
}
}
}
}
If you want a bubble sort algorithm which changes dramatically for best, worst and average case efficiency, try this:
int count = n - 1; // The input size
bool sFlag = true; // A flag variable allowing the inner outerloop to
break early and fall through
while (sFlag ){
sFlag = false; // Set false so that the loop can break if no swaps occur
for (int j = 0; j < count; j++){
if (A[j+1] < A[j]){
int temp; // Swap the two elements
temp = A[j];
A[j] = A[j+1];
A[j+1] = temp;
sFlag = true; // A swap has occured, iterate again
}
}
count--; //Next time, don't bother looking at the last element, it is
in order
}
The Worst case for this is Cworst(n) = 1/2n(n+1), best case is Cbest(n) = n-1.
This is because the count variable makes the inner loop iterate less based on the amount of iteration already done relative to the input size.
This is the most efficient bubble sort I've come across so far.