Event Bubbling and Event Capturing in Javascript

Most of us use event handlers in javascripts be it onclick, onmousedown or any other random event handlers.

Behind the scene, how does javascript deal with them. Lets see.

I will go through some examples which will make it easier for you to understand the concept behind event bubbling and event capturing.

Suppose we have a nested div structure.

Event Bubbling: In javascript when an event is triggered on an element inside DOM, the click gets triggered to its next parent until it reaches the topmost element i.e. html.  This is event bubbling. The event bubbles up the DOM. So when we click on the div with id “three” in above code. The onclick event is fired on “three“, “two” and at last “one“. So we will get inside console the output

three

two

one

Now the target element stays the same i.e. div with id “three“. But event pops up to next parent which can be accessed using ‘this‘.

Event Capturing:  Event capturing is just the opposite of event bubbling, the event starts from topmost parent till it reaches the target element. So on clicking the inside most div i.e div#three. We will get the following response.

one

two

three

Now in javascript if you want to specify whether to use event capturing or event bubbling for event handler. We will concentrate on the third parameter inside addEventListener.

addEventListener(“eventName”, EventHandlerfunction(), boolean);

If you specify it as true you will get event capturing for your event handling while if you specify it as false you will get event bubbling.

Thanks for reading this post.

REST API on RoR

I decided to learn to implement REST Api.. so i chose Ruby on rails framework for this purpose. In this post i will explain building rest api backend using ruby on rails. I am working on MAC env. I suggest u select a linux env or mac when working with RoR, as it is more convenient and working with console is always cool.

You can follow my previous blog post for ruby on rails installation using the below link.

Ruby on Rails Installation

Follow this link to read more about RESTful API.

I wanted to create a simple dashboard with basic CRUD api calls. To create a new task, update, delete or show all tasks we will have 4 different api calls, i.e. GET,POST,PUT,DELETE.

I will share each api call functionality one by one. Now as ruby on rails is a MVC model. So our API call will hit the controller using the routes.rb file and will modify or fetch the data from database using models and render the view as response to be sent to the caller.

I ran into some gems that were needed for my requirement. Go to your Gemfile and add these lines

# rake gem
gem ‘rake’, ‘~> 10.4.2’

Rake gem is used to experiment with the migrations and do many more things like running cron_tasks. You can read more about rake here.

As i said earlier rails app requires 4 steps that of routes, controller, model and view. So setting the route for our application. Go to routes.rb file and add this line

resources :tasks

‘tasks’ is the name of my application which will be accessed like this ‘localhost:3000/tasks’. This url will hit the controller tasks_controller.rb and will render the index.html.erb inside tasks folder in views directory of app. So we need to generate the appropriate controller and model for this app.

rails generate controller tasks #will generate the controller tasks_controller.rb

rails generate model task #will generate the model task.rb

Now you will be able to see the files created in your app folder. To have a more subtle view of routes run 'rake routes' in your console. This will provide you the path that rails will follow depending on the request.

Ruby on Rails Installation

Ruby on rails is a MVC model framework. which is very popular in recent time and used in many companies. For installation follow the below steps. These are written for MAC env.

  1. Install xcode.

xcode-select –install

2.  Install RVM

curl -SSL https://get.rvm.io | bash

source /Users/<username>/.rvm/scripts/rvm

rvm install 2.0.0

Note: You might have to install bundler gem

command: gem install bundler

3.  Install Git

brew install git

4.   By default rails uses sqlite as its database. But i am using mysql db for this                purpose.

brew install mysql

5.  Now all you need to do is to select a working directory and run the following command.

rails new myapp –d mysql  —- use your appname instead of myapp

gem install bundler

6.  Edit the database.yml file inside myapp/config/ directory

add the username and password for mysql. I suggest you download sequel pro for providing a UI to your database and save the overhead for writing out queries. Choose a db name in the development section in database.yml file. and you are good to go.

7.  Start the mysql server

mysql.server start

8.  Now for creating the database you need to use rake command.

rake db:create

if you receive an error in this step. Go to Gemfile file and replace the line gem ‘mysql2’

with

gem 'mysql2', '~> 0.3.18'

and run the command again

9.  Now all you need to do is to start the rails server.

rails s -p “port_number”

without quotes

Reading a UTF-16 encoded file in java and writing back into it.

I have had recent troubles in reading from file which i didnt know was UTF-16 encoded. So i was getting some weird kind of output when i tried printing it. So on googling and with someone’s help, i was able to resolve the problem and want to share this with you guys out there.

First comes reading

Now for reading a file in java as we all know it can be done in a quicker way using the bufferedinputstream.

So what we can do is

File file = new File("File Path");
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF16"));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
String everything = sb.toString();
System.out.println(everything);
} finally {
	br.close();
}

Note we used “UTF-16” as a parameter in the FileInputStream to read in that encoding. “UTF-16” is common in log files as well as some files with unknown extension.

A second way to do this is by simply reading the contents of file as you already used to do. And then when you are done after obtaining a string, you can do something like this.

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
try {
        StringBuilder sb = new StringBuilder();
	String line = br.readLine();
	while (line != null) {
		sb.append(line);
		sb.append(System.lineSeparator());
		line = br.readLine();
	}
	String fileContent = sb.toString();
        final String defaultEncoding = Charset.defaultCharset().name();
        final byte[] utfString = fileContent.getBytes(Charset.forName(defaultEncoding));
	fileContent = new String(utfString, Charset.forName("UTF-16"));
} finally {
     br.close();
}

Now you have the content in readable form. You can always try printing if you are not sure.
Now do some appending or modification with the text. and after this you wanna write it back to the file which expects “UTF-16” encoded string. So, we will reconvert the string to be written to “UTF-16” encoding.

Suppose you would be needing to write the string str into file then.

FileOutputStream fs = new FileOutputStream(file);
fs.write(str.toString().getBytes("UTF-16"));
fs.close();

And here we go, you are done.
In case of any queries or suggestions feel free to comment below. I’ll be happy to help you out.
Happy coding guys.

How Ethernet works?

There would be many of use who are presently in colleges and stay in touch with their mates via Ethernet present in colleges .Most libraries today also use Ethernet to make the access of books easier for the readers.

Now Ethernet basically works on a LAN, and is used for communication between the various nodes that are linked to each other. I want to specify that by nodes I mean the PCs and Laptops that have an Ethernet port present in them. Now suppose you want to send a message to your fellow mate using another port. What will happen is your message will be broadcasted on the network. But the question is how does the Ethernet know to whom the message is intended to. I mean you don’t wanna just broadcast your private message right. So, this is accomplished by the use of IP addresses. That are unique for every system. Now the packet or in Ethernet language the frame sent by you would be prefixed with a header that would contain the info about the source address and the destination address, to whom the message is intended to. Now every node that is connected to the network will receive a broadcast frame, and will look upon the destination address. If it matches its IP Address then it will take it otherwise it will discard it.

A Daily Life Example

Now Suppose that there is small room in which some well mannered people are having a conversation. Now, as they are smart and well mannered, before anyone would be willing to share something they would confirm that no one else is talking at that moment. And then only would they speak. This is what happens in Ethernet. If a node wants to broadcast a frame then it waits till the network becomes silent or the network is currently idle. Now coming back to the room example, suppose the everyone has finished and more than one person wants to share something. This situation is termed as collision. When this kind of situation occurs in the Ethernet then the node wait for a random amount of time, so that when the nodes have finished waiting they don’t collide again.

The Ethernet range is usually small like about 500 meters only. But in huge campuses, this kind of thing is undesirable. So repeaters are used to increase the range. The repeaters are basically devices that transfer the frame from one Ethernet segment to another, thereby increasing the range. 

Suppose the small room now becomes a larger room where there are many groups talking to each other at the same time. Now if every one follows the same procedure of mannerism that is waiting for others to finish and then start saying something. That wont be viable. But what happens when someone in your group is talking to you, you are able to distinguish that person’s voice from all the voices that are being heard at the same time. So ,  The probability of collision increases many folds and this leads to delay in communication and slows it. To resolve this network traffic issue, Bridges come into play. Bridges mostly function same as repeaters like transferring the frame from one segment to other. The network is divided into segments. When the frame comes to bridge it checks for the destination address and transfers the frame to that segment accordingly rather than simply broadcasting it to every other segment, it encounters. Bridges are able to reduce traffic upto some level. 

Switches were introduced later on to improvise the concept of bridges and to enhance the transfer speed between the network. Switched Ethernet allows a system to have its own segment and switches allow more segments to connect. Switches replaced the sharing technology with the dedicated station segment for each node. Switches on receiving the frame sends it to the appropriate segment. But since every segment is associated with an individual node, it allows the frame to sent only to the recipient. This allows many conversation to occur simultaneously on the switched network. Switched networks allowed the Ethernet to be full duplex that is node can send as well as receive at the same time. Since the nodes do not directly communicate with each other they do it via the switch, This allows the communication to be collision free. With the use of fiber optic cables transfer speeds of 100Mb/s to 1000Mb/s can be achieved. Switches allow the device to use the whole bandwidth for itself.

Now there is a difference between how the switches and how the routers do. Switches are considered to operable at layer 2 (Data-Link) of OSI Model i.e they work over the MAC addresses, and NIC. while the routers operate on layer 3 that includes IP addresses. Now consider a 4 way road. Suppose vehicles are coming from all four directions intersecting at a common point. Instead of waiting for the road to be clear Switches makes an exit pass for the vehicle that allows them to cross the point without waiting for others to stop. Thats why switches allow the device to use the whole bandwidth for sending and receiving data. In a network the devices can communicate easily if they know destination addresses of each other. Suppose a new device is added to the network. Then how would the other devices know its address. So when a new device enters the network it broadcasts a message which allows all the devices to save its address in their memory, and communicate directly from that point. 

How are routers different from this? Suppose on 4 way road, on reaching the intersection point you have to give the destination address to the border security guard before you can cross the road. Now if you dont know the destination address, then you cant pass. So routers dont allow broadcasts to be sent without knowing the destination address. This is where switches are used. Routers are used to connect two different networks.

Here’s a step-by-step description of transparent bridging:

  • The switch is added to the network, and the various segments are plugged into the switch’s ports.
  • A computer (Node A) on the first segment (Segment A) sends data to a computer (Node B) on another segment (Segment C).
  • The switch gets the first packet of data from Node A. It reads the MAC address and saves it to the lookup table for Segment A. The switch now knows where to find Node A anytime a packet is addressed to it. This process is called learning.
  • Since the switch does not know where Node B is, it sends the packet to all of the segments except the one that it arrived on (Segment A). When a switch sends a packet out to all segments to find a specific node, it is called flooding.
  • Node B gets the packet and sends a packet back to Node A in acknowledgement.
  • The packet from Node B arrives at the switch. Now the switch can add the MAC address of Node B to the lookup table for Segment C. Since the switch already knows the address of Node A, it sends the packet directly to it. Because Node A is on a different segment than Node B, the switch must connect the two segments to send the packet. This is known as forwarding.
  • The next packet from Node A to Node B arrives at the switch. The switch now has the address of Node B, too, so it forwards the packet directly to Node B.
  • Node C sends information to the switch for Node A. The switch looks at the MAC address for Node C and adds it to the lookup table for Segment A. The switch already has the address for Node A and determines that both nodes are on the same segment, so it does not need to connect Segment A to another segment for the data to travel from Node C to Node A. Therefore, the switch will ignore packets traveling between nodes on the same segment. This is filtering.
  • Learning and flooding continue as the switch adds nodes to the lookup tables. Most switches have plenty of memory in a switch for maintaining the lookup tables; but to optimize the use of this memory, they still remove older information so that the switch doesn’t waste time searching through stale addresses. To do this, switches use a technique called aging. Basically, when an entry is added to the lookup table for a node, it is given a timestamp. Each time a packet is received from a node, the timestamp is updated. The switch has a user-configurable timer that erases the entry after a certain amount of time with no activity from that node. This frees up valuable memory resources for other entries. As you can see, transparent bridging is a great and essentially maintenance-free way to add and manage all the information a switch needs to do its job!

In our example, two nodes share segment A, while the switch creates independent segments for Node B and Node D. In an ideal LAN-switched network, every node would have its own segment. This would eliminate the possibility of collisions and also the need for filtering.

Abstract Class and Virtual Function in C++

Abstract Class

Abstract Class is a class which contains atleast one Pure Virtual function in it. Abstract classes are used to provide an Interface for its sub classes. Classes inheriting an Abstract Class must provide definition to the pure virtual function, otherwise they will also become abstract class.

 

Characteristics of Abstract Class

  1. Abstract class cannot be instantiated, but pointers and refrences of Abstract class type can be created.
  2. Abstract class can have normal functions and variables along with a pure virtual function.
  3. Abstract classes are mainly used for Upcasting, so that its derived classes can use its interface.
  4. Classes inheriting an Abstract Class must implement all pure virtual functions, or else they will become Abstract too.

Pure Virtual Functions

Pure virtual Functions are virtual functions with no definition. They start with virtual keyword and ends with= 0. Here is the syntax for a pure virtual function,

virtual void f() = 0;

Concept Of VTables

When working with virtual functions in C++, it’s the vtable that’s being used behind the scenes to help achieve polymorphism. And, although you can understand polymorphism without understanding vtables, many interviewers like to ask this question just to see if you really know your stuff.

Whenever a class itself contains virtual functions or overrides virtual functions from a parent class the compiler builds a vtable for that class. This means that not all classes have a vtable created for them by the compiler. The vtable contains function pointers that point to the virtual functions in that class. There can only be one vtable per class, and all objects of the same class will share the same vtable.

Associated with every vtable is what’s called a vpointer. The vpointer points to the vtable, and is used to access the functions inside the vtable. The vtable would be useless without a vpointer.

class Animal // base class
{

public:

int weight;

virtual int getWeight() {};
}


// Obviously, Tiger derives from the Animal class
class Tiger: public Animal {

public:

int weight;

int height; 

int getWeight() {return weight;};

int getHeight() {return height;};

int main()
{	
	Tiger t1;
	
	/* below, an Animal object pointer is set to point
	   to an object of the derived Tiger class  */
	
	Animal *a1 = &t1; 
	
	/*  below, how does this know to call the 
		definition of getWeight in the Tiger class, 
		and not the definition provided in the Animal 
		class  */
		
	a1 -> getWeight(); 
}			
}

For any class that contains a vtable, the compiler will also add “hidden” code to the constructor of that class to initialize the vpointers of its objects to the address of the corresponding vtable.

The vtable contains function pointers that point to the virtual functions in that class. It’s important to note that there can only be one vtable per class, and all objects of the same class will share the same vtable. This means that in the example above, the Animal and Tiger classes will each have their very own vtable, and any objects of the Animal or Tiger classes will use their respective class’s vtables.

The question that the code above raises is at runtime how does the call “a1 -> getWeight()” know to use the version of getWeight provided in the Tiger – and not the Animal class. The answer, as you probably guessed, is by using vtables.

Because the Tiger class contains a pointer to the vtable called vptr1, the call “a1 -> getWeight()” will actually be translated to “(*(a1 -> vptr1 -> getWeight())”.

Dpkg Lock in Ubuntu

Often using Ubuntu, especially when installing or updating an application,  /var/lib/dpkg/lock is acquired . And if the process turns into a infinite loop or stucks, then you may have to wait for a pretty long time.. which is really nasty. The error looks like this

E: Could not get lock /var/lib/dpkg/lock – open (11 Resource temporarily unavailable)
  E: Unable to lock the administration directory (/var/lib/dpkg/), is another process using it?

So i saw a solution on internet a few days ago to undo the lock without deleting the file.

Now as i said this error occurs when you try to download a package using the command   ‘sudo apt-get install xyz
in the terminal while you have Synaptic package manager open (or vice versa) or in another terminal you are installing another package . The most common solution is just to wait for the other installation(s) to finish  and close the package manager if you are done with it. However, if the package manager is crashed in the middle some stuck-up  processes may still be using the lock (/var/lib/dpkg/lock).

In that case, use fuser to find out the runaway process(es); and while you’re at it, you may use -k flag which will kill the process that is still using /var/lib/dpkg/lock. Then configure (–configure) all the packages (-a) which are yet unpacked and unconfigured, using dpkg:
$ sudo fuser -vki /var/lib/dpkg/lock;

    $ sudo dpkg –configure -a

In the first command (fuser), the -i flag asks for user confirmation, and -v is for verbose mode.

After that, proceed to the usual installation step of the package that you want to install.

Nice n Easy!! Well there were some other ways too but i didnt trust’em. I found this solution convienient.

How to install Sublime Text 3 on Ubuntu/Windows and crack the license.

As we know how cool is the interface of Sublime Text 3, n I m sure the coders would enjoy using it. But unfortunately you have to purchase a license to use it.. But not any more .. Follow these steps for using Sublime Text without license..

For Windows

1. Download Sublime Text 3 from its official website as usual.. http://www.sublimetext.com/3

2. Now U need to get a hex-code editor to continue further. http://www.hexedit.com/

3. After this go to the location where you have installed Sublime Text and open the launcher file i.e. sublime text.exe file with hex-editor.

4. Now for

64 Bit Windows
Find:85 C0 0F 94 C0 88 05 D2 BA 41 00 84 C0
Replace:90 90 90 90 90 88 05 D2 BA 41 00 84 C0

32 Bit Windows
Find:74 03 33 FF 47 85 FF 0F 85 9A 06 00 00 BE 1C BE
Replace:75 03 33 FF 90 85 FF 0F 85 9A 06 00 00 BE 1C BE

After this start the sublime text application

Go to help->enter license

and copy this into it

—————————————————————————————————————————————-

– BEGIN License –
Love
Unlimited user license
EA7E-8441
918381ACA844A0379CCAC729059720A4
BC9D409098618744BB45FF23E67568DB
82B926D92157127DB3B4054834D0477F
DD9C2B251A57F2E3259E04AD9B7DB8B8
1778C37C1D3B494671C5F4ECFBD2B519
361CD9624A56C21F54F8DD51F5BDF799
68F9537ED74680494853423904F032BA
3E896607B4D398E8C897A4DD1A8CB449
– END the LICENSE –

—————————————————————————————————————————————————————-

For Linux/Ubuntu

For linux/ubuntu users go to the terminal. Install vim in it.

1. Open sublime_text with vim by typing “sudo vim /opt/sublime_text/sublime_text”(without quotes)

2. Convert to hex, type “:%!xxd“(without quotes)

3. Search and replace value by typing “:%s/7001 0000 8a9b b800 0000 e87f 3f00 0048/7001 0000 90b3 0190 9090 e87f 3f00 0048/“(without quotes)

4. Convert to binary, “:%!xxd -r“(without quotes)

5.  Save the file and exit, type “:wq”(without quotes)

Open the sublime text either by typing “subl”  in terminal or through the dash.

After that go to Help->Enter License

And copy this

– BEGIN License –
Love
Unlimited user license
EA7E-8441
918381ACA844A0379CCAC729059720A4
BC9D409098618744BB45FF23E67568DB
82B926D92157127DB3B4054834D0477F
DD9C2B251A57F2E3259E04AD9B7DB8B8
1778C37C1D3B494671C5F4ECFBD2B519
361CD9624A56C21F54F8DD51F5BDF799
68F9537ED74680494853423904F032BA
3E896607B4D398E8C897A4DD1A8CB449
– END the LICENSE –

 

And this should do it.. 😀

Hope it works. For further queries you can comment below.

 

 

Longest Increasing Subsequence Problem with O(nlogn) complexity

Given an array of random numbers. Find longest monotonically increasingsubsequence (LIS) in the array. I know many of you might have read recursive and dynamic programming (DP) solutions. There are few requests for O(N log N) algo in the forum posts.

For the time being, forget about recursive and DP solutions. Let us take small samples and extend the solution to large instances. Even though it may look complex at first time, once if we understood the logic, coding is simple.

Consider an input array A = {2, 5, 3}. I will extend the array during explanation.

By observation we know that the LIS is either {2, 3} or {2, 5}. Note that I am considering only strictly increasing monotone sequences.

Let us add two more elements, say 7, 11 to the array. These elements will extend the existing sequences. Now the increasing sequences are {2, 3, 7, 11} and {2, 5, 7, 11} for the input array {2, 5, 3, 7, 11}.

Further, we add one more element, say 8 to the array i.e. input array becomes {2, 5, 3, 7, 11, 8}. Note that the latest element 8 is greater than smallest element of any active sequence (will discuss shortly about active sequences). How can we extend the existing sequences with 8? First of all, can 8 be part of LIS? If yes, how? If we want to add 8, it should come after 7 (by replacing 11).

Since the approach is offline (what we mean by offline?), we are not sure whether adding 8 will extend the series or not. Assume there is 9 in the input array, say {2, 5, 3, 7, 11, 8, 7, 9 …}. We can replace 11 with 8, as there is potentially best candidate (9) that can extend the new series {2, 3, 7, 8} or {2, 5, 7, 8}.

Our observation is, assume that the end element of largest sequence is E. We can add (replace) current element A[i] to the existing sequence if there is an element A[j] (j > i) such that E < A[i] < A[j] or (E > A[i] < A[j] – for replace). In the above example, E = 11, A[i] = 8 and A[j] = 9.

In case of our original array {2, 5, 3}, note that we face same situation when we are adding 3 to increasing sequence {2, 5}. I just created two increasing sequences to make explanation simple. Instead of two sequences, 3 can replace 5 in the sequence {2, 5}.

I know it will be confusing, I will clear it shortly!

The question is, when will it be safe to add or replace an element in the existing sequence?

Let us consider another sample A = {2, 5, 3}. Say, the next element is 1. How can it extend the current sequences {2,3} or {2, 5}. Obviously, it can’t extend either. Yet, there is a potential that the new smallest element can be start of an LIS. To make it clear, consider the array is {2, 5, 3, 1, 2, 3, 4, 5, 6}. Making 1 as new sequence will create new sequence which is largest.

The observation is, when we encounter new smallest element in the array, it can be a potential candidate to start new sequence.

From the observations, we need to maintain lists of increasing sequences.

In general, we have set of active lists of varying length. We are adding an element A[i] to these lists. We scan the lists (for end elements) in decreasing order of their length. We will verify the end elements of all the lists to find a list whose end element is smaller than A[i] (floor value).

Our strategy determined by the following conditions,

1. If A[i] is smallest among all end candidates of active lists, we will start new active list of length 1.

2. If A[i] is largest among all end candidates of active lists, we will clone the largestactive list, and extend it by A[i].

3. If A[i] is in between, we will find a list with largest end element that is smaller than A[i]. Clone and extend this list by A[i]. We will discard all other lists of same length as that of this modified list.

Note that at any instance during our construction of active lists, the following condition is maintained.

“end element of smaller list is smaller than end elements of larger lists”.

It will be clear with an example, let us take example from wiki {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}.

A[0] = 0. Case 1. There are no active lists, create one.
0.
-----------------------------------------------------------------------------
A[1] = 8. Case 2. Clone and extend.
0.
0, 8.
-----------------------------------------------------------------------------
A[2] = 4. Case 3. Clone, extend and discard.
0.
0, 4.
0, 8. Discarded
-----------------------------------------------------------------------------
A[3] = 12. Case 2. Clone and extend.
0.
0, 4.
0, 4, 12.
-----------------------------------------------------------------------------
A[4] = 2. Case 3. Clone, extend and discard.
0.
0, 2.
0, 4. Discarded.
0, 4, 12.
-----------------------------------------------------------------------------
A[5] = 10. Case 3. Clone, extend and discard.
0.
0, 2.
0, 2, 10.
0, 4, 12. Discarded.
-----------------------------------------------------------------------------
A[6] = 6. Case 3. Clone, extend and discard.
0.
0, 2.
0, 2, 6.
0, 2, 10. Discarded.
-----------------------------------------------------------------------------
A[7] = 14. Case 2. Clone and extend.
0.
0, 2.
0, 2, 6.
0, 2, 6, 14.
-----------------------------------------------------------------------------
A[8] = 1. Case 3. Clone, extend and discard.
0.
0, 1.
0, 2. Discarded.
0, 2, 6.
0, 2, 6, 14.
-----------------------------------------------------------------------------
A[9] = 9. Case 3. Clone, extend and discard.
0.
0, 1.
0, 2, 6.
0, 2, 6, 9.
0, 2, 6, 14. Discarded.
-----------------------------------------------------------------------------
A[10] = 5. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 5.
0, 2, 6. Discarded.
0, 2, 6, 9.
-----------------------------------------------------------------------------
A[11] = 13. Case 2. Clone and extend.
0.
0, 1.
0, 1, 5.
0, 2, 6, 9.
0, 2, 6, 9, 13.
-----------------------------------------------------------------------------
A[12] = 3. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 3.
0, 1, 5. Discarded.
0, 2, 6, 9.
0, 2, 6, 9, 13.
-----------------------------------------------------------------------------
A[13] = 11. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 3.
0, 2, 6, 9.
0, 2, 6, 9, 11.
0, 2, 6, 9, 13. Discarded.
-----------------------------------------------------------------------------
A[14] = 7. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 3.
0, 1, 3, 7.
0, 2, 6, 9. Discarded.
0, 2, 6, 9, 11.
----------------------------------------------------------------------------
A[15] = 15. Case 2. Clone and extend.
0.
0, 1.
0, 1, 3.
0, 1, 3, 7.
0, 2, 6, 9, 11.
0, 2, 6, 9, 11, 15. <-- LIS List
----------------------------------------------------------------------------

It is required to understand above strategy to devise an algorithm. Also, ensure we have maintained the condition, “end element of smaller list is smaller than end elements of larger lists“. Try with few other examples, before reading further. It is important to understand what happening to end elements.

Algorithm:

Querying length of longest is fairly easy. Note that we are dealing with end elements only. We need not to maintain all the lists. We can store the end elements in an array. Discarding operation can be simulated with replacement, and extending a list is analogous to adding more elements to array.

We will use an auxiliary array to keep end elements. The maximum length of this array is that of input. In the worst case the array divided into N lists of size one (note that it does’t lead to worst case complexity). To discard an element, we will trace ceil value of A[i] in auxiliary array (again observe the end elements in your rough work), and replace ceil value with A[i]. We extend a list by adding element to auxiliary array. We also maintain a counter to keep track of auxiliary array length.

Bonus: You have learnt Patience Sorting technique partially :).

Here is a proverb, “Tell me and I will forget. Show me and I will remember. Involve me and I will understand.” So, pick a suit from deck of cards. Find the longest increasing sub-sequence of cards from the shuffled suit. You will never forget the approach. :)

Given below is code to find length of LIS,

#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
#define ARRAY_SIZE(A) sizeof(A)/sizeof(A[0])
// Binary search (note boundaries in the caller)
// A[] is ceilIndex in the caller
int CeilIndex(int A[], int l, int r, int key) {
    int m;
    while( r - l > 1 ) {
        m = l + (r - l)/2;
        (A[m] >= key ? r : l) = m; // ternary expression returns an l-value
    }
    return r;
}
int LongestIncreasingSubsequenceLength(int A[], int size) {
    // Add boundary case, when array size is one
    int *tailTable   = new int[size];
    int len; // always points empty slot
    memset(tailTable, 0, sizeof(tailTable[0])*size);
    tailTable[0] = A[0];
    len = 1;
    for( int i = 1; i < size; i++ ) {
        if( A[i] < tailTable[0] )
            // new smallest value
            tailTable[0] = A[i];
        else if( A[i] > tailTable[len-1] )
            // A[i] wants to extend largest subsequence
            tailTable[len++] = A[i];
        else
            // A[i] wants to be current end candidate of an existing subsequence
            // It will replace ceil value in tailTable
            tailTable[CeilIndex(tailTable, -1, len-1, A[i])] = A[i];
    }
    delete[] tailTable;
    return len;
}
int main() {
    int A[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
    int n = ARRAY_SIZE(A);
    printf("Length of Longest Increasing Subsequence is %d\n",
            LongestIncreasingSubsequenceLength(A, n));
    return 0;
}

Complexity:

The loop runs for N elements. In the worst case (what is worst case input?), we may end up querying ceil value using binary search (log i) for many A[i].

Therefore, T(n) < O( log N! )  = O(N log N). Analyse to ensure that the upper and lower bounds are also O( N log N ). The complexity is THETA (N log N).

 

 

This post has been taken from http://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/..   I happened to encounter this post after going through a LIS question.

Design a site like this with WordPress.com
Get started