Friday, 6 May 2011

spiral matrix

Note: Code snippet loading may take few seconds.
Generate a square matrix of size n, such that
  1. it has elements from 1 to n*2 (or 0 to n*2-1)
  2. lowest element is at [n,n] (or [n-1,n-1])
  3. elements are arranged in a spiral order as shown in Figure.
For instance, when n=2 and n=3
M2 =           M3=
| 3 4 |           | 5   6   7 |
| 2 1 |           | 4   9   8 |
                     | 3   2   1 |

This is really simple when we consider pattern of filling these elements at an abstract level. Our general approach is to find position for element in order {1, 2, 3, ..., n*n}

We start with rightmost bottom position and put first element there. Then we decide direction to proceed in, which is horizontal in this case. For every next element, we seek a position for it in following way-
We consider adjacent positions of current position in the direction we are in, i.e. here we consider [n,n-1] and [n,n+1] (with [n,n] as our rightmost bottom position. We see if any of this is free. We generalize any position outside matrix dimensions to be non-free and thus next position we have is [n,n-1]. We fill next element in this position and keep going.
At some point, we will find no position free for next element in the direction we are in, which is signal for us to change direction. We switch to vertical direction now and keep going with same logic. This w
ay, we keep moving ahead, find a free slot and change direction if we don't find one.
Note that when we fill in last element, we no longer find free position in either direction and we are done.

Following is the C code.

// generates a spiral square matrix of n*n
// @author Girija

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    int i, j, num;
    int pi, pj;
    bool pfound;

    // setup
    int n = atoi(argv[1]);
    bool horizontal = true;
    int max_num = num*num; // starts at 1

    // allocate
    int **matrix = (int **) malloc(sizeof(int) * n * n);

    // initialize
    for(i=0; i<n; i++) {
     matrix[i] = (int *) malloc(sizeof(int) * n);
      for(j=0; j<n; j++) {
        matrix[i][j] = -1;
      }
    }

    pi = pj = n-1;

    // generate spiral matrix
    num = 1;
    while(1) {
      // place current number at pi,pj
      matrix[pi][pj] = num;
      // get position to place next number
      pfound = false;
      if(horizontal) {
        // we are following horizontal direction, check left-right empty slots first
        // check if empty slot, reset pj
        if(pj-1 >=0 && matrix[pi][pj-1] == -1) {
            pj--;
            pfound = true;
        }
        else if(pj+1 <= n-1 && matrix[pi][pj+1] == -1) {
            pj++;
            pfound = true;
        }
        if(!pfound) {
            // time to change direction
            horizontal = false;
            // reset pi
            if(pi-1 >= 0 && matrix[pi-1][pj] == -1) {
              pi--;
              pfound = true;
            }
            else if(pi+1 <= n-1 && matrix[pi+1][pj] == -1) {
              pi++;
              pfound = true;
            }
        }
      } else {
        // we are following vertical direction, check up-down empty slots first
        // check if empty slot, reset pi
        if(pi-1 >=0 && matrix[pi-1][pj] == -1) {
            pi--;
            pfound = true;
        }
        else if(pi+1 <= n-1 && matrix[pi+1][pj] == -1) {
            pi++;
            pfound = true;
        }
        if(!pfound) {
            // time to change direction
            horizontal = true;
            // reset pj
            if(pj-1 >= 0 && matrix[pi][pj-1] == -1) {
              pj--;
              pfound = true;
            }
            else if(pj+1 <= n-1 && matrix[pi][pj+1] == -1) {
              pj++;
              pfound = true;
            }
        }
      }
      // not found? we are done!
      if(!pfound)
        break;
      num++;
    }

    for(i=0; i<n; i++) {
      printf("n");
      for(j=0; j<n; j++) {
        printf("%dt", matrix[i][j]);
      }
    }
    printf("n");
}

Tuesday, 3 May 2011

top k from n (k << n)

Bhai was asked this problem in one of the interviews he faced.

Given n objects and associated scores, find top k objects s.t. k is much smaller compared to n.

The most trivial approach is of course to sort n objects based on their scores and pick top k. The best known comparison based sort will do this in O(n log n) with additional pass to pick top k. And of course, this is not what is expected! We need complexity to be lower than O(n log n).

Let's focus on last part of the problem statement. What additional benefit does it give us to know that k << n? One obvious thing that comes to mind is, we are interested in correct ordering of just top k objects, remaining n-k could be unordered at the benefit of having lower complexity. Thinking in the same direction, one can try to pick k such objects such that remaining n-k are virtually ignored! But, there has to be some mechanism to pick top k. The same thing considered in opposite way will give us better insights - i.e. we get lower complexity at the expense of neglecting ordering of non-top n-k objects; meaning we don't care about them, specifically their position in ordered list.

So, is there any way where we can selectively pick elements s.t. the highest score is picked first then the second highest scored and so on? well.. this suggests none other than a max-heap! a max-heap allows you to get maximum element one at a time with delete operation. Let's see the algorithm.

  1. Build heap of n objects given.
  2. for i=1 to k do
    1. get max element (delete from heap)
Let's see the complexity if we are doing any better than O(n log n). Step 1 above takes O(n). Refer Complexity of building heap for analysis. Step 2.1 takes O(log n) and thus step 2 takes O(k log n). In first read, one might think the complexity is O(n) + O(k log n). Let's analyze more with examples.
  • n = 1024, k = 10
    • n+k log n ~ 1024 + 10 * 10 ~ 1024 -> O(n)
  • n = 1024, k = 200
    • n+k log n ~ 1024 + 200 * 10 ~ 2000 -> O(k log n) which will approach O(n log n) as k -> n
Of course, if k -> n, this algorithm will degenerate to O(n log n)  but in given setting where k << n, case 1 above will result in linear time algorithm.
:)

Wednesday, 5 May 2010

Majority element of an array

Given an array of n number, find the majority element (if any)?

(Majority element is the one which occurs more than n/2 number of times)

Example: A = [20, 4, 4, 7, 4, 16, 20, 4, 0, 4, 4], n = 11, '4' occurs 6 times, is the majority elemet.

How to go about it? Simplest method follows. Keep another array of counts and keep track of which number occurs how many times. But, this is possible only when we know the range of numbers. Even though we know that, it is inefficient in space. So, let's rule out that method. What we have to thus look for, is a way to keep counts / track of a possible majority element run time. How to do this?

What if we consider the smaller part of above given A? We start with count=0. At index_0, we assume 20 is the majority element, thus setting count to 1 and also keep track that '20' is our probable majority number so far. At index_1, we find that the number is not 20 and thus we have lost on score, thus decrementing the count, so not it is 0 again. Here, we are kind of sure that from the elements we have seen so far, each appeared with equal counts and thus, we should look for a new start. So, when count hits 0, we change our probable majority element to the current one and again repeat the process.

With above example, count and probable majority element (pme) go as follows.
A        = [20, 4, 4, 7, 4, 16, 20, 4, 0, 4, 4]
count = [  1, 0, 1, 0,  0,  0,   0, 0, 0, 0, 1]
pme   = [20, 4, 4, 7, 4, 16, 20, 4, 0, 4, 4]

Thus, in O(n) we can find the majority element.

Wednesday, 28 April 2010

Prime number pairs summing to an odd number

While reading a book (details below), I came across a very nice problem as follows.

Find all pairs of prime numbers that sum up to 999.

As the book says, it involves thinking before actually attacking the problem. Few observations:
  • Sum given is odd (999).
  • To get sum odd, exactly one of the two numbers have to be even.
  • Asked are the pairs of prime numbers.
  • Meaning, we want intersection of prime and even which is just the number 2.
So, one of the numbers has to be 2; and thus the other of course is 997. And, that's the only pair of prime numbers which sums up to  999.

Cool indeed! :)

Book details:
Title:  math Charmers - Tantalizing Tidbits for the mind
Author: alfred s. posamentier
Publisher: University Press

Tuesday, 8 December 2009

n-th last element in the list

Given a singly linked list, find n-th element from the last.

The most obvious way is to traverse the list once and get its length say L. Then traverse again first L-n nodes to get to the n-th last node. This is linear in complexity but we need to traverse the list twice. Can we eliminate this?

We can, using extra pointer. Let's have a pointer to the list say *first and one more say *second. We traverse the list using *first till n nodes are traversed. Now imagine that at this moment we start traversing the list with second pointer, say *second. Then, by the time *first reaches towards the end of the list, *second will fall short by n nodes from the end of the list. That's precisely the node we want - n-th node from the end. So the solution is clear. After *first reaches the n-th node, start traversing with *second and continuing with *first till *first reached the last node.

Note: This will take care of the error in input when n > length of the list as *first will reach NULL sooner than expected.

Monday, 7 December 2009

Must Read

This post will be kept updated with links as and when I find them. While browsing, if you come across any of the dangling / dead links or redirections, please let me know.

- A collection of dynamic programming
problems
very well explained.

for loop in C

Following code has a bug. Can you find that out? Hint: Well, this code is intended to print "hi " **20** times, does it?
   int i, n=20;
   for (i=0; i < n; i--) {        printf("hi ");    }


If you have found the bug, can you now make it print "hi " 20 times by replacing one character.

Well, the answer is too simple (once known :D). Just a hint: Make sure you understand how for loop works, specially at the beginning of the loop.

(Spoiler alert: Solution in comment)