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).
Related
Working on the following problem:
Given a string s, find the length of the longest substring without repeating characters.
I'm using this brute force solution:
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
if (checkRepetition(s, i, j)) {
res = Math.max(res, j - i + 1);
}
}
}
return res;
}
private boolean checkRepetition(String s, int start, int end) {
int[] chars = new int[128];
for (int i = start; i <= end; i++) {
char c = s.charAt(i);
chars[c]++;
if (chars[c] > 1) {
return false;
}
}
return true;
}
}
Tbe big O notation is as follows:
I understand that three nested iterations would result in a time complexity O(n^3).
I only see two sigma operators being used on the start of the formula, could someone enlighten me on where the third iteration comes to play in the beginning of the formula?
The first sum from i=0 to n-1 corresponds to the outer for loop of lengthOfLongestSubstring, which you can see iterates from i=0 to n-1.
The second sum from j = i+1 to n corresponds to the second for loop (you could be starting j at i+1 rather than i as there's no need to check length 0 sub-strings).
Generally, we would expect this particular double for loop structure to produce O(n^2) algorithms and a third for loop (from k=j+1 to n) to lead to O(n^3) ones. However, this general rule (k for loops iterating through all k-tuples of indices producing O(n^k) algorithms) is only the case when the work done inside the innermost for loop is constant. This is because having k for loops structured in this way produces O(n^k) total iterations, but you need to multiply the total number of iterations by the work done in each iteration to get the overall complexity.
From this idea, we can see that the reason lengthOfLongestSubstring is O(n^3) is because the work done inside of the body of the second for loop is not constant, but rather is O(n). checkRepitition(s, i, j) iterates from i to j, taking j-i time (hence the expression inside the second term of the sum). O(j-i) time is O(n) time in the worst case because i could be as low as 0, j as high as n, and of course O(n-0) = O(n) (it's not too hard to show that checkRepitions is O(n) in the average case as well).
As mentioned by a commenter, having a linear operation inside the body of your second for loop has the same practical effect in terms of complexity as having a third for loop, which would probably be easier to see as being O(n^3) (you could even imagine the function definition for checkRepitition, including its for loop, being pasted into lengthOfLongestSubstring in place to see the same result). But the basic idea is that doing O(n) work for each of the O(n^2) iterations of the 2 for loops means the total complexity is O(n)*O(n^2) = O(n^3).
Suppose you have a method subArrayLeftShift(a,i) which shifts left the sub array a[i,...,n-1] when n is the array length. That means that the elements a[i+1],...,a[n-1] are moving one place to the left, and the original a[i] will become the last one.
More formally, here is the function implementation:
public static void subArrayLeftShift(int[] a, int i){
if (a.length == 0) return;
int last = a.length - 1;
int insertToLast = a[i];
for (; i < last; i++){
a[i] = a[i + 1];
}
a[last] = insertToLast;
}
Now for the question: implement a function that receives an unsorted array, and returns the minimal number of calls to subArrayLeftShift for sorting the array.
In the interview I couldnt find the way to do it. I succeed to find the minimal number of calls for every example I wrote for intuition, but couldn't find a way for generalizing it.
Do you know how to solve it?
I propose the following algorithm to solve the problem:
Find the minimum number in the array that is not sorted ( has a smaller number on the right in the array). Let this number be x.
Count how many numbers in the array are greater than the previously found number x. Let this number be y.
Since for each call to the function, the unsorted number will end up at the last position, the optimum strategy is to call the function for each unsorted number in increasing order. Using what was found previously we start with x. We continue with the next unsorted number bigger than x, because in this way, it will end up on the right of x, hence it will be sorted. Continue in the same fashion. How much? How many bigger number than x we have? Well, that's y. So as a total, the number of calls to the function is 1 + y.
public static int minimumCalls(int[] a) {
int minCalls = 0;
for (int i = 0; i < a.length - 1; i++) {
for (int j = i+1; j < a.length; j++) {
if (a[i] > a[j]) {
minCalls++;
break;
}
}
}
return minCalls;
}
The idea behind my thinking is that you must invoke the method once whenever there exists in the SubArray any value less than the current i. The name of the method subArrayShiftLeft, i feel, is designed to throw you off and drag your attention away from thinking of this easily.
If there's any values less than the current one further on in the array, just invoke the method.
It's much easier to think of this as moving a single larger value to the end of the array than trying to shift the smaller ones to the left.
I have been solving exercise from Introduction to Algorithms - CLRS and came across solving maximum contiguous sub-array in linear time (Q 4.1-5).
Please look at my solution below. I have been searching for online judges for this exercise but found none. After solving it when I looked for solutions I found kadane's algorithm which seems different than my implementation also this solution gives the correct output when all numbers are negative.
public static int linearMaxSolve(int[] arr) {
int max = Integer.MIN_VALUE;
int sum = 0;
for (int i : arr) {
sum += i;
if (i > sum) {
sum = i;
}
if (sum > max) {
max = sum;
}
}
return max;
}
Is there a way to check the validity of this algorithm apart from feeding in manual test cases to the program?
This really depends on what is your definition for an array with all negative values.
In case you don't count the empty sub-array as a possible solution then yes, your solution is correct and actually it's exactly the same as the Kadane's algorithm.
int max_so_far = a[0];
int max_ending_here = a[0];
for (int i = 1; i < size; i++)
{
max_ending_here = Math.max(a[i], max_ending_here+a[i]);
max_so_far = Math.max(max_so_far, max_ending_here);
}
return max_so_far;
The only difference is the initialization, but if you'll take a closer look, at the first iteration of your algorithm, both sum and max will have the value of a[0].
But again, you assume here that both your array isn't empty (in that case you'll return Integer.MIN_VALUE, is that what you want?) and that an empty sub-array (sum==0) is not a possible solution.
For example, if you were given {1,2} as the small array and {1,2,3,4,1,2,1,3} as the big one, then it would return 2.
This is probably horribly incorrect:
public static int timesOccur(int[] small, int big[]) {
int sum= 0;
for (int i=0; i<small.length; i++){
int currentSum = 0;
for (int j=0; j<big.length; j++){
if (small[i] == big[j]){
currentSum ++;
}
sum= currentSum ;
}
}
return sum;
}
As #AndyTurner mentioned, your task can be reduced to the set of well-known string matching algorithms.
As I can understand you want solution faster than O(n * m).
There are two main approaches. First involves preprocessing text (long array), second involves preprocessing search pattern (small array).
Preprocessing text. By this I mean creating suffix array or LCP from your longer array. Having this data structure constructed you can perform a binary search to find your your substring. The most efficient time you can achieve is O(n) to build LCP and O(m + log n) to perform the search. So overall time is O(n + m).
Preprocessing pattern. This means construction DFA from the pattern. Having DFA constructed it takes one traversal of the string (long array) to find all occurrences of substring (linear time). The hardest part here is to construct the DFA. Knuth-Morris-Pratt does this in O(m) time, so overall algorithm running time will be O(m + n). Actually KMP algorithm is most probably the best available solution for this task in terms of efficiency and implementation complexity. Check #JuanLopes's answer for concrete implementation.
Also you can consider optimized bruteforce, for example Boyer-Moore, it is good for practical cases, but it has O(n * m) running time in worst case.
UPD:
In case you don't need fast approaches, I corrected your code from description:
public static int timesOccur(int[] small, int big[]) {
int sum = 0;
for (int i = 0; i < big.length - small.length + 1; i++) {
int j = 0;
while (j < small.length && small[j] == big[i + j]) {
j++;
}
if (j == small.length) {
sum++;
}
}
return sum;
}
Pay attention on the inner while loop. It stops as soon as elements don't match. It's important optimization, as it makes running time almost linear for best cases.
upd2: inner loop explanation.
The purpose of inner loop is to find out if smaller array matches bigger array starting from position i. To perform that check index j is iterated from 0 to length of smaller array, comparing the element j of the smaller array with the corresponding element i + j of the bigger array. Loop proceeds when both conditions are true at the same time: j < small.length and corresponding elements of two arrays match.
So loop stops in two situations:
j < small.length is false. This means that j==small.length. Also it means that for all j=0..small.length-1 elements of the two arrays matched (otherwise loop would break earlier, see (2) below).
small[j] == big[i + j] is false. This means that match was not found. In this case loop will break before j reaches small.length
After the loop it's sufficient to check whether j==small.length to know which condition made loop to stop and hence know whether match was found or not for current position i.
This is a simple subarray matching problem. In Java you can use Collections.indexOfSublist, but you would have to box all the integers in your array. An option is to implement your own array matching algorithm. There are several options, most string searching algorithms can be adapted to this task.
Here is an optimized version based on the KMP algorithm. In the worst case it will be O(n + m), which is better than the trivial algorithm. But it has the downside of requiring extra space to compute the failure function (F).
public class Main {
public static class KMP {
private final int F[];
private final int[] needle;
public KMP(int[] needle) {
this.needle = needle;
this.F = new int[needle.length + 1];
F[0] = 0;
F[1] = 0;
int i = 1, j = 0;
while (i < needle.length) {
if (needle[i] == needle[j])
F[++i] = ++j;
else if (j == 0)
F[++i] = 0;
else
j = F[j];
}
}
public int countAt(int[] haystack) {
int count = 0;
int i = 0, j = 0;
int n = haystack.length, m = needle.length;
while (i - j <= n - m) {
while (j < m) {
if (needle[j] == haystack[i]) {
i++;
j++;
} else break;
}
if (j == m) count++;
else if (j == 0) i++;
j = F[j];
}
return count;
}
}
public static void main(String[] args) {
System.out.println(new KMP(new int[]{1, 2}).countAt(new int[]{1, 2, 3, 4, 1, 2, 1, 3}));
System.out.println(new KMP(new int[]{1, 1}).countAt(new int[]{1, 1, 1}));
}
}
Rather than posting a solution I'll provide some hints to get your moving.
It's worth breaking the problem down into smaller pieces, in general your algorithm should look like:
for each position in the big array
check if the small array matches that position
if it does, increment your counter
The smaller piece is then checking if the small array matches a given position
first check if there's enough room to fit the smaller array
if not then the arrays don't match
otherwise for each position in the smaller array
check if the values in the arrays match
if not then the arrays don't match
if you get to the end of the smaller array and they have all matched
then the arrays match
Though not thoroughly tested I believe this is a solution to your problem. I would highly recommend using Sprinters pseudocode to try and figure this out yourself before using this.
public static void main(String[] args)
{
int[] smallArray = {1,1};
int[] bigArray = {1,1,1};
int sum = 0;
for(int i = 0; i < bigArray.length; i++)
{
boolean flag = true;
if(bigArray[i] == smallArray[0])
{
for(int x = 0; x < smallArray.length; x++)
{
if(i + x >= bigArray.length)
flag = false;
else if(bigArray[i + x] != smallArray[x])
flag = false;
}
if(flag)
sum += 1;
}
}
System.out.println(sum);
}
}
I'm trying to write code that will work out prime numbers using the sieve of Eratosthenes. I have to include a function that will take in a number and cross of all of the multiples of that number. For testing I set the first number to be 2 and the second as 3. It works for the first number but never for the second(no matter the order of the numbers i.e if I put 3 into the function first). I know there are other completed sieve of Eratosthenes out there but I wanted to try and do it in the way that I thought of first.
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
System.out.println("Which number would you like to calculate up to?");
int n = input.nextInt();
input.close();
int x = 0;
int newNumber = 2;
int numbers[] = new int[n];
while(newNumber <= n){
numbers[x] = newNumber;
x++;
newNumber++;
}
int currentNumber = 2;
int finalNumber[] = markOfMultiples(n, numbers, currentNumber);
for(int y = 0;y < n-1;y++){
System.out.print(finalNumber[y] + ", ");
}
currentNumber = 3;
int secondNumber[] = markOfMultiples(n, numbers, currentNumber);
for(int y = 0;y < n-1;y++){
System.out.println(secondNumber[y]);
}
}
public static int[] markOfMultiples(int n, int numbers[], int currentNumber){
int originalNumber = currentNumber;
while(currentNumber<n){
currentNumber = currentNumber + originalNumber;
int count2 = 0;
while(currentNumber != numbers[count2] && currentNumber<=n && count2<n){
count2++;
}
numbers[count2] = 0;
}
return numbers;
}
The error I'm getting is: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 20
at sieveOfEratosthenes.sieveOfEratosthenes.markOfMultiples(sieveOfEratosthenes.java:46)
at sieveOfEratosthenes.sieveOfEratosthenes.main(sieveOfEratosthenes.java:28)
Line 28 is when I recall the function:int secondNumber[] = markOfMultiples(n, numbers, currentNumber);
And line 46 is while(currentNumber != numbers[count2] && currentNumber<=n && count2<20){
Any help would be much appreciated. How do I keep on calling the function?
p.s. Please excuse the variable names as I'll be changing them when I get the program working.
If you want to get this approach working, you can do the fix advised by #Thierry to check count2 < n first in your while loop and then also surround the line
numbers[count2] = 0
with an if clause to check count2 is not beyond the end of the index. e.g.
if (count2 < n) {
numbers[count2] = 0;
}
Your final challenge is how you call your markOfMultiples() function enough times when n gets a bit larger. It's not a problem with your fundamental approach - you can definitely do it and your approach will work well and have acceptable performance for low-ish numbers (say up to 10000).
However
I realise this is an assignment and you want to do it your way, but there are a few features of your approach which you might want to consider - maybe after you've got it working.
Readability - is it going to be easy for someone looking at (marking) your code to understand what it's doing and verify that it will do the right thing for all values of n?
Try not to repeat yourself - for instance consider where you fill your numbers array:
while(newNumber <= n){
numbers[x] = newNumber;
x++;
newNumber++;
}
Will x ever be different to newNumber? Did you need both variables? This sort or repetition occurs elsewhere in your code - the principle to stick to is known as DRY (Don't Repeat Yourself)
Is there an easier way to move the index on originalNumber places in your markOfMultiples() method? (HINT: yes, there is)
Do you really need the actual numbers in the numbers[] array? You're going to end up with a lot of zeros and the primes left as integer values if you work out how to call your markOfMultiples repeatedly for high values of n. Would an array of 1s and 0s (or trues and falses) be enough if you used the array index to give you the prime number?
You need to test if count2 < n BEFORE access to numbers[count2]:
while(count2 < n && currentNumber != numbers[count2] && currentNumber<= n){
count2++;
}