Wednesday 26 December 2018

N-Queens and Map Coloring (Coursera Discrete Optimization Course)


  • Place 8 Queens on a 8*8 board such that none of them attack each other.
  • Backtrack: Use constraints to reduce search space.
  • Map Coloring: Every 2D map can be colored with 4 colors (upper bound: dimension+1)
  • Domain Store is the search space and independent constraints interact with it and if they are feasible, keep reducing the domain store.
  • Propagation Engine: Iterative algorithm, bring constraints one by one and if feasible remove values from domain store one by one.
  • Decision Variable: A model to associate a part of problem in the form of variable that we can check one by one and solve problem. The constraints will be on this decision variable.

N-Queen Problem ( Call by nqueen(1) )
 public void nqueen(int r,int n,int x[]){
     if(r==n+1) print("Found"+x);
     else{
      boolean legal;
      for(int j=1;j<=n;j++){
       legal=true;
       for(int i=1;i<=r-1;i++)
        if(x[i-1]==j||x[i-1]==j+r-i||x[i-1]==j-r+i) legal=false;
       if(legal){
        x[r-1]=j;
        nqueen(r+1,n,x);
       }
      }
     }
    }

Counting set bits in binary representation of a positive integer for beginners (Brian Kernighan's algorithm )

 I will call it a post for beginners , prerequisites might be basic understanding of binary number system, how to convert fromm decimal to binary form for positive integers and basic binary operations

problem at hand:
Given a positive integer  N in base 10, we want to find how many 1's ( set bits ) are there in the binary representation of N


 First thought might be , we know how to convert a decimal to binary and in that process we can keep a note of how many 1's we have seen and that is our answer.

example
say we can convert 4 to (100)2 or 7 to (111)2 , so we directly get the number of 1's in the process and our problem is solved

but this post is aimed at introducing you to interesting uses of binary operations and one such use is solving our problem at hand and we have an algorithm for that called Brian Kernighan's algorithm 

 now lets see the binary representation of 256 its (100000000)2
 as we see their is only one set bit , so can we do something which might help us solve at least this case with only one set bit without manually looking at each bit ?

CLAIM: any binary representation containing only one set bit is a power of 2
// try to convert some powers of 2 to binary representation and try to see why this claim is true


so now i will present what actually lies at the heart of  Brian Kernighan's algorithm
its this binary operation

n & (n-1)

whole magic trick we are trying to pull here lies in this expression , so lets see what it does

for the sake of not escalating too quickly we will first look at the case of numbers with only one bit set (or as i said powers of 2)

I claim that our binary operation ( n & (n-1)) will give 0 for every power of 2


nn in base 2n-1 in base 2n & (n-1)
1100
21010
4100110
810001110
161000011110

it can be proved by using the fact that power of 2 have only one bit set but n-1 have all bits set but the bit which was set in n is not set in n-1 so when we take n & (n-1) which is bitwise, no set bit corresponds to set bit and so the result is zero
re- read the above statement and let it sink in

so now we have established that for n being power of 2   n & (n-1)  shall result in zero

let me restate that
performing n & (n-1)  unset the set bit from n
trivial to say that as there was only 1 bit which was set .. so yes that was unset

now we move to general case lets see what n&(n-1) does to any random value
 I will randomly generate a table   

nn in base 2n-1 in base 2n & (n-1) in base 2
56111000110111110000
60111100111011111000
44101100101011101000
68100010010000111000000
60111100111011111000

now we have something interesting to observe
observe  what is the difference between n and (n-1) in base 2 representation
first set bit from right (least significant bit which is set) is unset

Lets see how we can have some proof for this
Its actually not very hard to see
observe that first set bit from right and all zeroes on its right taken together will behave like a power of 2 as there is only one bit set and n-1 affects only those bits  and higher bits will remain same
now  x & x = x so higher bits remain unchanged even after (n & (n-1))

so we can claim that in general case n & (n-1)  unsets the least significant bit which was set
and if keep repeating this operation then eventually all set bits will be unset one by one
( note that repeating means value of  n&(n-1 ) becomes the new value of  n for next iteration)
and we will reach zero
as in one operation we remove one set bit
number of iterations will directly give us number of set bit

following is a simple javascript implementation:


 function count_set_bits( n ){  
  var count =0;  
  while(n>0){  
   n = (n & (n-1));  
   count++;
  }  
  return count;  
 }  

 alert(count_set_bits(7)); //alerts 3

Thursday 20 August 2015

Inversions in an array

Inversions : Number of pairs (i,j) such that i < j and arr[i] > arr[j] .

Now lets see how to find number of such pairs.

The Brute Way O(N^2)

We will traverse array for each pair i,j and check if arr[i]>arr[j] .

int count = 0;
for(int i=0;i<N;i++)
for(int j=i+1;j<N;j++)
if(arr[j]<arr[i])  count++;

The count will store our answer.

A Smart Way O(N logN)

We can use modified merge sort to find number of inversions in an array.

As we know in merge sort we keep on dividing the array then we sort those parts and then merge those sorted parts, we can modify the algorithm by adding just a variable that will keep on adding count of inversions.

Now we know when we are merging two parts number of inversions are sum of inversions in both those parts and the number of inversions in the merge operation.

Now the main trick and heart of algorithm lies in the merge part and lets see how to calculate that :
As we can see both these parts are sorted, so for a specific j if arr[j] < arr[i] all elements between mid and i will be greater than j, since both arrays are sorted, so we need to add (mid-i) to the count of inversions.
Here is a sample code for better understanding :

public  int merge_sort(int left, int right) {

int count = 0;
if (right > left) {
int mid = (right + left) / 2;
count = merge_sort(left, mid);
count += merge_sort(mid + 1, right);
count += merge(left, mid + 1, right);
}
return count;
}

public  int merge(int left, int mid, int right) {
int count=0;
int i=left,j=mid,k=left;
while((i<mid)&&(j<=right))
{
if(arr[i]<=arr[j]) temp[k++]=arr[i++];
else {
temp[k++]=arr[j++];
count+=(mid-i);
}
}
while(i<mid) temp[k++]=arr[i++];
while(j<=right) temp[k++]=arr[j++];
for(i=left;i<=right;i++) arr[i]=temp[i];
return count;
}

Another Smart Way : BIT O(N log N)

This problem can also be solved using a BIT (Binary Indexed Tree). Lets see how to do that.
Basically using a BIT we can find cumulative sum till an index i in logn time.We will use this property to count the number of inversions.

Here is a simple implementation of BIT :

  class BIT
{
int tree[];
public BIT(int n)
{
tree=new int[n+1];      //only for this case else construct properly.
}
public int sum(int i)
{
int sum=0;
while(i>0)
{
sum+=tree[i];
i -= (i & -i);
}
return sum;
}
public void update(int i,int x)
{
while(i<tree.length)
{
tree[i]+=x;
i += (i & -i);
}
}
 }

Now basically we will see count of all i such that arr[i]<arr[j] which we can get from BIT easilly, we need the opposite so we can keep on adding i-sum(i) to our count which will give us the number of inversions.

Here is the sample code to do that :

  BIT bit=new BIT(arr.length);
int tempo[]=arr.clone();
Arrays.sort(tempo);
int res=0;
for(int i=0;i<arr.length;i++)
{
int ind=Arrays.binarySearch(tempo, arr[i])+1;
res+=(i-bit.sum(ind));
bit.update(ind, 1);
}

Hope you enjoy it !!!

Tuesday 18 August 2015

Sliding Range Query

As the name depicts we will be given a problem and we will compute results for the range-queries.
We can assume that there is a range [Left,Right] in each query and we need to give the answer to the problem for the given range given in each query.

Now what could be the problem, it could be the minimum value, maximum value, sum or anything typical.For this post let us assume we need to find the minimum value.Now let us rephrase the problem : Given an array of numbers find for each range-query the minimum value in the range.
There is also a condition in our favor that these ranges are in increasing order.Example if range-queries are [L1,R1], [L2,R2], [L3,R3]..., then L1<=L2<=L3<=... and R1<=R2<=R3....

Now let us see how to solve the problem.

The Brute force way : O(n^2).

For each range traverse the array store the min till now in a variable and return it. For each query the complexity will be O(n) and for n queries O(n^2).

The Smart way O(n log n).

We can use a segment tree, Binary Indexed Tree or RMQ etc and get the answer for each query in O(logn) time.So overall complexity for n queries is O(n log n).

The Genius way O(n).

Due to the favorable condition of ranges we can use a Deque and solve our problem in linear time.Lets see how to do that.

Let us write down some of the facts that we can observe :

1) Since L and R will always increase we never need to come back, once we have moved forward.
2) When R increase and a number is smaller that current min value, our current min will change else it will not effect our current min.i.e R can only decrease the min, never increase it.
3) When L increase it may be possible our current min is left behind hence our current min will increase else it will remain same.i.e L can only increase the min, never decrease it.

Now how can we use these facts to our advantage, lets see how.

Deque, if someone is confused is a data structure where we can add as well as remove elements from both the ends start as well as last.

So we need to use a deque for adding and removing elements per query such that overall complexity remains O(2*n).i.e each element will be added and removed at most once.

Now here is how we will do our magic :
1) For each R, if the new element is bigger than last element in deque add the element in deque, else remove all elements from deque which are bigger than new element from the end.
2) For each L, if first element of deque is is the element to be removed, remove the element from deque.

Now what will be the output : tadaa, The leftmost element of Deque.

Here is pseudocode in java to do the same :

   Deque<Integer> deque=new LinkedList<Integer>();
int l=0,r=-1;
while(Q-->0)
{
str=in.readLine().split(" ");
int L=Integer.parseInt(str[0])-1;
int R=Integer.parseInt(str[1])-1;
while(l<L)
{
if((!deque.isEmpty())&&deque.getFirst()==arr[l]) deque.removeFirst();
l++;
}
while(R>r)
{
r++;
if((!deque.isEmpty())&&deque.getLast()<=arr[r]) deque.addLast(arr[r]);
else if((!deque.isEmpty()))
{
while((!deque.isEmpty())&&deque.getLast()>arr[r]) deque.removeLast();
}
deque.addLast(arr[r]);
}
out.write(deque.getFirst()+"\n");
}


Hope you enjoy it !!!

  

Saturday 27 June 2015

Z Algorithm

The concept of Z Algorithm is quite simple.
First of all, let us see what is a Z function or a Z array. At any index i, Z[i] stores longest match between
String[i,n] and String[0,n].
For example,
String                Z array
a                        1
aa                       21
aba                     301
ababa                 50301
tests                    50010

So, I hope after reading these examples i hope, its quite clear what a Z array is.
Let us redefine it, Z array stores longest match between all suffixes of a string and string itself. Or we can say if for any i, Z[i]>0 then that suffix is also a prefix of that string with length Z[i].

It has various applications in substring matching and finding count of a substring in a string.
Now let us see how to compute this array.

O(n^2) Algorithm : The Brute Force One.

Here, we one by one see each and every suffix and match it with the string.
for(i=0 to n-1)                                                             // assuming 0 indexing, n=string length
        {
            String suffix=str.substring(i,n);                      // suffix starting from i
            int m=suffix.length();                                    // m=suffix length
            int match=0;                                                 // for storing current longest match.
            for(int j=0;j<m;j++)
            {
                if(str.charAt(j)==suffix.charAt(j)) match++;           // if match found increment match
                else break;                                                                 // else break
            }
            Z[i]=match;                                                  // store the match in Z[i].
        }

In this way we can get the Z function in O(n^2) time, but as we can see all later suffixes are also suffixes of previous ones.We can use this fact to come up with a better approach.

O(n) Algorithm : The Smart One.

As, I have said earlier we can use a fact that we can use the knowledge of previous computed longest match of a previous suffix.To do this we will use two variables L and R (interval) .These two variables for each index will store length of longest substring string[L..R] that is also a prefix of the string.Now how are these two values useful, as we can see in case of a match we can Z[i]=R-L+1; and if no match we need to make R such that Z[i] is 0 and L will be start of that match.

For example if string is ababa
Index              L:R
 0                   0:4
1                   1:0
2                   2:4
3                   3:2
4                   4:4
Now let us see how the algorithm works,suppose we have calculated the values of L and R for an index i, then for an index i+1, we have two simple conditions,if(i>R) then we need to compute new values of L and R,else we can either use a precomputed Z value or compute a new interval.

Now let us see how the algorithm works (source : codeforces blog)

        int L=0,R=0;                                                   // interval L and R initialize
        Z[0]=n;                                                          // this will always be n
        for(i=1 to n)                                                   // start with 1 now.
        {
            if(i>R)                                                       // our initial case
            {
                L=R=i;                                                 // set L and R initially before matching
                while(R<n&&str.charAt(R)==str.charAt(R-i)) R++;          //new R
                Z[i]=R-L;                                            // store Z
                R--;                                                      // bring R back, since last R did not matched.
            }
            else
            {
                int k=i-L;                                           //length of current block of L...R
                if(Z[k]<R-i+1) Z[i]=Z[k];              //since L...R is equal to 0...R-L+1 (match thats why L,R)
                else
                {
                    L=i;                                             // in this case a greater match is possible
                    while(R<n&&str.charAt(R)==str.charAt(R-i)) R++;       //compute a new R
                    Z[i]=R-L;R--;                             // store the new match
                }
            }
        }

In this way, we can compute the Z array.
Problems : CHSTR

Tuesday 19 November 2013

Online Prime Factorization

Prime Factorization -> Technique of finding all prime factors of a number.
There are various algorithms for finding prime factors of a number.

Lets start with the easiest one :

Suppose the number is 12.
Now its prime factors will be 2 , 2 and 3.

Now we need to check for all prime numbers whether they divide the number which we need to factorize or not.But how to decide which prime numbers need to be considered ?

  With little thinking we can conclude that we should start counting from 2 since 1 is not a prime number and the maximum prime number that will be a factor can be the number itself.
Hence we can get the range to check as [2,N] where N is number we need to factorize.

Second conclusion that we can make is that we need to divide the number by a factor till we are able to, for example 8 has factors 2 , 2 and 2 so we need to divide 8 by 2 three times.In other words till remainder is 0.                     //while(N%i==0)

Now the final conclusion could be we can change number N itself once we have got a factor.
For example to find factors of 12 once we divide it by 2 we get 6 , now instead of checking 12 with 2,3,...; we can directly check for 6 by making N = 6 since no number greater than 6 can be a factor of 12.

Pseudo code for the above algorithm can be written as :

The Brute Way


for (i = 2 to N)
{
      while (N % i == 0)
      {
        print(i);
        N /= i;
      }
}

On scratching a bit of head you will be able to conclude that instead of looping till N you could
loop till N/i and later if N>1 you can conclude N as prime.
So the final pseudo code will be :

The Smart Way
 
for (i = 2 to N/i) 
{
      while (N % i == 0
      {
        print(i);
        N /= i;
      }
}
if(N>1) print(N);
 
Applications
The most exciting application of this algorithm is finding no of factors of a number.As we can see,we can find
all prime factors and count from above algorithm, we can use the below formula to find count of all the 
factors of a number :
count(a^p*b^q*....m^z)=(1+a)(1+b)....(1+z).
This can be stored in a variable in above algorithm in similar complexity. 
Problems : Project Euler Problem 12

 
 All suggestions and doubts are welcomed.

What is brain-dump ?

brain-dump
What basically is brain-dump ?
Dumping our brain , more precisely our thoughts , knowledge and doubts.
It is a small attempt to teach algorithms and mathematical tricks that can make life of programmers easier.
So stop thinking start dumping ;)