6

The method hasTwoTrueValues return true if at least two values in an array of boolean are true. Provide the Big-O running time for all three implementations proposed.

// Version 1

public boolean hasTwoTrueValues(boolean[] arr) {
    int count = 0;
    for(int i = 0; i < arr.length; i++)
        if(arr[i])
            count++;
        return count >= 2;
}

// Version 2

public boolean hasTwoTrueValues(boolean[] arr) {
    for(int i = 0; i < arr.length; i++)
        for(int j = i + 1; j < arr.length; j++ )
            if(arr[i] && arr[j])
                return true;
}

// Version 3

public boolean hasTwoTrueValues(boolean[] arr) {
    for(int i = 0; i < arr.length; i++)
        if(arr[i])
            for(int j = i + 1; j < arr.length; j++)
                if(arr[j])
                    return true;
                        return false;
}

These are my answers:

  • Version 1 is O(n)
  • Version 2 is O(n^2)
  • Version 3 is O(n^2)

I am really new to this Big-O Notation so I need guidance if my answers are correct/incorrect. If I'm wrong, could you please explain and help me to learn?

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • Yup, I don't find anything wrong with your analysis. – Sidharth Mudgal Oct 01 '12 at 03:52
  • Yes ! These answers match. If you want more info then refer some Big-Oh Practice problems. – djadmin Oct 01 '12 at 03:54
  • Some people misunderstand the function of this site, and others misuse their power to vote to close. That isn't a reason to start the same question repeatedly, nor should you intentionally deface them simply out of frustration. I think this was a reasonable question, and I provided what I (hope) was a thorough answer. I'm more than willing to provide additional assistance/clarification, and if you have further questions you can [edit](http://stackoverflow.com/posts/12667234/edit) *this* post, rather than asking the same question again (hint: it will probably just get closed again). – nbrooks Oct 01 '12 at 06:12
  • Once the community feels this question is up to standard, it may be reopened. (I personally think it should be, though you reword it to not be such a yes/no wuestion) – nbrooks Oct 01 '12 at 06:13
  • I would have voted to close this as "too localized"; i.e. not likely to be of any use to anyone but the OP. Anyway, he has his answer so I don't wee the point of reopening it. @nbrooks - unfortunately, you spent a lot of time explaining something that probably didn't need to be explained at all. The OP only asked for an explanation *if he was wrong*. – Stephen C Oct 01 '12 at 07:15
  • 1
    @stephen I agree it wouldn't have been useful to anybody else...if I only explained *if he was wrong*. By providing a general analysis I hoped to make it more useful. In any case, he *was* wrong, since he wrote that **version 3** was `O(n^2)`, and I sought to distinguish it from the other cases by explaining *why* he was wrong. – nbrooks Oct 01 '12 at 07:31

2 Answers2

4

Version 1 is pretty straightforward and runs linear, so the runtime of that is O(n) on average.

Version 2 is a bit more interesting. It runs with n(n-1) on average, which is O(n2). There's an early return in this loop, so it's definitely possible that it could break as early as the first two elements.

Version 3 is trickier. You have to be careful on this. The second loop will only run if arr[i] is true. The runtime of it has to be put into distinct categories then.

  • If all elements of the array are false, then your runtime will be O(n).
  • If half of the elements of the array are true, then you will be running the second loop on a condition of (n(n-1))/2, which is O(n2).
  • If all of the elements of the array are true, then you will be running in O(n2). You will also immediately exit after the first two elements, but you're still using two loops to perform the action.

It's safe to say then that the average and worst runtime for Version 3 will be O(n2). Its best would be O(n), which is definitely possible.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • 1
    +1: These are the kind of answers that help people to learn (even people that enter for curiosity). – Luiggi Mendoza Oct 01 '12 at 03:58
  • The analysis of version #3 is incorrect. It is actually `O(N)` in the worst case, and `O(1)` in the best case. See nbrook's answer. – Stephen C Oct 01 '12 at 14:59
0

In short, the worst-case run-times are: Version 1: O(n)
Version 2: O(n^2)
Version 3: O(n)


A more detailed analysis...

For this algorithm you will have to consider best-case, worst-case and average-case runtimes to get a meaningful comparison.

For each of them, the following should exemplify these:

bestCase = [ true, true, ...] // the first two are true
worstCase = [ false, false, ..., false] // all are false
averageCase = [ true, ..., true, ..., false // second true value is found about half-way

For all of your algorithms, the best-case run-time is O(2), meaning constant-time.

In the worst-case, your first algorithm is O(n), meaning linear run-time. However, in the worst-case your second algorithm will degenerate very specifically, since at each step you have one fewer element to check against. You end up with the summation n + (n-1) + (n-2) + ..., which will evaluate to n(n-1)/2 which, as you rightly said, is in O(n^2), and grows quadratically.

In the 'worst-case' where all are false (as we will see, this isn't in fact the worst-case for version 3), your third algorithm actually runs in linear time, since the if statement prevents the second loop from running.

As it turns out, version 3 will never run in quadratic time: it would be linear in the average and worst case, since it scans linearly for the first true, then scans the rest linearly for the second true only after finding that, although it doesn't even work! Because you have two returns in your inner for-loop, once the first true value has been encountered, it will return true if the next immediate neighbor is true. However, if the next immediate neighbor is false, it immediately returns false and doesn't check any of the other values. This means that on the input:

[ true, false, true ]

version 3 would return false as soon as it saw the second false value. (Technically I am assuming here that you want this return false to be executed inside of the for loop, in which case you also need to add { }, and likewise with your first version. While not always necessary, it helps clarify what exactly is happening, especially since this doesn't match your indentation currently. When absent only the statement immediately following is included on the loop/if body.) I suspect that, even if implemented correctly, *version 3 will still have a worse-case run time which is linear, on the input:

[true, false, false, ..., false]

The first true would cause it to scan n times in the inner loop, but then the outer loop would just continue running up to n without running the inner loop again, giving you a total of 2n-1 operations, which of course is in O(n).

If your { } are correct and it is simply your indentation which is wrong, then these analyses may need to be modified slightly, but this is the kind of thinking which you need to apply to big-O problems (and asymptotic analysis in general).

nbrooks
  • 18,126
  • 5
  • 54
  • 66