1

Right, this is from an older exam which i'm using to prepare my own exam in january. We are given the following method:

public static void Oorspronkelijk()
{
    String bs = "Dit is een boodschap aan de wereld";
    int max = -1;
    char let = '*';
    for (int i=0;i<bs.length();i++) {
        int tel = 1;
        for (int j=i+1;j<bs.length();j++) {
            if (bs.charAt(j) == bs.charAt(i)) tel++;
        }

        if (tel > max) {
            max = tel;
            let = bs.charAt(i);
        }
    }

    System.out.println(max + " keer " + let);
}

The questions are:

  1. what is the output? - Since the code is just an algorithm to determine the most occuring character, the output is "6 keer " (6 times space)
  2. What is the time complexity of this code? Fairly sure it's O(n²), unless someone thinks otherwise?
  3. Can you reduce the time complexity, and if so, how?

Well, you can. I've received some help already and managed to get the following code:

public static void Nieuw()
{
    String bs = "Dit is een boodschap aan de wereld";
    HashMap<Character, Integer> letters = new HashMap<Character, Integer>();
    char max = bs.charAt(0);
    for (int i=0;i<bs.length();i++) {
        char let = bs.charAt(i);
        if(!letters.containsKey(let)) {
            letters.put(let,0);
        }

        int tel = letters.get(let)+1;
        letters.put(let,tel);

        if(letters.get(max)<tel) {
            max = let;
        }
    }

    System.out.println(letters.get(max) + " keer " + max);
}

However, I'm uncertain of the time complexity of this new code: Is it O(n) because you only use one for-loop, or does the fact we require the use of the HashMap's get methods make it O(n log n) ?

And if someone knows an even better way of reducing the time complexity, please do tell! :)

moinudin
  • 134,091
  • 45
  • 190
  • 216
Koeneuze
  • 477
  • 2
  • 7
  • 9
  • I'm not good in determining complexity and wounder - why O(n^2)? The problem spot for me is: In the 2nd loop u iterate not N times, but (N - M, and M increasing by 1 on each iteration). – Vanger Dec 29 '10 at 09:12
  • @Vanger that means the second loop will be performed (1+2+3+...+N) times which is [(N+1)*N]/2 = (N^2+N)/2 = O(N^2) – yurib Dec 29 '10 at 09:16
  • @yurib Thx :) totally forgot series. – Vanger Dec 29 '10 at 09:19

5 Answers5

2

The time complexity of the new code is O(n) - this is because the hashmap lookup is a constant time operation and constant time operation do not affect the order.

One suggestion I could make, just an optimisation though (won't make a huge difference) - not a major change and won't affect the order - is that you could use an array of ints rather than a hash map to track counts of each character. Just use the int value equivalent of the char as the index of the array.

Michael Wiles
  • 20,902
  • 18
  • 71
  • 101
0

a hash function get operation is O(1), so your solution's time complexity is O(n). you can't do better than that since any solution would require you to read the entire input at least once.

yurib
  • 8,043
  • 3
  • 30
  • 55
0

I think it is O(n) . because searching in HashMap is just O(1)

for (int i=0;i<bs.length();i++) { // O(n)
    char let = bs.charAt(i); // O(1)
    if(!letters.containsKey(let)) { // O(1)
        letters.put(let,0);
    }

the overall complexity is O(n)

0

To ensure, the HashMap will always have the time complexity of O(1), you may have to enter proper initialCapacity. You need to know the complete domain values that the bs String is going to have.

Assuming, 1. Both Upper and Lower cases will be treated seperately. 2. The string will only have alphabets and a space charecter

The inital Load capacity should be greater than, 26(lower case) + 26 (Upper case) + 1(Space) = 53

53 + 25%(53) = 53 + 13.25 + 2.75(buffer) = 69.

So the hashmap initiation could be like the below,

HashMap<Character, Integer> letters = new HashMap<Character, Integer>(69);

Ravi
  • 301
  • 1
  • 2
  • 8
  • This isn't going to have much of an impact here, since 69 is such a small number. But for larger numbers you're totally correct. – moinudin Dec 29 '10 at 09:56
  • the hashmap will have a default capacity of 16, if you do not initialize anything. And the time complexity will go from O(1) to O(5) - since 69/16 = 4.3... – Ravi Dec 29 '10 at 10:01
  • 1
    O(5) = O(1), but even that is incorrect as the 5 is not a factor of the complexity but a constant overhead. So it doesn't affect the big-O complexity. – moinudin Dec 29 '10 at 10:52
0

Hashmap is O(1), but here you can also use an array, since the number of letters is fairly small (only 256) you can also use an Array. This is also O(1), but is faster, uses less memory, and it's simpler:

String bs = "Dit is een boodschap aan de wereld";
int letters[] = new int[256];
char max = 0;
for (int i=0;i<bs.length();i++) {
    char let = bs.charAt(i);
    ++letters[let];

    if(letters[max] < letters[let]) {
        max = let;
    }
}

System.out.println(letters[max] + " keer " + max);
martinus
  • 17,736
  • 15
  • 72
  • 92