<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-759530137113893554</id><updated>2025-07-01T21:20:24.623-07:00</updated><category term="algorithms"/><category term="maths"/><category term="puzzle"/><category term="probability"/><category term="hash"/><title type='text'>Puzzles, Maths and Algorithms</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>34</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-6078820850276633907</id><published>2015-02-16T00:13:00.001-08:00</published><updated>2015-02-16T00:14:37.280-08:00</updated><title type='text'>Finding Switch - Bulb Association</title><content type='html'>&lt;b&gt;Problem 1&lt;/b&gt;: There are three light bulbs in a room. Outside the room are three switches which operate those bulbs. You know that the bulbs are initially turned off and you can toggle the switches as much as you want. While you toggle the switches, you cant peek inside the room. Finally when you are done with the switches, you enter the room once and you have to tell which switch is associated with which bulb. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Solution&lt;/b&gt;: &lt;a href=&quot;#&quot; id=&quot;fslba021615_a&quot; onclick=&quot;return toggleMenuAdi(&#39;fslba021615_a&#39;,&#39;fslba021615_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;fslba021615_s&quot; style=&quot;display: none;&quot;&gt;1. Toggle switch 1 and wait for 10 mins. &lt;br /&gt;
2. Toggle switch 1 and 2. &lt;br /&gt;
3. Enter the room.&lt;br /&gt;
4. Touch all the bulbs and the bulb which is hot is associated with switch 1. &lt;br /&gt;
5. Bulb which is on is associated with switch 2. &lt;br /&gt;
6. Bulb which is off is associated with switch 3. &lt;/div&gt;&lt;br /&gt;
&lt;b&gt;Problem 2&lt;/b&gt;: Same problem as 1, but now we dont know if the bulbs are initially on or off. So in a way we do not know if turning the switch up turns on the bulb or turns it off. All we know is that all the bulbs are in same state, i.e., all are either on or off. Now we have to toggle the switches and enter the room once and tell which switch operates which bulb. &lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/6078820850276633907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2015/02/finding-switch-light-bulb-association.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/6078820850276633907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/6078820850276633907'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2015/02/finding-switch-light-bulb-association.html' title='Finding Switch - Bulb Association'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-3296655272595836605</id><published>2014-07-02T09:32:00.000-07:00</published><updated>2014-07-02T10:41:18.567-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="puzzle"/><title type='text'>Solving Sudoku Puzzles</title><content type='html'>Recently, I got hooked on to &lt;a href=&quot;http://en.wikipedia.org/wiki/Sudoku&quot;&gt;Sudoku&lt;/a&gt; (thanks to a wonderful IPhone app). I found it to be a slightly more constructive time sink and plan to teach it to my daughter some day (she is one year old as of yet). For this, I thought of writing an assistive software to teach kids how to simplify a Sudoku. This motivated me to first build a Sudoku solver and this blog is about it. &lt;br /&gt;
&lt;br /&gt;
A Sudoku is a matrix of cells, typically 9x9, but it can be any number. In this post, we consider N x N Sudoku (where N is a perfect square, i.e. 1x1, 4x4, 9x9, 16x16). Now for such a Sudoku, we first construct a groups of cells called as blocks. We get N row blocks, N column blocks and N sub-grid blocks. All the blocks contain N cells each. A cell can have a value from 1 to N, such that, if a cell is assigned a value, then no other cell in the same block can be assigned that value. To check if a Sudoku is solved, all the blocks must sum to N*(N+1)/2. Another check is one where number uniqueness constraints are satisfied per block and each cell is assigned a value from 1 to N.&lt;br /&gt;
&lt;br /&gt;
To simplify a Sudoku by hand, I typically use the following techniques:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;A number is assigned to a cell,&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;If a cell can hold only that number.&lt;/li&gt;
&lt;li&gt;If that number can be held by only that cell (in at least one block).&lt;/li&gt;
&lt;/ul&gt;Once a cell is assigned a number, other cells (in the same block) get their possible hints (or values) pruned.&lt;br /&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Two numbers are assigned to two cells if those two cells share at least one block (Note: two cells can share maximum of two blocks),&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;The two numbers are referred exclusively by these two cells in a given block. In this case other hints of the two numbers are pruned.&lt;/li&gt;
&lt;li&gt;The two cells refer to those two numbers only. In this case the two numbers are removed from the hints of other cells in their shared block.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;To finally solve it, simplify Sudoku by applying (1) and (2) until further simplification is not possible. Then pick a cell with least number of hints. Assign it one of those hints and repeat this brute-force method. If failed, then try another hint. If all hints fail then Sudoku is not solvable.&lt;/li&gt;
&lt;/ol&gt;Algorithm 1a, 1b are pretty straightforward. Algorithm 2a and 2b are also easy to see (if you have played Sudoku before). In spirit Algo 2 can be extended for k&amp;gt;2 but the benefit of simplification it provides is marginal compared to the cost of finding set of k cells or k numbers that satisfy the unique reference aspect. Now to encode these algorithms, I &lt;a href=&quot;https://github.com/n1balgo/sudoku&quot;&gt;wrote a Java program&lt;/a&gt; which solves Sudoku of size N x N (where N is a perfect square). &lt;br /&gt;
&lt;br /&gt;
The program is oriented to be event driven, where a cell is asked to remove its hint based on the logic of (1,2,3). In this process if a cell has only one hint remaining, it triggers a fix event. When the fix event is called, this cell is assigned the value and that value is removed from the hint of cells that share block with it. If at anytime any inconsistencies are found, the events return a “false”, indicating that Sudoku is not solvable. This is a fail fast technique and it quickly helps in determining if a Sudoku is non-solvable or not. Otherwise, we would wait for all cells to get filled and then realize that it failed (wasting precious time). A simple brute-force strategy is very easy to code, however the possibilities to check are huge. For e.g., we might end up checking O(9^81) possibilities (which can be prohibitive). The simplification algorithms (1) and (2) come to the rescue by drastically simplifying the Sudoku. For most of the easy problems - the recursive step (3) is not even triggered. &lt;br /&gt;
&lt;br /&gt;
I searched online for Sudoku problems and found that Peter Norvig has a &lt;a href=&quot;http://norvig.com/sudoku.html&quot;&gt;blog&lt;/a&gt; about it.  He used algo(1,3) but not (2) and has shared a set of easy, hard, and hardest Sudoku puzzles. It amazes me to say that for most hard problem, I take at least 8-10 minutes (and sometimes a hint) but a computer can solve it in order of ~0.1 ms. If you are interested in the maths of Sudoku (e.g. number of possible solutions), please check out the wikipedia page: &lt;a href=&quot;http://en.wikipedia.org/wiki/Mathematics_of_Sudoku&quot;&gt;maths of sudoku&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
In the first analysis below, we see how many cells different algorithms are able to solve. &lt;br /&gt;
&lt;table border=&quot;1&quot; cellpadding=&quot;5&quot; cellspacing=&quot;2&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&amp;nbsp;Input&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp;(1)&lt;/td&gt;&lt;td&gt;&amp;nbsp; (2a)&lt;/td&gt;&lt;td&gt;&amp;nbsp;(2b)&lt;/td&gt;&lt;td&gt;&amp;nbsp; (2)&lt;/td&gt;&lt;td&gt;&amp;nbsp;(1+2a)&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;(1+2b)&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; (*)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Easy&lt;/td&gt;&lt;td&gt;&amp;nbsp;35%&lt;/td&gt;&lt;td&gt;&amp;nbsp;89%&lt;/td&gt;&lt;td&gt;&amp;nbsp;54%&lt;/td&gt;&lt;td&gt;&amp;nbsp;68%&lt;/td&gt;&lt;td&gt;&amp;nbsp;70%&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp;96%&lt;/td&gt;&lt;td&gt;&amp;nbsp; 94%&lt;/td&gt;&lt;td&gt;&amp;nbsp;96%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Hard&lt;/td&gt;&lt;td&gt;&amp;nbsp;25%&lt;/td&gt;&lt;td&gt;&amp;nbsp;31%&lt;/td&gt;&lt;td&gt;&amp;nbsp;26%&lt;/td&gt;&lt;td&gt;&amp;nbsp;26%&lt;/td&gt;&lt;td&gt;&amp;nbsp;26%&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp;41%&lt;/td&gt;&lt;td&gt;&amp;nbsp; 31%&lt;/td&gt;&lt;td&gt;&amp;nbsp;41%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Hardest&lt;/td&gt;&lt;td&gt;&amp;nbsp;30%&lt;/td&gt;&lt;td&gt;&amp;nbsp;45%&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;35%&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;35%&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;36%&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp;50%&lt;/td&gt;&lt;td&gt;&amp;nbsp; 45%&lt;/td&gt;&lt;td&gt;&amp;nbsp;50%&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
Here we see that algorithm (1) itself can solve 89% of the cells for easy problems. However, the joint application of (1+2) is able to solve 96% of the easy cells and 41% of the hard cells (and roughly provide a 10-15% improvement. This is a great simplification, especially for easy Sudoku problems. Amongst (2a) and (2b), I find (2a) to be a better strategy to run in conjunction with (1) as (1+2a) has same result as (*).&lt;br /&gt;
&lt;br /&gt;
In the next analysis, we see how many hints are left after application of different algorithms&lt;br /&gt;
&lt;table border=&quot;1&quot; cellpadding=&quot;5&quot; cellspacing=&quot;2&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&amp;nbsp;Input&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; (1)&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;(2a)&lt;/td&gt;&lt;td&gt;&amp;nbsp;(2b)&lt;/td&gt;&lt;td&gt;&amp;nbsp; (2)&lt;/td&gt;&lt;td&gt;&amp;nbsp;(1+2a)&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;(1+2b)&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; (*)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Easy&lt;/td&gt;&lt;td&gt;&amp;nbsp; 474&lt;/td&gt;&lt;td&gt;&amp;nbsp; 29&lt;/td&gt;&lt;td&gt;&amp;nbsp;126&lt;/td&gt;&lt;td&gt;&amp;nbsp; 89&lt;/td&gt;&lt;td&gt;&amp;nbsp; 82&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp;10&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp; 16&lt;/td&gt;&lt;td&gt;&amp;nbsp; 10&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Hard&lt;/td&gt;&lt;td&gt;&amp;nbsp; 544&lt;/td&gt;&lt;td&gt;&amp;nbsp;230&lt;/td&gt;&lt;td&gt;&amp;nbsp;252&lt;/td&gt;&lt;td&gt;&amp;nbsp;260&lt;/td&gt;&lt;td&gt;&amp;nbsp;250&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp;184&lt;/td&gt;&lt;td&gt;&amp;nbsp; 228&lt;/td&gt;&lt;td&gt;&amp;nbsp;181&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Hardest&lt;/td&gt;&lt;td&gt;&amp;nbsp; 508&lt;/td&gt;&lt;td&gt;&amp;nbsp;161&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;191&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;193&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;189&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp;141&lt;/td&gt;&lt;td&gt;&amp;nbsp; 158&lt;/td&gt;&lt;td&gt;&amp;nbsp;141&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
Similar analysis as above. 2a appears better than 2b. But (*) must better than (1) or (2). So combining these strategies is much more effective. We see that clearly (1+2a) as good as (*) so we can simply drop algorithm 2b. To see how much (if at all) there is a penalty of running the (2b) algo, we turn to time taken.&lt;br /&gt;
&lt;br /&gt;
For measuring time, I use Java&#39;s System.NanoTime() function, which gives very precise timing. Experiments are run on my MacBook Pro with 2.6Ghz intel I7 processor. To get the timings, I solve a puzzle 500 times and take the average solving time. We get the following timings.&lt;br /&gt;
&lt;br /&gt;
&lt;table border=&quot;1&quot; cellpadding=&quot;5&quot; cellspacing=&quot;2&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&amp;nbsp;Brute Force&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;(1)&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; (1+2a)&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; (1+2b)&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; (*)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Easy&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp; 0.14 ms&lt;/td&gt;&lt;td&gt;&amp;nbsp;0.04 ms&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;0.03 ms&lt;/td&gt;&lt;td&gt;&amp;nbsp; 0.03 ms&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; 0.03 ms&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Hard&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp; 21 ms&lt;/td&gt;&lt;td&gt;&amp;nbsp;1.16 ms&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;0.44 ms&lt;/td&gt;&lt;td&gt;&amp;nbsp; 0.55 ms&lt;/td&gt;&lt;td&gt;&amp;nbsp; 0.42 ms&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Hardest&lt;/td&gt;&lt;td&gt;&amp;nbsp; &amp;nbsp; 0.61 ms&lt;/td&gt;&lt;td&gt;&amp;nbsp;0.17 ms&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp;0.20 ms&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; 0.19 ms&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;nbsp; 0.22 ms&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
Clearly brute force without simplification is a bad idea. (*) improves timing over (1) for hard problems at least. For other problems, numbers are very close to conclude. My experience over other random problems that I tried, suggests that (*) leads to fastest simplification (i.e. reduced iterations) and hence better.&lt;br /&gt;
&lt;br /&gt;
I also tried the problem that Peter mentions taking most time and noted its timing through my Java implementation. It took 6134 ms for algo (1), but only 10ms for (*). A clear evidence of the joint algorithms&#39; usefulness. This improved timing comes from the fact that Sudoku gets drastically simplified before entering the brute-force stage and even for each choice of brute-force, it further gets simplified eliminating possible hints.&lt;br /&gt;
&lt;br /&gt;
The &lt;a href=&quot;https://github.com/n1balgo/sudoku&quot;&gt;Sudoku program&lt;/a&gt; is generic in the sense that it can solve 1x1, 4x4, 9x9, 16x16, … problems. A quick run of the program is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: Monaco; font-size: 11px;&quot;&gt;Solving a Sudoku puzzle of size 1 ...&lt;br /&gt;
&amp;nbsp;===&lt;br /&gt;
| * |&lt;br /&gt;
&amp;nbsp;===&lt;br /&gt;
[status] solved=0 hints=1&lt;br /&gt;
&amp;nbsp;===&lt;br /&gt;
| 1 |&lt;br /&gt;
&amp;nbsp;===&lt;br /&gt;
[status] SOLVED&lt;br /&gt;
Time taken=0.022 ms&lt;br /&gt;
&lt;div style=&quot;min-height: 15px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;Solving a Sudoku puzzle of size 4 ...&lt;br /&gt;
&amp;nbsp;===== =====&lt;br /&gt;
| 4 * | 2 * |&lt;br /&gt;
| * * | 4 1 |&lt;br /&gt;
&amp;nbsp;===== =====&lt;br /&gt;
| 1 * | * * |&lt;br /&gt;
| * * | 1 4 |&lt;br /&gt;
&amp;nbsp;===== =====&lt;br /&gt;
[status] solved=7 hints=36&lt;br /&gt;
&amp;nbsp;===== =====&lt;br /&gt;
| 4 1 | 2 3 |&lt;br /&gt;
| 2 3 | 4 1 |&lt;br /&gt;
&amp;nbsp;===== =====&lt;br /&gt;
| 1 4 | 3 2 |&lt;br /&gt;
| 3 2 | 1 4 |&lt;br /&gt;
&amp;nbsp;===== =====&lt;br /&gt;
[status] SOLVED&lt;br /&gt;
Time taken=0.132 ms&lt;br /&gt;
&lt;div style=&quot;min-height: 15px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;Solving a Sudoku puzzle of size 9 ...&lt;br /&gt;
&amp;nbsp;======= ======= =======&lt;br /&gt;
| * * * | 7 * * | 6 * 3 |&lt;br /&gt;
| 7 * 3 | 9 * * | * 1 2 |&lt;br /&gt;
| * * * | 5 3 * | * * * |&lt;br /&gt;
&amp;nbsp;======= ======= =======&lt;br /&gt;
| 1 * * | * * * | * * 7 |&lt;br /&gt;
| 9 * * | * * * | * * * |&lt;br /&gt;
| * 4 5 | * * * | * 9 6 |&lt;br /&gt;
&amp;nbsp;======= ======= =======&lt;br /&gt;
| 3 * * | * * * | 9 * * |&lt;br /&gt;
| * * * | * * 1 | * 6 5 |&lt;br /&gt;
| * 1 * | 3 6 * | * 7 4 |&lt;br /&gt;
&amp;nbsp;======= ======= =======&lt;br /&gt;
[status] solved=27 hints=486&lt;br /&gt;
&amp;nbsp;======= ======= =======&lt;br /&gt;
| 5 9 4 | 7 1 2 | 6 8 3 |&lt;br /&gt;
| 7 8 3 | 9 4 6 | 5 1 2 |&lt;br /&gt;
| 6 2 1 | 5 3 8 | 7 4 9 |&lt;br /&gt;
&amp;nbsp;======= ======= =======&lt;br /&gt;
| 1 6 2 | 8 5 9 | 4 3 7 |&lt;br /&gt;
| 9 3 7 | 6 2 4 | 1 5 8 |&lt;br /&gt;
| 8 4 5 | 1 7 3 | 2 9 6 |&lt;br /&gt;
&amp;nbsp;======= ======= =======&lt;br /&gt;
| 3 5 6 | 4 8 7 | 9 2 1 |&lt;br /&gt;
| 4 7 8 | 2 9 1 | 3 6 5 |&lt;br /&gt;
| 2 1 9 | 3 6 5 | 8 7 4 |&lt;br /&gt;
&amp;nbsp;======= ======= =======&lt;br /&gt;
[status] SOLVED&lt;br /&gt;
Time taken=2.198 ms&lt;br /&gt;
&lt;div style=&quot;min-height: 15px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;Solving a Sudoku puzzle of size 16 ...&lt;br /&gt;
&amp;nbsp;============= ============= ============= =============&lt;br /&gt;
| 8&amp;nbsp; 7&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; 3&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | 13 *&amp;nbsp; 4&amp;nbsp; *&amp;nbsp; |&lt;br /&gt;
| *&amp;nbsp; 5&amp;nbsp; 14 *&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; 3&amp;nbsp; 10 | 15 9&amp;nbsp; 1&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; 6&amp;nbsp; *&amp;nbsp; *&amp;nbsp; |&lt;br /&gt;
| 16 *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | 5&amp;nbsp; 8&amp;nbsp; 7&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; 14 *&amp;nbsp; *&amp;nbsp; | 9&amp;nbsp; *&amp;nbsp; 11 12 |&lt;br /&gt;
| *&amp;nbsp; *&amp;nbsp; 4&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; 14 6&amp;nbsp; 13 | *&amp;nbsp; 11 10 12 | *&amp;nbsp; 7&amp;nbsp; *&amp;nbsp; 3&amp;nbsp; |&lt;br /&gt;
&amp;nbsp;============= ============= ============= =============&lt;br /&gt;
| 14 *&amp;nbsp; *&amp;nbsp; 8&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; 1&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; 3&amp;nbsp; | 7&amp;nbsp; 4&amp;nbsp; 12 *&amp;nbsp; |&lt;br /&gt;
| 9&amp;nbsp; *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; 6&amp;nbsp; 15 12 | *&amp;nbsp; *&amp;nbsp; 13 14 | *&amp;nbsp; 3&amp;nbsp; 1&amp;nbsp; *&amp;nbsp; |&lt;br /&gt;
| 11 *&amp;nbsp; 10 3&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; 13 *&amp;nbsp; | *&amp;nbsp; 8&amp;nbsp; *&amp;nbsp; 1&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; 6&amp;nbsp; *&amp;nbsp; |&lt;br /&gt;
| 6&amp;nbsp; *&amp;nbsp; *&amp;nbsp; 1&amp;nbsp; | 14 *&amp;nbsp; 4&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; 5&amp;nbsp; *&amp;nbsp; 9&amp;nbsp; | 11 *&amp;nbsp; *&amp;nbsp; 13 |&lt;br /&gt;
&amp;nbsp;============= ============= ============= =============&lt;br /&gt;
| *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | 15 *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; 9&amp;nbsp; *&amp;nbsp; | 5&amp;nbsp; *&amp;nbsp; 2&amp;nbsp; 10 |&lt;br /&gt;
| 10 1&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | 6&amp;nbsp; *&amp;nbsp; 5&amp;nbsp; *&amp;nbsp; | 13 15 7&amp;nbsp; 16 | *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; |&lt;br /&gt;
| *&amp;nbsp; *&amp;nbsp; 16 11 | *&amp;nbsp; 4&amp;nbsp; *&amp;nbsp; 8&amp;nbsp; | 2&amp;nbsp; *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; 13 *&amp;nbsp; 7&amp;nbsp; |&lt;br /&gt;
| *&amp;nbsp; 9&amp;nbsp; *&amp;nbsp; 7&amp;nbsp; | 1&amp;nbsp; 3&amp;nbsp; *&amp;nbsp; 2&amp;nbsp; | 6&amp;nbsp; *&amp;nbsp; 8&amp;nbsp; 10 | 16 15 14 4&amp;nbsp; |&lt;br /&gt;
&amp;nbsp;============= ============= ============= =============&lt;br /&gt;
| 7&amp;nbsp; *&amp;nbsp; 13 *&amp;nbsp; | 9&amp;nbsp; 16 *&amp;nbsp; 5&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; 14 4&amp;nbsp; | 3&amp;nbsp; 8&amp;nbsp; *&amp;nbsp; 2&amp;nbsp; |&lt;br /&gt;
| *&amp;nbsp; *&amp;nbsp; 3&amp;nbsp; *&amp;nbsp; | 10 *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; 16 15 *&amp;nbsp; |&lt;br /&gt;
| 1&amp;nbsp; *&amp;nbsp; 9&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; 14 4&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; 7&amp;nbsp; *&amp;nbsp; |&lt;br /&gt;
| *&amp;nbsp; 6&amp;nbsp; 8&amp;nbsp; *&amp;nbsp; | 3&amp;nbsp; *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | 10 7&amp;nbsp; *&amp;nbsp; *&amp;nbsp; | *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; *&amp;nbsp; |&lt;br /&gt;
&amp;nbsp;============= ============= ============= =============&lt;br /&gt;
[status] solved=116 hints=2240&lt;br /&gt;
&amp;nbsp;============= ============= ============= =============&lt;br /&gt;
| 8&amp;nbsp; 7&amp;nbsp; 11 10 | 2&amp;nbsp; 12 9&amp;nbsp; 1&amp;nbsp; | 5&amp;nbsp; 3&amp;nbsp; 16 6&amp;nbsp; | 13 14 4&amp;nbsp; 15 |&lt;br /&gt;
| 12 5&amp;nbsp; 14 13 | 4&amp;nbsp; 11 3&amp;nbsp; 10 | 15 9&amp;nbsp; 1&amp;nbsp; 7&amp;nbsp; | 2&amp;nbsp; 6&amp;nbsp; 16 8&amp;nbsp; |&lt;br /&gt;
| 16 3&amp;nbsp; 1&amp;nbsp; 6&amp;nbsp; | 5&amp;nbsp; 8&amp;nbsp; 7&amp;nbsp; 15 | 4&amp;nbsp; 14 2&amp;nbsp; 13 | 9&amp;nbsp; 10 11 12 |&lt;br /&gt;
| 2&amp;nbsp; 15 4&amp;nbsp; 9&amp;nbsp; | 16 14 6&amp;nbsp; 13 | 8&amp;nbsp; 11 10 12 | 1&amp;nbsp; 7&amp;nbsp; 5&amp;nbsp; 3&amp;nbsp; |&lt;br /&gt;
&amp;nbsp;============= ============= ============= =============&lt;br /&gt;
| 14 13 15 8&amp;nbsp; | 11 2&amp;nbsp; 1&amp;nbsp; 9&amp;nbsp; | 16 10 6&amp;nbsp; 3&amp;nbsp; | 7&amp;nbsp; 4&amp;nbsp; 12 5&amp;nbsp; |&lt;br /&gt;
| 9&amp;nbsp; 4&amp;nbsp; 7&amp;nbsp; 5&amp;nbsp; | 8&amp;nbsp; 6&amp;nbsp; 15 12 | 11 2&amp;nbsp; 13 14 | 10 3&amp;nbsp; 1&amp;nbsp; 16 |&lt;br /&gt;
| 11 2&amp;nbsp; 10 3&amp;nbsp; | 7&amp;nbsp; 5&amp;nbsp; 13 16 | 12 8&amp;nbsp; 4&amp;nbsp; 1&amp;nbsp; | 15 9&amp;nbsp; 6&amp;nbsp; 14 |&lt;br /&gt;
| 6&amp;nbsp; 16 12 1&amp;nbsp; | 14 10 4&amp;nbsp; 3&amp;nbsp; | 7&amp;nbsp; 5&amp;nbsp; 15 9&amp;nbsp; | 11 2&amp;nbsp; 8&amp;nbsp; 13 |&lt;br /&gt;
&amp;nbsp;============= ============= ============= =============&lt;br /&gt;
| 3&amp;nbsp; 8&amp;nbsp; 6&amp;nbsp; 12 | 15 13 16 7&amp;nbsp; | 14 4&amp;nbsp; 9&amp;nbsp; 11 | 5&amp;nbsp; 1&amp;nbsp; 2&amp;nbsp; 10 |&lt;br /&gt;
| 10 1&amp;nbsp; 2&amp;nbsp; 4&amp;nbsp; | 6&amp;nbsp; 9&amp;nbsp; 5&amp;nbsp; 14 | 13 15 7&amp;nbsp; 16 | 8&amp;nbsp; 12 3&amp;nbsp; 11 |&lt;br /&gt;
| 15 14 16 11 | 12 4&amp;nbsp; 10 8&amp;nbsp; | 2&amp;nbsp; 1&amp;nbsp; 3&amp;nbsp; 5&amp;nbsp; | 6&amp;nbsp; 13 9&amp;nbsp; 7&amp;nbsp; |&lt;br /&gt;
| 13 9&amp;nbsp; 5&amp;nbsp; 7&amp;nbsp; | 1&amp;nbsp; 3&amp;nbsp; 11 2&amp;nbsp; | 6&amp;nbsp; 12 8&amp;nbsp; 10 | 16 15 14 4&amp;nbsp; |&lt;br /&gt;
&amp;nbsp;============= ============= ============= =============&lt;br /&gt;
| 7&amp;nbsp; 11 13 15 | 9&amp;nbsp; 16 12 5&amp;nbsp; | 1&amp;nbsp; 6&amp;nbsp; 14 4&amp;nbsp; | 3&amp;nbsp; 8&amp;nbsp; 10 2&amp;nbsp; |&lt;br /&gt;
| 5&amp;nbsp; 12 3&amp;nbsp; 14 | 10 7&amp;nbsp; 8&amp;nbsp; 6&amp;nbsp; | 9&amp;nbsp; 13 11 2&amp;nbsp; | 4&amp;nbsp; 16 15 1&amp;nbsp; |&lt;br /&gt;
| 1&amp;nbsp; 10 9&amp;nbsp; 2&amp;nbsp; | 13 15 14 4&amp;nbsp; | 3&amp;nbsp; 16 5&amp;nbsp; 8&amp;nbsp; | 12 11 7&amp;nbsp; 6&amp;nbsp; |&lt;br /&gt;
| 4&amp;nbsp; 6&amp;nbsp; 8&amp;nbsp; 16 | 3&amp;nbsp; 1&amp;nbsp; 2&amp;nbsp; 11 | 10 7&amp;nbsp; 12 15 | 14 5&amp;nbsp; 13 9&amp;nbsp; |&lt;br /&gt;
&amp;nbsp;============= ============= ============= =============&lt;br /&gt;
[status] SOLVED&lt;br /&gt;
Time taken=1.346 ms&lt;br /&gt;
&lt;div style=&quot;min-height: 15px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;Solving all puzzles from: ./src/sudoku/hardest.txt&lt;br /&gt;
Solved &amp;nbsp; &amp;nbsp; &amp;nbsp; :&amp;nbsp; 11/11&lt;br /&gt;
Solved Cells :&amp;nbsp; 270(input) 891(finally) 891(expected)&lt;br /&gt;
Cell Hints &amp;nbsp; :&amp;nbsp; 5589(input) 0(finally)&lt;br /&gt;
Time Taken &amp;nbsp; :&amp;nbsp; 2.59014144 milli-seconds&lt;br /&gt;
Avg time &amp;nbsp; &amp;nbsp; :&amp;nbsp; 0.23546740363636365 milli-seconds&lt;br /&gt;
&lt;div style=&quot;min-height: 15px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;Solving all puzzles from: ./src/sudoku/hard.txt&lt;br /&gt;
Solved &amp;nbsp; &amp;nbsp; &amp;nbsp; :&amp;nbsp; 95/95&lt;br /&gt;
Solved Cells :&amp;nbsp; 1953(input) 7695(finally) 7695(expected)&lt;br /&gt;
Cell Hints &amp;nbsp; :&amp;nbsp; 51678(input) 0(finally)&lt;br /&gt;
Time Taken &amp;nbsp; :&amp;nbsp; 41.772783616 milli-seconds&lt;br /&gt;
Avg time &amp;nbsp; &amp;nbsp; :&amp;nbsp; 0.4397135117473684 milli-seconds&lt;br /&gt;
&lt;div style=&quot;min-height: 15px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;Solving all puzzles from: ./src/sudoku/easy.txt&lt;br /&gt;
Solved &amp;nbsp; &amp;nbsp; &amp;nbsp; :&amp;nbsp; 50/50&lt;br /&gt;
Solved Cells :&amp;nbsp; 1418(input) 4050(finally) 4050(expected)&lt;br /&gt;
Cell Hints &amp;nbsp; :&amp;nbsp; 23688(input) 0(finally)&lt;br /&gt;
Time Taken &amp;nbsp; :&amp;nbsp; 1.868110848 milli-seconds&lt;br /&gt;
Avg time &amp;nbsp; &amp;nbsp; :&amp;nbsp; 0.03736221696 milli-seconds&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;A word of advice to readers. While building the Sudoku (or similar programs), you might be tempted to optimize it. I suggest its more important for the code to be readable and debuggable and concise. I tried to optimize my code, but realized its not worth it. Using some tricks i got speed up of 1ms for a specific alto, but that meant highly cryptic data structure. This would lead to increased timing in another algo and a nightmare to debug. Just do basic optimizations. As a side-effect of my attempt, i learnt few useful things to speed up the code in Java.&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;bytes is more expensive that int. So use int.&lt;/li&gt;
&lt;li&gt;int check (e.g. i==0) is very-very slightly faster than boolean check. But don&#39;t use it if it compromises readability.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Exception handling (even if exception is never thrown) is expensive.&lt;/li&gt;
&lt;li&gt;Java doesn&#39;t do tail call optimization. So don&#39;t worry too must about trying formatting your recursive routine.&lt;/li&gt;
&lt;li&gt;keyword final has no effect on performance in Java. So if you think a one liner function is inlined, its not.&lt;/li&gt;
&lt;li&gt;Avoid using array list and use fixed array. Even if array list is of size say k and array of n where k &amp;lt; n, its faster to use array. UNLESS k &amp;lt;&amp;lt;&amp;lt; n.&lt;/li&gt;
&lt;li&gt;Hashmap, Hashsets would easily hog performance. It can easily double the running time. So if you can avoid it, its better.&lt;/li&gt;
&lt;li&gt;1-d array is cheaper than 2-d array.&lt;/li&gt;
&lt;li&gt;Using objects is extremely cheap. I find next to nil penalty on using objects. So use them to simplify code.&lt;/li&gt;
&lt;li&gt;Caching can be useful. for example instead of referring A[i] several times, its faster to set x =A[i] and refer to x.&lt;/li&gt;
&lt;li&gt;private, public, and other qualifies only increase space of byte code but has no performance impact. So use them for good design principles and not for performance improvements.&lt;/li&gt;
&lt;/ol&gt;Code is available at &lt;a href=&quot;https://github.com/n1balgo/sudoku&quot;&gt;https://github.com/n1balgo/sudoku&lt;/a&gt;. Feel free to check it out and drop in comments or email for feedback (and suggestions and bugs).</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/3296655272595836605/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2014/07/solving-sudoku-puzzles.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/3296655272595836605'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/3296655272595836605'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2014/07/solving-sudoku-puzzles.html' title='Solving Sudoku Puzzles'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>San Francisco, CA, USA</georss:featurename><georss:point>37.7749295 -122.41941550000001</georss:point><georss:box>37.373502 -123.06486250000002 38.176356999999996 -121.77396850000001</georss:box></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-6438268924894412212</id><published>2014-05-02T15:45:00.000-07:00</published><updated>2014-05-02T22:16:55.041-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="maths"/><title type='text'>Stick Breaking</title><content type='html'>&lt;b&gt;Problem Set 1&lt;/b&gt;: Given a stick of length 1 meter. It is cut into two parts randomly.
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Problem 1a: What is the expected length of the smaller stick?&lt;/li&gt;
&lt;li&gt;Problem 1b: What is the expected length of the bigger stick?&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;b&gt;Problem Set 2&lt;/b&gt;: Given a stick of length 1 meter. It is cut into three parts randomly.
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Problem 2a: What is the expected length of the smallest stick?&lt;/li&gt;
&lt;li&gt;Problem 2b: What is the expected length of the largest stick?&lt;/li&gt;
&lt;li&gt;Problem 2c: What is the expected length of the stick with second smallest (or second largest) length?&lt;/li&gt;
&lt;li&gt;Problem 2d: What is the expected length of the middle stick (stick that is between the two cuts)?&lt;/li&gt;
&lt;li&gt;Problem 2e: What is the probability that the three sticks would form a triangle?&lt;/li&gt;
&lt;li&gt;Problem 2f: What is the probability that the three sticks would form a right angle triangle?&lt;/li&gt;
&lt;li&gt;Problem 2g: What is the probability that the three sticks would form an equilateral triangle?&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;b&gt;Problem Set 3&lt;/b&gt;: Given a stick of length 1 meter. It is cut into two parts randomly. Then bigger stick is picked and is again cut into two parts randomly.
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Problem 3a: What is the expected length of the smallest stick?&lt;/li&gt;
&lt;li&gt;Problem 3b: What is the expected length of the largest stick?&lt;/li&gt;
&lt;li&gt;Problem 3c: What is the expected length of the stick with second smallest (or second largest) length?&lt;/li&gt;
&lt;li&gt;Problem 3d: What is the expected length of the middle stick (stick that is between the two cuts)?&lt;/li&gt;
&lt;li&gt;Problem 3e: What is the probability that the three sticks would form a triangle?&lt;/li&gt;
&lt;li&gt;Problem 3f: What is the probability that the three sticks would form a right angle triangle?&lt;/li&gt;
&lt;li&gt;Problem 3g: What is the probability that the three sticks would form an equilateral triangle?&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;b&gt;Generalized Cut Problem&lt;/b&gt;: Find the solution to problem 2a-2c, 3a-3c for n-1 cuts.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Solution&lt;/b&gt;: &lt;a href=&quot;https://www.blogger.com/blogger.g?blogID=759530137113893554#&quot; id=&quot;sb050214_a&quot; onclick=&quot;return toggleMenuAdi(&#39;sb050214_a&#39;,&#39;sb050214_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;sb050214_s&quot; style=&quot;display: none;&quot;&gt;
Solution for problem 1: 1/4 (1a), 3/4 (1b) &lt;br /&gt;
Solution for problem 2: 1/9 (2a), 11/18 (2b), 5/18 (2c), 1/3 (2d), 1/4 (2e), 0 (2f), 0 (2g) &lt;br /&gt;
Solution for problem 3: 15/16 - 2log(3/2) (3a), … &lt;br /&gt;
&lt;br /&gt;
Let us work out solution for 1a. Smaller stick has length x which is uniformly distributed in the range [0,0.5]. The probability distribution of x is p(x) = 1 / [1/2-0] = 2. Yes it is a pdf, ∫ &lt;sub&gt;0&lt;/sub&gt;&lt;sup style=&quot;left: -.5em; position: relative;&quot;&gt;0.5&lt;/sup&gt;p(x)dx = 1. The expected length of the smaller stick is E[x] = ∫ x p(x) dx = ∫ &lt;sub&gt;0&lt;/sub&gt;&lt;sup style=&quot;left: -.5em; position: relative;&quot;&gt;0.5&lt;/sup&gt;2xdx = 1/4.&lt;br /&gt;
&lt;br /&gt;
2a) Let us work out solution for 2a. Let two cuts are at distance x,y from one end. Let x &amp;lt; y. So the three sticks are of length x, y-x, 1-y. Let z = min(x,y-x,1-y) represent the minimum length of the stick. Let Pr(z&amp;gt;a) indicate the probability that min length stick has length greater than a.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Pr(z&amp;gt;a) = 2 * Pr(x&amp;gt;a, y-x&amp;gt;a, 1-y&amp;gt;a) = Pr(x&amp;gt;a, a+x &amp;lt; y &amp;lt; 1-a)&lt;br /&gt;
&lt;br /&gt;
Note multiplication by 2 is for the other case (x &amp;gt; y). Since a+x&amp;lt; y &amp;lt; 1-a, we get x &amp;lt; 1-2a. Also setting x =a, we get a &amp;lt; 1/3 (which is obvious).&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Pr(z &amp;gt; a) = 2 ∫ &lt;sub&gt;a&lt;/sub&gt;&lt;sup style=&quot;left: -0.5em; position: relative;&quot;&gt;1-2a&lt;/sup&gt; ∫ &lt;sub&gt;a+x&lt;/sub&gt;&lt;sup style=&quot;left: -1.5em; position: relative;&quot;&gt;1-a&lt;/sup&gt;dxdy = (1-3a)&lt;sup&gt;2&lt;/sup&gt;.
&lt;br /&gt;
&lt;br /&gt;
So we get Pr(z&amp;lt;=a) = 1-Pr(z&amp;gt;a). And Pr(z=a) = derivative of Pr(z&amp;lt;=a) at a = 6(1-3a).&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; E[a] = &amp;nbsp;∫ &lt;sub&gt;0&lt;/sub&gt;&lt;sup style=&quot;left: -0.5em; position: relative;&quot;&gt;1/3&lt;/sup&gt;6a(1-3a)da = 1/9&lt;br /&gt;
&lt;br /&gt;
2b) We can do a similar derivation for z = max(x,y-x,1-y) to get the expected max length. It would be slightly more complicated. Unlike above, we compute here Pr(z&amp;lt; a)&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Pr(z &amp;lt; a) = Pr(x &amp;lt; a, y-x &amp;lt; a, 1-y &amp;lt; a) = Pr( 1-2a &amp;lt; x &amp;lt; a, 1-a &amp;lt; y &amp;lt; x + a).&lt;br /&gt;
&lt;br /&gt;
We need to be careful here are respect constraints like x &amp;gt; 0, x &amp;lt; y, y &amp;lt; 1. To ensure these constraints are respected. Pr(z &amp;lt; a) is broken into three cases, Case 1: a &amp;lt; 1/2. Case 2: a &amp;gt;= 1/2, 0 &amp;lt; x &amp;lt; 1-a, Case 3: &amp;nbsp;a &amp;gt;= 1/2, 1-a &amp;lt; x &amp;lt; a. Then we have to take differential of obtained Pr(z &amp;lt; a) to get Pr(z=a). [Dont mix terms from the three cases].&lt;br /&gt;
&lt;br /&gt;
Integrate the first case from [1/3 to 1/2]. Second and third case from [1/2 to 1]. We will see the desired output as 1/2+1/9=11/18. (Don&#39;t forget to multiply by 2 to cover for x &amp;gt; y case).&lt;br /&gt;
&lt;br /&gt;
2c) It would be easy to obtain: 1 - (2a) - (2b) = 1 - 1/9 -&amp;nbsp;1/2 - 1/9 = 1/2 - 2/9 = 5/18.&lt;br /&gt;
&lt;br /&gt;
2d) Since there are no constraints, expected length of middle cut is 1/3&lt;br /&gt;
&lt;br /&gt;
2e) For triangle, we require satisfaction of three inequalities&lt;br /&gt;
&amp;nbsp;x + y - x &amp;gt; 1-y,&lt;br /&gt;
&amp;nbsp;x&amp;nbsp;+ 1- y &amp;gt; y - x,&lt;br /&gt;
&amp;nbsp;y - x&amp;nbsp;+ 1 - y &amp;gt; x&lt;br /&gt;
Apart from the implicit x &amp;lt; y inequality.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; 1/2 &amp;lt; y &amp;lt; x&amp;nbsp;+ 1/2, x &amp;lt; 1/2&lt;br /&gt;
&lt;br /&gt;
So x follows a pdf of P(x) = 2. y satisfied the range with probability x. So the probability of triangle formation is &amp;nbsp;∫&amp;nbsp;&lt;sub&gt;0&lt;/sub&gt;&lt;sup style=&quot;left: -0.5em; position: relative;&quot;&gt;1/2&lt;/sup&gt;2 x dx = 1/4.&lt;br /&gt;
&lt;br /&gt;
2f) There are discrete stick lengths, e.g. (3/12, 4/12, 5/12) that satisfy this property. There are countably infinite, yet the area encapsulated by them is 0.&lt;br /&gt;
&lt;br /&gt;
Problem set 3 is slightly more complicated. Let us work out 3a).&lt;br /&gt;
&lt;br /&gt;
Let the first cut is at length x from shorter side (x &amp;lt; 1/2). Now from the stick of length (1-x), we make a cut at random of length y. Let y &amp;lt; (1-x)/2. If x is the shortest stick then x &amp;lt; y =&amp;gt; x &amp;lt; 1/3.&lt;br /&gt;
&lt;br /&gt;
Case 1: 1/3 &amp;lt; x &amp;lt; 1/2, 0 &amp;lt; y &amp;lt; (1-x)/2 =&amp;gt; y is the shortest stick&lt;br /&gt;
&lt;br /&gt;
Case 2: 0 &amp;lt; x &amp;lt; 1/3&lt;br /&gt;
&amp;nbsp; &amp;nbsp; Case 2a: 0 &amp;lt; y &amp;lt; x =&amp;gt; y is the shortest stick&lt;br /&gt;
&amp;nbsp; &amp;nbsp; Case 2b: x &amp;lt; y &amp;lt; (1-x)/2 =&amp;gt; x is the shortest stick&lt;br /&gt;
&lt;br /&gt;
We also note that P(x) = 2 (a uniform distribution in [0,1/2]), P(y) = 2/(1-x) (a uniform distribution in [0, (1-x)/2]).&lt;br /&gt;
&lt;br /&gt;
So the Expected min length = ∫ &lt;sub&gt;1/3&lt;/sub&gt;&lt;sup style=&quot;left: -1.3em; position: relative;&quot;&gt;1/2&lt;/sup&gt; ∫ &lt;sub&gt;0&lt;/sub&gt;&lt;sup style=&quot;left: -0.5em; position: relative;&quot;&gt;(1-x)/2&lt;/sup&gt; 4y/(1-x) dx dy + ∫ &lt;sub&gt;0&lt;/sub&gt;&lt;sup style=&quot;left: -0.5em; position: relative;&quot;&gt;1/3&lt;/sup&gt; ∫ &lt;sub&gt;0&lt;/sub&gt;&lt;sup style=&quot;left: -0.5em; position: relative;&quot;&gt;x&lt;/sup&gt; 4y/(1-x) dx dy + &lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;∫ &lt;sub&gt;0&lt;/sub&gt;&lt;sup style=&quot;left: -0.5em; position: relative;&quot;&gt;1/3&lt;/sup&gt;∫&amp;nbsp;&lt;sub&gt;x&lt;/sub&gt;&lt;sup style=&quot;left: -0.5em; position: relative;&quot;&gt;(1-x)/2&lt;/sup&gt;4x/(1-x) dx dy = 15/16 - 2 log(3/2)&lt;br /&gt;
&lt;br /&gt;
For Generalized problem read &lt;a href=&quot;http://books.google.com/books?id=bdhzFXg6xFkC&amp;amp;printsec=frontcover&amp;amp;dq=david+and+nagaraja+order+statistics&amp;amp;source=bl&amp;amp;ots=OaK_k-BbTf&amp;amp;sig=vAtEAURNfZTe3NDV9WodQZ-3ip4&amp;amp;hl=en&amp;amp;ei=DfsDTdiXPML88AafsKnqAg&amp;amp;sa=X&amp;amp;oi=book_result&amp;amp;ct=result&amp;amp;resnum=1&amp;amp;ved=0CBgQ6AEwAA#v=onepage&amp;amp;q&amp;amp;f=false&quot;&gt;David and Nagaraja&#39;s Order Statistics (pp. 133-135, and p. 153)&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
The solutions through Monte-Carlo simulations. Following python code solves problem set 2 and 3. 

&lt;br /&gt;
&lt;pre&gt;from random import random
def prob2():
    niter = 100000
    n, ntri, nrtri = 0.0, 0, 0
    lsmall, llarge, lmid, lcenter = 0, 0, 0, 0

    while n &amp;lt; niter:
        n += 1
        p = random()
        q = random()
        x = min(p, q)
        y = max(p, q)

        l1 = x
        l2 = y-x
        l3 = 1-y

        mn = min(l1, l2, l3)
        mx = max(l1, l2, l3)
        md = 1 - mn - mx
        lsmall += mn
        llarge += mx
        lmid += md
        lcenter += y

        if l1 + l2 &amp;gt; l3 and l1 + l3 &amp;gt; l2 and l2 + l3 &amp;gt; l1:
            ntri += 1

        if mn**2 + md**2 == mx**2:
            nrtri += 1

    print &#39;min len:&#39;, lsmall/n
    print &#39;max len:&#39;, llarge/n
    print &#39;mid len:&#39;, lmid/n
    print &#39;center stick len&#39;, lcenter/n
    print &#39;triangle prob:&#39;, ntri/float(n)
    print &#39;right triangle prob:&#39;, nrtri/float(n)

def prob3():
    niter = 100000
    n, ntri, nrtri = 0.0, 0, 0
    lsmall, llarge, lmid, lcenter = 0, 0, 0, 0

    while n &lt; niter:
        n += 1
        p = random()
        q = random()

        l1 = 0.5 * (1-p)
        l2 = 0.25 * (1+p) * (1-q)
        l3 = 0.25 * (1+p) * (1+q)

        mn = min(l1, l2, l3)
        mx = max(l1, l2, l3)
        md = 1 - mn - mx
        lsmall += mn
        llarge += mx
        lmid += md
        lcenter += (l2+l3)/2

        if l1 + l2 &gt; l3 and l1 + l3 &gt; l2 and l2 + l3 &gt; l1:
            ntri += 1

        if mn**2 + md**2 == mx**2:
            nrtri += 1

    print &#39;min len:&#39;, lsmall/n
    print &#39;max len:&#39;, llarge/n
    print &#39;mid len:&#39;, lmid/n
    print &#39;center stick len&#39;, lcenter/n
    print &#39;triangle prob:&#39;, ntri/float(n)
    print &#39;right triangle prob:&#39;, nrtri/float(n)
&lt;/pre&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/6438268924894412212/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2013/12/stick-breaking.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/6438268924894412212'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/6438268924894412212'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2013/12/stick-breaking.html' title='Stick Breaking'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-798808824644047369</id><published>2014-05-01T13:59:00.000-07:00</published><updated>2014-05-02T14:43:10.696-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="puzzle"/><title type='text'>Defective Balls</title><content type='html'>For problem 1-3 consider a weighing scale (with two sides) and it only tells which side is heavier (it doesnt tell by how much). &lt;br /&gt;&lt;br /&gt;

&lt;b&gt;Problem 1&lt;/b&gt;: You have 9 balls of same weight, except that 1 ball is defective and it is known to be lighter. Find the defective ball in two weighing. &lt;br /&gt;&lt;br /&gt;

&lt;b&gt;Problem 2&lt;/b&gt;: You have 9 balls of same weight, except that 1 ball is defective (it can be heavier or lighter, we dont know). Find the defective ball in three weighing. &lt;br /&gt;&lt;br /&gt;

&lt;b&gt;Problem 3&lt;/b&gt;: You have 9 balls of same weight, except that 2 balls are defective and they are known to be lighter. Find the defective balls in four weighing. &lt;br /&gt;&lt;br /&gt;

&lt;b&gt;Problem 4&lt;/b&gt;: There are 9 machines that produce the balls. You get 9 balls from each machine during a production cycle. You are given a weighing scale that gives the exact weight. You are told that one machine produced defective balls in a given production cycle. Find the defective machine through a single weight measurement. Assume that a perfect ball weight 1lbs and defective ball weight 1.1lbs. &lt;br /&gt;&lt;br /&gt;

&lt;b&gt;Problem 5&lt;/b&gt;: Consider problem 4. Now assume that the weight of the defective ball is unknown. Now find the defective machine in two weighing. &lt;br /&gt;&lt;br /&gt;

&lt;b&gt;Problem 6&lt;/b&gt;: There are two jars A and B. A contains 50 perfect balls and B contains 50 defective balls. Arrange the 100 balls in the two jars in a way that the probability of randomly picking a ball (by first randomly picking a jar) is maximized. &lt;br /&gt;&lt;br /&gt;

&lt;b&gt;Solution&lt;/b&gt;: &lt;a href=&quot;#&quot; id=&quot;dc050114_a&quot; onclick=&quot;return toggleMenuAdi(&#39;dc050114_a&#39;,&#39;dc050114_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;dc050114_s&quot; style=&quot;display: none;&quot;&gt;
For the problems 1-3, divide the 9 balls into 3 groups of 3 balls each. &lt;br /&gt;&lt;br /&gt;

Problem1: Weight group1 and group2. If they are same weight, defective ball is in group3. Pick two balls from group3 and weight them. If they weight same, then the ball left out (from group3) is defective. All other cases are also easy to see. &lt;br /&gt;&lt;br /&gt;

Problem2: Weight group1 and group2. Then weigh group2 and group3. After these two weighing you would know the group containing the defective ball as well as whether that ball is heavy or light. Then simply pick two balls from the identified group and weight them. &lt;br /&gt;&lt;br /&gt;

Problem3: This problem has two cases: Case1: One group contains both the defective balls or Case2: Two groups contains one defective ball. Weight group1 and group2. Then weight group2 and group3. After these two weighing you would know whether we have case1 or case2 and also the groups containing the defective balls would be known. Case1 is now easy to solve. Consider case2. Say group1 and group2 contain one defective ball. We can easily find the defective ball in the two groups INDEPENDENTLY in one weighing each (hence 4 weighing). &lt;br /&gt;&lt;br /&gt;

Problem 4: Let defective machine is x. Pick 1 ball from machine 1, 2 from machine 2, and so on. Total wt would be n*(n+1)/2 + x(.1). Solve for x. &lt;br /&gt;&lt;br /&gt;

Problem 5: Form two equations. Let defective ball has wt = y. First pick 1 ball from machine 1, 2 from machine 2, and so on. We get equation: &lt;br /&gt;
 n*(n+1)/2 - x(1-y) = A &lt;br /&gt;&lt;br /&gt;

Next pick 1 ball from machine 9, 2 from machine 8, and so on. We get equation: &lt;br /&gt;
 n*(n+1)/2 - (n-x+1)(1-y) = B &lt;br /&gt;&lt;br /&gt;

We have two equations and two variables. We get x = a(n+1)/(a+b), where a = n(n+1)/2-A and b = n(n+1)/2-B.&lt;br /&gt;&lt;br /&gt;

Problem 6. Leave one perfect ball in Jar A and put rest in Jar B. The probability of picking the perfect ball is now 1/2 + 49/99. This is clearly the best we can do. &lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/798808824644047369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2014/05/defective-cubes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/798808824644047369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/798808824644047369'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2014/05/defective-cubes.html' title='Defective Balls'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-2868390602328391174</id><published>2013-12-09T16:40:00.000-08:00</published><updated>2014-05-01T15:30:54.114-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>Palindrome Numbers</title><content type='html'>&lt;b&gt;Problem 1&lt;/b&gt;: Given a number n, check whether it is a palindrome or not. For e.g., n = 303 is a palindrome, where as n = 302 is not. Give an O(log n) algorithm. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Problem 2&lt;/b&gt;: Given a number n, find the largest palindrome that is less than or equal to n. For e.g., n = 36, then 33 is the largest palindrome less than or equal to n. Give an O(log n) algorithm. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Problem 3&lt;/b&gt;: Given a number n, find all the palindrome less than or equal to n. Give an efficient O(k) algorithm, where k = number of palindromes less than n. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Problem 4&lt;/b&gt;: Prove that all palindromes with even length is divisible by 11. For e.x. 6996 is divisible by 11. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Problem 5&lt;/b&gt;: Consider a palindrome number generator as follows.&lt;br /&gt;
&lt;br /&gt;
Step 1: n = n + reverse(n)&lt;br /&gt;
Step 2: If !is_palindrome(n): Goto Step 1&lt;br /&gt;
&lt;br /&gt;
Given a palindrome number m, find the smallest n which can generate m using this generator. Is it possible that no such n exist?&lt;br /&gt;
&lt;br /&gt;
For e.g., m = 121, we get n = 19. To see this, we get, n1 = 19+91 = 110. In the next step we get n2 = 110 + 011 = 121.</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/2868390602328391174/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2013/12/palindrome-numbers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/2868390602328391174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/2868390602328391174'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2013/12/palindrome-numbers.html' title='Palindrome Numbers'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-796439494126931000</id><published>2013-12-01T19:54:00.007-08:00</published><updated>2013-12-23T13:01:52.564-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>Finding Relevant Keywords from Large Corpus of Text </title><content type='html'>&lt;b&gt;Problem 1&lt;/b&gt;: Given a large paragraph of words containing n words (separated by space), and k keywords. Find the smallest distance between these keywords in the paragraph. &lt;br /&gt;
&lt;br /&gt;
To illustrate the problem, consider that the paragraph is A B A C E D O A B. Let us say that we are interested in two keywords A and D. Then the closest they appear is at position 8 and 6 (D O A) and the minimum distance is 1 (i.e. number of non-keyword words between them). &lt;br /&gt;
&lt;br /&gt;
Build an efficient algorithm with O(k) space and O(n log k) running cost. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Solution&lt;/b&gt;: &lt;a href=&quot;http://www.blogger.com/blogger.g?blogID=759530137113893554#&quot; id=&quot;frklct1213_a&quot; onclick=&quot;return toggleMenuAdi(&#39;frklct1213_a&#39;,&#39;frklct1213_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;frklct1213_s&quot; style=&quot;display: none;&quot;&gt;To solve this problem, we need to register the last seen position of each of k keywords, as we read the paragraph word-by-word. If the next word, and if that matches a keyword, we need to update the last seen position of the matching keyword and also compute the minimum of the position register. That helps us find the smallest distance. &lt;br /&gt;
&lt;br /&gt;
In order to implement this efficiently, we need a hash map and min heap (tree based implementation, not array based). Following is the code to solve this problem. &lt;br /&gt;
&lt;pre&gt;Let K[i] indicate ith keyword.
Let W[i] indicate ith word in the paragraph. 

// init map and heap
map = {}
heap = []
for i in 1 to k

  // init heap with -Inf as position of the keyword
  node = heap_node()
  node.val = -Inf

  // map stores the keyword and its pointer to node in the heap
  heap.put(node)
  map.put(K[i], node)
end

idx_start = 0
idx_end = 0
min_dist = Inf
for i in 1 to n
  w = W[i]

  // check if w is one of the keywords, if not ignore
  if !map.contains_key(w)
    continue
  end

  // get the heap node corresponding to the
  // key W[i] and update its position
  node = map.get(w)
  node.val = i

  // re-heapify the min heap
  heap.heapify()

  // min of all positions
  idx = heap.min()

  // if idx = -Inf then some keywords are not seen yet.
  if idx == -Inf
    continue
  end

  // compute distance between keywords
  dist = i - idx - k + 1
  if dist &lt; min_dist
    idx_start = idx
    idx_end = i
    min_dist = dist
  end 
end
&lt;/pre&gt;
The above algorithm requires O(k) memory for the map and the heap. For each word, it requires O(log k) to re-heapify the min heap. &lt;/div&gt;&lt;br /&gt;

&lt;b&gt;Problem 2&lt;/b&gt;: Given a large paragraph of words (separated by space). Consider N tuples of names and interests. If a given person and their interest appears within K words then its a match else not. Find all matches from the paragraph. &lt;br /&gt;
&lt;br /&gt;
To illustrate the problem, consider that the paragraph is &quot;John likes swimming and Jack likes Tennis&quot;. Let the interest map is &amp;lt;john swimming&amp;gt;, &amp;lt;john tennis&amp;gt;, &amp;lt;jack swimming&amp;gt;, &amp;lt;jack tennis&amp;gt;. For k = 3, 4, 5, 6 the matches found in the paragraph are &amp;lt;john swimming&amp;gt;, &amp;lt;jack swimming&amp;gt;, &amp;lt;jack tennis&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Propose an efficient algorithm for two cases: k is small, k is very large. </content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/796439494126931000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2013/12/finding-relevant-keywords-from-large.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/796439494126931000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/796439494126931000'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2013/12/finding-relevant-keywords-from-large.html' title='Finding Relevant Keywords from Large Corpus of Text '/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-1538252664247327061</id><published>2012-08-12T18:36:00.000-07:00</published><updated>2012-08-12T19:30:38.340-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="puzzle"/><title type='text'>Bulls and Cows</title><content type='html'>&lt;a href=&quot;http://en.wikipedia.org/wiki/Bulls_and_cows&quot;&gt;Bulls and Cows&lt;/a&gt; is a two player game. First player thinks of a N digit secret number and second player guesses that number. This is done by second player making a guess and first player telling the number of bulls and cows in the guess. If the digits of guess matches secret and they are in right position, it&#39;s a bull, if they match but on different position, they are cows. For e.g. Let secret be 0123 and guess be 0012. The guess has 1 bull, 2 cows. The game continues, until second player gets a response of N bulls.&lt;br /&gt;
&lt;br /&gt;
The problem is to write a computer solver for bulls and cows that would try to guess the secret making only a small number of attempts.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Solution&lt;/b&gt;: &lt;a href=&quot;#&quot; id=&quot;bc0812_a&quot; onclick=&quot;return toggleMenuAdi(&#39;bc0812_a&#39;,&#39;bc0812_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;bc0812_s&quot; style=&quot;display: none;&quot;&gt;Let D be the unique digits that can be put in the secret. Let N be the length of the secret number. The total number of secrets is D^N.&lt;br /&gt;
&lt;br /&gt;
A naive solution is to try all D^N guesses until N bulls is the response. This approach makes D^N attempts in worst case. Not good.&lt;br /&gt;
&lt;br /&gt;
We can do better than this. Let us make a random first guess and we get a response r. We create a pruned set by selecting all numbers (from D^N possible) that have response r with the guess. Secret must be in the pruned set. We can pick a number from this set as our guess and repeat the logic until we hear N bulls.&lt;br /&gt;
&lt;br /&gt;
There are three ways to pick the next number&lt;br /&gt;
a) Pick the first number from the pruned set&lt;br /&gt;
b) Pick the number randomly from the pruned set&lt;br /&gt;
c) Use a heuristic to pick a number (Note this number can be outside the pruned set).&lt;br /&gt;
&lt;br /&gt;
Our experiments show that b) is better than a). For N = 4, D = 10 with distinct digits in secret (5040 possible secrets) and initial guess of 0123, the pick first strategy makes 6.0051 attempts on average and 9 attempts in a worst case. On the other hand, randomly picking from the pruned set makes 5.9136 attempts on average and 9 attempts in a worst case.&lt;br /&gt;
&lt;br /&gt;
Note that optimal strategy for N=4, D=10 with distinct digits in secret (5040 possible secrets) takes an average of 5.2131 attempts with 7 attempts in the worst case (&lt;a href=&quot;http://www.jfwaf.com/Bulls%20and%20Cows.pdf&quot;&gt;technical paper&lt;/a&gt;). It is also guaranteed that 6 attempts is the worst case lower bound for any algorithm. Since 5.2131 is theoretical best, 5.9136 achieved by random is not bad.&lt;br /&gt;
&lt;br /&gt;
Let us now explore option c. There are (N+1)*(N+2)/2 - 1 response classes starting from (0 bulls, 0 cows) to (N bulls, 0 cows). Note the -1 is there because if the response is N-1 bulls then we cannot have 1 cow. The response to a guess, partitions the D^N numbers (as shown in Fig 1).&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeMjUvlHNrhWl0EQB76vOwoMi9GiIVdiQBS7tbNUCRFNZiHN73RD0Zta3iZpmlPUu3LRDy6BVD_XHYmZhglJz9p2VfHKrtsVrxub5ncg0BdooO9pdvOET1zALVcma9DAyTcMgQ1aKx_q4/s1600/responsedist.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;270&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeMjUvlHNrhWl0EQB76vOwoMi9GiIVdiQBS7tbNUCRFNZiHN73RD0Zta3iZpmlPUu3LRDy6BVD_XHYmZhglJz9p2VfHKrtsVrxub5ncg0BdooO9pdvOET1zALVcma9DAyTcMgQ1aKx_q4/s400/responsedist.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Fig 1. Response partition of 10^4 numbers for the secret 0123&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
Now we know that the secret lies in the pruned set. We need to pick our next guess that partitions the pruned set in the best possible manner. One way to judge the goodness of partition is by information gain [sum_i ni * log (ni)]. The issue now is that to compute information gain, we need to compute responses for D^N * length(pruned set) pairs.&lt;br /&gt;
&lt;br /&gt;
Note that the best guess can be outside the pruned set, that is why we need to compute D^N * length(pruned set) responses and not length(pruned set)^2. To see this consider that pruned set is [089, 189, 289, 389, 489, 589, 689, 789]. If our secret is 789 we need 8 guesses but if we try 012 as guess 1 then we get pruned set [389, 489, 589, 689, 789], then we try 345 as our guess 2 to get a pruned set [689, 789] and now two more guesses are required. So we solved it in 4 attempts instead of 8.&lt;br /&gt;
&lt;br /&gt;
But the bigger issues is that this technique can only be applied if length of pruned set is small, otherwise it can be computationally prohibitive and memory intensive. Our strategy is as follows:&lt;br /&gt;
&lt;pre&gt;step 1. Pick distinct digits to make first guess.
step 2. Select random guess from the pruned set.
step 3. Perform step 2, three or four times.
step 4. Pick guess using information gain measure.
step 5. Perform step 4, until game is solved.&lt;/pre&gt;For N = 4, D = 10, (5040 possible secrets), this strategy makes 5.7201 attempts on average with 8 attempts in a worst case. Summary of algorithms is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;table border=1&gt;&lt;tr&gt;&lt;td colspan=3&gt;D=10, N=4, 5040 secrets&lt;/td&gt;
&lt;tr&gt;&lt;th&gt;algo&lt;/th&gt;&lt;th&gt;average #attempts&lt;/th&gt;&lt;th&gt;worst #attempts&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;pick first&lt;/td&gt;&lt;td&gt;6.0051&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;pick random&lt;/td&gt;&lt;td&gt;5.9136&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;heuristic pick&lt;/td&gt;&lt;td&gt;5.7201&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;optimal&lt;/td&gt;&lt;td&gt;5.2131&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
&lt;table border=1&gt;&lt;tr&gt;&lt;td colspan=3&gt;D=10, N=4, 10000 secrets&lt;/td&gt;
&lt;tr&gt;&lt;th&gt;algo&lt;/th&gt;&lt;th&gt;average #attempts&lt;/th&gt;&lt;th&gt;worst #attempts&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;pick first&lt;/td&gt;&lt;td&gt;8.0291&lt;/td&gt;&lt;td&gt;13&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;pick random&lt;/td&gt;&lt;td&gt;6.6323&lt;/td&gt;&lt;td&gt;11&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;heuristic pick&lt;/td&gt;&lt;td&gt;6.2001&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Source code: &lt;a href=&quot;https://github.com/n1balgo/algo/blob/master/bulls_cows.py&quot;&gt;bullscows.py&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Technical resources: &lt;a href=&quot;http://www.jfwaf.com/Bulls%20and%20Cows.pdf&quot;&gt;optimal strategy&lt;/a&gt;, &lt;a href=&quot;http://bulls-cows.sourceforge.net/bullscows.pdf&quot;&gt;bullscows.pdf&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/1538252664247327061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2012/08/bulls-and-cows.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/1538252664247327061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/1538252664247327061'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2012/08/bulls-and-cows.html' title='Bulls and Cows'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeMjUvlHNrhWl0EQB76vOwoMi9GiIVdiQBS7tbNUCRFNZiHN73RD0Zta3iZpmlPUu3LRDy6BVD_XHYmZhglJz9p2VfHKrtsVrxub5ncg0BdooO9pdvOET1zALVcma9DAyTcMgQ1aKx_q4/s72-c/responsedist.jpg" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-2599729749123069410</id><published>2012-07-21T14:51:00.001-07:00</published><updated>2014-05-01T14:04:01.981-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="maths"/><category scheme="http://www.blogger.com/atom/ns#" term="probability"/><category scheme="http://www.blogger.com/atom/ns#" term="puzzle"/><title type='text'>Number of Paths in a Rectangular Grid</title><content type='html'>&lt;b&gt;Problem 1&lt;/b&gt;: Consider a rectangular grid of n x m rectangular cells. The problem is to find the number of shortest (or monotonic in this case) paths along the edges of the cell that start at (0,0) and end at (n,m). How do we print all such paths? &lt;br /&gt;
&lt;br /&gt;
A monotonic path consists of moving up or right but not down or left. Figure 1 illustrates such a path for a grid of size 5 x 3.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDbfEmEj5r28pMcVUOnHMh08Kqbnhnb6TQvAYqc2UEa6D2WFI2QHAus_-E4McfR69RMbeERo4NsHvvjUwDglB_N9pLZl0NBZos82q-NIuPLZ_I92yqeyT4kJ7i3D3iij86rYYLUOd9C3k/s1600/grid.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDbfEmEj5r28pMcVUOnHMh08Kqbnhnb6TQvAYqc2UEa6D2WFI2QHAus_-E4McfR69RMbeERo4NsHvvjUwDglB_N9pLZl0NBZos82q-NIuPLZ_I92yqeyT4kJ7i3D3iij86rYYLUOd9C3k/s320/grid.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 1&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;b&gt;Solution&lt;/b&gt;: &lt;a href=&quot;#&quot; id=&quot;nprg2112_a&quot; onclick=&quot;return toggleMenuAdi(&#39;nprg2112_a&#39;,&#39;nprg2112_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;nprg2112_s&quot; style=&quot;display: none;&quot;&gt;To go from (0,0) to (n,m), we need to make n moves to the right and m moves up. These moves can be performed in any order and still we reach the point (n,m). So the total number of ways is simply the total number of ways n red balls and m green balls can be arranged in a straight line. This is simply &lt;sup&gt;n+m&lt;/sup&gt;C&lt;sub&gt;m&lt;/sub&gt;.&lt;br /&gt;
&lt;br /&gt;
We can print all such paths using recursion. The following code does this. &lt;br /&gt;
&lt;pre&gt;Function printPath(n, m, path)
   if n == 0 and m == 0
      print path
      return
   end

   if n &amp;gt; 0
      printPath(n-1, m, path + &quot;right&quot;)
   end

   if m &amp;gt; 0
      printPath(n, m-1, path + &quot;up&quot;)
   end
end
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;b&gt;Problem 2&lt;/b&gt;: Now we need to print all monotonic paths that do not go above the diagonal y = x. Figure 2 shows such a path. Note that the path in figure 1 goes above the diagonal, hence not desirable in this case. How many such paths exist for n x m grid (n &amp;gt;= m)?&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4C6UBxZkiKsN1t54MmsaGyNXoOoODKHTZoviEtsfjnTzWcuMCnPw0RDMum6xyx25T5mSmsGDCTI5b4zckRYcfVGBfBw58vB-MAAJ5VBcq5Jh2clg4zpzwSdBHhk7TteEdohQgc68f6wE/s1600/grid1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;238&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4C6UBxZkiKsN1t54MmsaGyNXoOoODKHTZoviEtsfjnTzWcuMCnPw0RDMum6xyx25T5mSmsGDCTI5b4zckRYcfVGBfBw58vB-MAAJ5VBcq5Jh2clg4zpzwSdBHhk7TteEdohQgc68f6wE/s320/grid1.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 2&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;b&gt;Solution&lt;/b&gt;: &lt;a href=&quot;#&quot; id=&quot;nprg21121_a&quot; onclick=&quot;return toggleMenuAdi(&#39;nprg21121_a&#39;,&#39;nprg21121_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;nprg21121_s&quot; style=&quot;display: none;&quot;&gt;Let us first discuss how to print all monotonic paths that do not go above the diagonal. In order for a path to be valid, at all points (x,y) on the path, y should be less than or equal to x. We can simply ensure this constraint while printing paths, using the following code.&lt;br /&gt;
&lt;pre&gt;Function printPath(x, y, n, m, path)
   if x == n and y == m:
      print path
      return
   end

   if x &amp;lt; n
      printPath(x+1, y, n, m, path + &quot;right&quot;)
   end

   if y &amp;lt; m and y &amp;lt; x
      printPath(x, y+1, n, m, path + &quot;up&quot;)
   end
end
&lt;/pre&gt;The total number of such paths are  [(n-m+1)/(n+1)] * &lt;sup&gt;n+m&lt;/sup&gt;C&lt;sub&gt;m&lt;/sub&gt;. For n = m, this simplifies to [1/(n+1)] * &lt;sup&gt;2n&lt;/sup&gt;C&lt;sub&gt;n&lt;/sub&gt; which is known as &lt;a href=&quot;http://en.wikipedia.org/wiki/Catalan_number&quot;&gt;Catalan number&lt;/a&gt;. The wiki page also contains other interesting problems that have Catalan number as their solution. &lt;br /&gt;
&lt;br /&gt;
Now, In order to obtain the number of paths, we need to subtract the number of paths that cross the diagonal from the total number of paths &lt;sup&gt;n+m&lt;/sup&gt;C&lt;sub&gt;m&lt;/sub&gt;.&lt;br /&gt;
&lt;br /&gt;
Consider a path that crosses the diagonal. Let that path cross the diagonal for the first time at point (x,y). Since this is the first point after crossing the diagonal, so y should be equal to x+1. So the path has taken x right and y up moves. It is yet to take n-x right and m-y up moves to reach (n,m). If we flip the n-x right to n-x up and m-y up to right, then starting from point (x,y), we will reach the point (x+m-y,y+n-x). Setting y = x+1, we get that the resulting end point is (m-1,n+1). Since m &amp;lt;= n, the resulting end point is above the diagonal. So we can do surgery on all paths that cross the diagonal to make them reach (m-1,n+1). So the total number of paths that cross the diagonal must be the total number of paths from (0,0) to (m-1,n+1). This is &lt;sup&gt;n+m&lt;/sup&gt;C&lt;sub&gt;m-1&lt;/sub&gt;.&lt;br /&gt;
&lt;br /&gt;
So the desired number is = &lt;sup&gt;n+m&lt;/sup&gt;C&lt;sub&gt;m&lt;/sub&gt; - &lt;sup&gt;n+m&lt;/sup&gt;C&lt;sub&gt;m-1&amp;nbsp;&lt;/sub&gt; = [(n-m+1)/(n+1)] * &lt;sup&gt;n+m&lt;/sup&gt;C&lt;sub&gt;m&lt;/sub&gt;. This is a proof based on &lt;a href=&quot;http://en.wikipedia.org/wiki/Catalan_number#Second_proof&quot;&gt;Andre&#39;s reflection method&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Alternately&lt;/i&gt;: &lt;br /&gt;
Andre&#39;s reflection method was used to originally solve a very interesting problem called Ballot problem. The ballot problem states that in a two candidate election, candidate A polled p votes and candidate B polled q votes (p &amp;gt; q). What is the probability that candidate A was leading over candidate B throughout the counting. &lt;br /&gt;
&lt;br /&gt;
Well the probability is simply (p-q)/(p+q). &lt;br /&gt;
&lt;br /&gt;
We can use the Ballot theorem to find the number of monotonic paths below the diagonal (that do not even touch the diagonal). We can assume right move to be candidate A and up move to be candidate B and the two polled n,m votes respectively. So the probability of number of right leading number of up is (n-m)/(n+m). So the number of monotonic paths that are below the diagonal (do not even touch) is [(n-m)/(n+m)] * &lt;sup&gt;n+m&lt;/sup&gt;C&lt;sub&gt;m&lt;/sub&gt;.&lt;br /&gt;
&lt;br /&gt;
Now since we are allowed to touch the diagonal, we can assume instead going to (n+1,m). This is because the first two moves would be right moves (otherwise we might touch the diagonal). Then we eliminate the first right move and allow a diagonal touch. So the total number of ways is [(n+1-m)/(n+1+m)] * &lt;sup&gt;n+m+1&lt;/sup&gt;C&lt;sub&gt;m&lt;/sub&gt; = [(n-m+1)/(n+1)] * &lt;sup&gt;n+m&lt;/sup&gt;C&lt;sub&gt;m&lt;/sub&gt;.&lt;/div&gt;&lt;br /&gt;
&lt;b&gt;Problem 3&lt;/b&gt;: Now let us consider that apart from up and right moves we can take up-right (diagonal) moves. Figure 3 shows such a path. How many such paths exist for n x m grid?&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfmbeDpjmEsKzyKT_ggxDyAggzePZl02LHgM8vO-kKwAdvkpTAeIH6kdFYpAcUNPmr91-yIwFVgAL1r0gblKYR6pjirzXatQe48taUP6puE7cwXV6MGZ6MuXR9CM4XO28m5IKiUApyXlY/s1600/grid2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfmbeDpjmEsKzyKT_ggxDyAggzePZl02LHgM8vO-kKwAdvkpTAeIH6kdFYpAcUNPmr91-yIwFVgAL1r0gblKYR6pjirzXatQe48taUP6puE7cwXV6MGZ6MuXR9CM4XO28m5IKiUApyXlY/s320/grid2.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 3&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;b&gt;Solution&lt;/b&gt;: &lt;a href=&quot;#&quot; id=&quot;nprg21122_a&quot; onclick=&quot;return toggleMenuAdi(&#39;nprg21122_a&#39;,&#39;nprg21122_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;nprg21122_s&quot; style=&quot;display: none;&quot;&gt;This problem is similar to problem 1, except that paths can contain diagonal moves. One diagonal move consumes 1 right and 1 up move. &lt;br /&gt;
&lt;br /&gt;
So let us assume that we make r diagonal moves, where r &lt;= min(n,m). In this case, we need to make n-r right moves and m-r up moves apart from r diagonal moves to reach (n,m). The number of ways, we can do this is = (n+m-r)! / [ (n-r)! * (m-r)! * r! ]. If we set r = 0, then we get the solution to problem 1. But in this case r can go from 0 to min(m,n). So the total number of ways is = &lt;pre&gt;Sum_r (n+m-r)! / [(n-r)!*(m-r)!*r!], where r in [0, min(m,n)]&lt;/pre&gt;Alternately, we can derive the recurrence relation for the total number of paths. Let D(n,m) be the total number of paths from (0,0) to (n,m) with up, right and diagonal moves. Clearly, we can reach (n,m) from (n-1,m) by a right move, from (n,m-1) by a up move, and from (n-1,m-1) by a diagonal move. These are the only three atomic steps. So, D(n,m) = D(n-1,m) + D(n,m-1) + D(n-1,m-1) for n,m &gt; 0. D is called as &lt;a href=&quot;http://mathworld.wolfram.com/DelannoyNumber.html&quot;&gt;Delannoy number&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
The code to print all paths has a small addition to the code for problem 1. &lt;br /&gt;
&lt;pre&gt;Function printPath(n, m, path)
   if n == 0 and m == 0
      print path
      return
   end

   if n &amp;gt; 0
      printPath(n-1, m, path + &quot;right&quot;)
   end

   if m &amp;gt; 0
      printPath(n, m-1, path + &quot;up&quot;)
   end

   if n &gt; 0 and m &gt; 0
      printPath(n-1, m-1, path + &quot;diagonal&quot;)
   end
end&lt;/pre&gt;We can extend this problem further by asking the number of paths that do not cross the diagonal (same constraint as problem 2). The number of paths in this case is called &lt;a href=&quot;http://mathworld.wolfram.com/SchroederNumber.html&quot;&gt;Schroder number&lt;/a&gt;.
&lt;br/&gt;&lt;br/&gt;
&lt;i&gt;Source Code&lt;/i&gt;: &lt;a href=&quot;https://github.com/n1balgo/algo/blob/master/grid_paths.py&quot;&gt;grid_paths.py&lt;/a&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/2599729749123069410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2012/07/number-of-paths-in-rectangular-grid.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/2599729749123069410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/2599729749123069410'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2012/07/number-of-paths-in-rectangular-grid.html' title='Number of Paths in a Rectangular Grid'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDbfEmEj5r28pMcVUOnHMh08Kqbnhnb6TQvAYqc2UEa6D2WFI2QHAus_-E4McfR69RMbeERo4NsHvvjUwDglB_N9pLZl0NBZos82q-NIuPLZ_I92yqeyT4kJ7i3D3iij86rYYLUOd9C3k/s72-c/grid.png" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-8844369124590311149</id><published>2012-07-09T16:11:00.000-07:00</published><updated>2014-07-01T15:10:36.725-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="hash"/><category scheme="http://www.blogger.com/atom/ns#" term="probability"/><title type='text'>Finding Top K Elements in Large Dataset</title><content type='html'>&lt;b&gt;Problem&lt;/b&gt;: Consider the problem of finding top K frequent numbers from a file with N numbers. Now consider that N is very large such that it cannot fit in the memory M available to the program. How do we find the top K frequent elements now with the assumption that K &lt; M &lt; N.
&lt;br&gt;&lt;br /&gt;
&lt;b&gt;Deterministic solution&lt;/b&gt;: &lt;a href=&quot;#&quot; id=&quot;ftkeild10312_a&quot; onclick=&quot;return toggleMenuAdi(&#39;ftkeild10312_a&#39;,&#39;ftkeild10312_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;ftkeild10312_s&quot; style=&quot;display: none;&quot;&gt;The idea is similar to solving the problem for small N (N &amp;lt; M) (see &lt;a href=&quot;http://n1b-algo.blogspot.com/2012/07/finding-top-k-frequent-items.html&quot;&gt;here&lt;/a&gt;). For large N, divide the problem into chunks of size &amp;lt;= M, then solve it.&lt;br /&gt;
&lt;br /&gt;
In order to divide the problem, consider a uniform hashing function H that takes a key and returns an integer from the set {1,2,....,ceil(N/M)}. So we get N/M chunks with roughly M unique keys per chunk. Since the number of unique numbers (U) is less than N, we expect each chunk to have less than M unique numbers. &lt;br /&gt;
&lt;br /&gt;
Now for each chunk, we compute the frequency of numbers contained in that chunk. This frequency computation can be done in memory and we can maintain a MIN-HEAP of size K which can be directly updated (&lt;a href=&quot;http://n1b-algo.blogspot.com/2012/07/finding-top-k-frequent-items.html&quot;&gt;follow the steps presented here&lt;/a&gt;). As a result only two reads of the dataset and one disk write is required to get the top K frequent items. The complexity of the algorithm is O(N log K). &lt;br /&gt;
&lt;br /&gt;
Probably for a small K (K &amp;lt; M^2/N), we can compute the top K per chunk in O(K log M) and combine the top K for all chunks N*K/M (&amp;lt;M) to get the overall top K. The total complexity of the algorithm is O(N + M log M).&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Alternate method&lt;/u&gt;: &lt;br /&gt;
We assume that the disk has a huge capacity which allows us to make a disk based hash table. Imagine that we create a very large file &lt;a href=&quot;http://lwn.net/Articles/357767/&quot;&gt;with holes&lt;/a&gt; and divide the file into B blocks with a capacity to hold more than N/B numbers and their integer counts. Using a uniform hash function H which takes as input an arbitrary number x and return H(x): the block number from the set {0, 1, ..., B-1}, we can store the numbers and their frequencies on disk map. H would give us the offset to seek within the file and we write number (and their frequency) sequentially once in correct block (or via another hash function H1). &lt;br /&gt;
&lt;br /&gt;
Now we proceed as usual, start counting the numbers in memory using a hash table (former approach). When we encounter a new number that could not be put in memory, we purge some entries from the hash table. The purged entries are written to the disk map. Now to purge the entries, we maintain an array which counts the frequency of the keys that lie within a block. Keys that belong to the most infrequent blocks can be purged first (or blocks that are least recently used or that lead to least disk access, etc). &lt;br /&gt;
&lt;br /&gt;
The following code gives a very basic detail of this approach&lt;br /&gt;
&lt;pre&gt;BlockFreq = array(B)
NumberFreq = hashtable(M)
diskwrite = 0
for i = 1:N
   x = A[i]
   BlockFreq[H[x]] += 1

   if NumberFreq.haskey(x)
      NumberFreq[x] += 1
      continue
   end

   if NumberFreq.hasspace()
      NumberFreq[x] = 1
      continue
   end

   if DiskMap.haskey(x)
      DiskMap[x] += 1
   else
      DiskMap[x] = 1
   end

   if diskwrite == 10
      purge(NumberFreq, BlockFreq)
      diskwrite = 0
   else
      diskwrite += 1
   end
end&lt;/pre&gt;Here purge is a procedure to purge some set of keys from NumberFreq based on the BlockFreq. Note that this code omits several key details of this process, so the idea presented here is quite crude. &lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;b&gt;Single pass probabilistic solution&lt;/b&gt;: &lt;a href=&quot;http://draft.blogger.com/blogger.g?blogID=759530137113893554#&quot; id=&quot;ftkeild0312_a&quot; onclick=&quot;return toggleMenuAdi(&#39;ftkeild0312_a&#39;,&#39;ftkeild0312_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;ftkeild0312_s&quot; style=&quot;display: none;&quot;&gt;Solution 1 is quite efficient as it requires only two disk reads of the dataset, but the bottleneck can be the disk writes during the initial chunk formation. We can reduce that bottleneck by considering a data-structure called &lt;a href=&quot;http://en.wikipedia.org/wiki/Bloom_filter&quot;&gt;Bloom filters&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
So consider that we have B uniform hash functions H1, H2, ..., HB and each hash function converts a key to a range {1,2,...,R}. Now imagine an array C of size B x R (&amp;lt;M) that represents count of how many times each key is seen. For each number (say x) that we read from the dataset, compute Hi[x] and increment C[i,Hi[x]] by 1. So we maintain B counts of x in different R buckets. We can say that the true count of x is less than min(C[1,H1[x]], ..., C[B,HB[x]]).&lt;br /&gt;
&lt;br /&gt;
Now if the query is to get all the elements with frequency greater than some threshold then we can use bloom filters to get all such numbers (with some false positives though, which can be filtered using another pass on the dataset). This can save a complete write of the data to the disk. (see the paper: &lt;a href=&quot;http://dl.acm.org/citation.cfm?id=671338&quot;&gt;Computing Iceberg Queries Efficiently&lt;/a&gt;). &lt;br /&gt;
&lt;br /&gt;
But in our case, we are interested in finding the top K frequent numbers. Following modification can be used to estimate the frequency of each number. &lt;br /&gt;
&lt;pre&gt;MH = MIN-HEAP(K)
for i = 1:N
   x = A[i]
   for b = 1:B
      C[b,Hb(x)] += Sb(x)
   end

   if contains(MH,x)
      increment count of x in the heap
   else 
      f = median(Hi(x) * Si(x), \forall i)
      if f &amp;gt; min(MH)
         remove-min(MH)
         insert(MH, (x,f))
      end
   end
end
&lt;/pre&gt;The Sb functions is a {-1,+1} hash function and this data-structure is called CountSketch. More details of the method is available in the paper: &lt;a href=&quot;http://dl.acm.org/citation.cfm?id=684566&quot;&gt;Finding Frequent Items in Data Streams&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Note that the above algorithm takes a single passes on the dataset (and no disk write) but it is not guaranteed to give the top K frequent items. It can make some mistakes for some less frequent items. In practice the choice of the hashing functions can be critical for the performance of the algorithm. &lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/8844369124590311149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2012/07/finding-top-k-elements-in-large-dataset.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/8844369124590311149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/8844369124590311149'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2012/07/finding-top-k-elements-in-large-dataset.html' title='Finding Top K Elements in Large Dataset'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-8436821098383264955</id><published>2012-07-03T14:24:00.001-07:00</published><updated>2014-07-17T08:09:05.249-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="hash"/><title type='text'>Finding Top K Frequent Items</title><content type='html'>&lt;br /&gt;
&lt;b&gt;Problem&lt;/b&gt;: Consider a file containing N numbers. For e.x. {2,3,4,3,1,78,78,3} is a file containing N=8 numbers. Assume that N is small enough to fit in the computer&#39;s memory M. So in this case N &amp;lt;&amp;lt; M. Now we need to find top K frequent numbers in the file. For the above example, output should be {3,78} for K = 2.&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Running Time&lt;/u&gt;: Time complexity should be either O(N), O(N log K), O(N + K log N) &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Solution&lt;/b&gt;: &lt;a href=&quot;https://draft.blogger.com/blogger.g?blogID=759530137113893554#&quot; id=&quot;ftkfi0312_a&quot; onclick=&quot;return toggleMenuAdi(&#39;ftkfi0312_a&#39;,&#39;ftkfi0312_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;ftkfi0312_s&quot; style=&quot;display: none;&quot;&gt;Finding top K frequent elements is a classical database and data streaming problem and there are several solutions to it ranging from deterministic to probabilistic. I&#39;ll illustrate the three obvious ones here. &lt;br /&gt;
&lt;br /&gt;
The first step is to count how many times each number appears in the file. If the file is pre-sorted then we need a single scan over the file. &lt;br /&gt;
&lt;pre&gt;Function COUNTS:
   A = load_file_in_array

   last = A[1]
   ctr = 1
   for i = 2:N
      if last == A[i]
         ctr += 1
      else
         CountMap{last} = ctr;
         last = A[i]
         ctr = 1
      end 
   end

   // required for the last element of the array
   CountMap{last} = ctr
end
&lt;/pre&gt;Note that CountMap is a hashmap that stores counts of all the elements. The procedure COUNTS is quite efficient if the file is pre-sorted. Now if the file is not pre-sorted then sorting increases the time complexity to O(N log N). In that case, we can do better by directly using hashmap to maintain current count of each number without sorting the file as follows:&lt;br /&gt;
&lt;pre&gt;Function EFFICIENT_COUNTS:
   A = load_file_in_array
   
   for i = 1:N
      CountMap{A[i]} += 1
   end
end
&lt;/pre&gt;The above procedure obtains counts of each element in a single scan of the file. Hence it runs in O(N) time. So now we have all the numbers along with their frequencies in an array (can be extracted by enumerating all keys of the CountMap or by another scan of the file!!). So for the example we have in the problem statement, we get the following tuple: {(2,1), (3,3), (4,1), (1,1), (78,2)}.&lt;br /&gt;
&lt;br /&gt;
The problem that remains is to find the most frequent K numbers from the array. The naive approach would be to sort numbers on their frequencies and pick the top K. This would take O(U log U) time where U (=5) is the number of unique elements in the array. If we consider U = O(N) then the time complexity of this sorting is O(N log N). We can do better than that as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;u&gt;Approach 1&lt;/u&gt;&lt;/i&gt;: O(N) time&lt;br /&gt;
Use selection algorithm to find the Kth most frequent number (on the second element of the tuple) using the &lt;a href=&quot;http://en.wikipedia.org/wiki/Selection_algorithm&quot;&gt;Selection Algorithm&lt;/a&gt; in O(U) time. The Kth most frequent element partitions the array in two parts: first part containing top K most frequent elements and second part containing bottom U-K-1 frequent elements. So we get the top K most frequent elements in no particular order in O(N) time (assuming U = O(N)). They can be sorted in O(K log K) if needed. Note that although this approach runs in O(N) time, the constants hidden in the O-notation can be large. So in practice this approach can be slower than the two approaches described below. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;u&gt;Approach 2&lt;/u&gt;&lt;/i&gt;: O(N log K) time&lt;br /&gt;
Pick first K tuples and put them on MIN-HEAP, where a tuple (x,y) is less than a tuple (a,b) if y is less than b. The time complexity to make the min heap of size K is O(K). &lt;br /&gt;
&lt;br /&gt;
Then for the remaining U - K elements, pick them one by one. If the picked element is lesser than the minimum on the heap, discard that element. Otherwise remove the min element from the head and insert the selected element in the heap. This ensures that heap contains only K elements. This delete-insert operation is O(log K) for each element. &lt;br /&gt;
&lt;br /&gt;
Once we are done picking all the elements, the elements that finally remain in the min-heap are the top K frequent items which can be popped in O(K log K) time. The overall cost of this approach is O(K + (U-K) log K + K log K) = O(K + U log K). Since K &amp;lt; U and U = O(N), we get the time complexity of O(N log K).&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;u&gt;Approach 3&lt;/u&gt;&lt;/i&gt;: O(N + K log N) time&lt;br /&gt;
This approach is similar to approach 2 but the main difference is that we make a MAX-HEAP of all the U elements. So the first step is to make the max heap of all the elements in O(U). Then remove the maximum element from the heap K times in O(K log U) time. The K removed elements are the desired most frequent elements. The time complexity of this method is O(U + K log U) and by setting U = O(N) we get O(N + K log N). &lt;br /&gt;
&lt;br /&gt;
Let us stop for a moment and contrast approach 2 from 3. For simplicity let T2 = K + N log K be the time complexity of approach 2 and T3 = N + K log N be the time complexity of the third approach. Figure below plots the ratio T2/T3 for N=100 and for different values of K. We observe that approach 3 is considerably better for small values of K whereas approach 2 is better for large values of K. Though actual difference depends on the constants involved we can still see the merit of one approach over another. &lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid_j0dFiPsoEttn-plYNXGc-8iANWrJAsyuFjYG4c_YlOpIJnYldv3n1pJhw8wUHvQD4Nlovz5WUqdkgRNKW1Bs2tmNFuEjERTQTfBiDYOME3Ubk25g6oXfF-8ly0QDChFNI81xzkNUok/s320/T2T3.bmp&quot; height=&quot;240&quot; width=&quot;320&quot; /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/8436821098383264955/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2012/07/finding-top-k-frequent-items.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/8436821098383264955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/8436821098383264955'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2012/07/finding-top-k-frequent-items.html' title='Finding Top K Frequent Items'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid_j0dFiPsoEttn-plYNXGc-8iANWrJAsyuFjYG4c_YlOpIJnYldv3n1pJhw8wUHvQD4Nlovz5WUqdkgRNKW1Bs2tmNFuEjERTQTfBiDYOME3Ubk25g6oXfF-8ly0QDChFNI81xzkNUok/s72-c/T2T3.bmp" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-7952057948689461397</id><published>2010-03-26T23:37:00.010-07:00</published><updated>2012-07-21T16:02:59.498-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="hash"/><title type='text'>Problems solvable using Hashtable</title><content type='html'>Hashtable are extremely useful data-structure as they provide storage and retrieval in O(1) time (amortized). Several problems of algorithms can be very efficiently solved using hashtables which otherwise turn out to be quite expensive. In this post, we consider some of these problems:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Problem 1&lt;/span&gt;: Remove duplicate elements from an unsorted array of size N.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;#&quot; id=&quot;psuh10310_a&quot; onclick=&quot;return toggleMenuAdi(&#39;psuh10310_a&#39;,&#39;psuh10310_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;psuh10310_s&quot; style=&quot;display: none;&quot;&gt;Lets first see the solution without hashtable. Naive solution would be to compare each pair of elements. If they are same then drop one of them. This solution would take O(N^2) time in average case and O(N) time in best case, when all the elements are same. The following code does that:&lt;br /&gt;
&lt;pre&gt;for i = 1 to N-1
  if a[i] == NaN: continue
  print a[i]
  
  for j = i+1 to N
    if a[i] == a[j]: a[j] = NaN
&lt;/pre&gt;Above code prints all non-duplicates from the array. Naive solution is average case O(N^2). In practice if you believe that array consists of few numbers duplicated lots of times, say K numbers duplicated N/K times, then the running time of above algorithm is O(KN).&lt;br /&gt;
&lt;br /&gt;
We can do better than worst case O(N^2) time. If we sort the elements in O(N logN) time and compare adjacent elements in O(N), we can solve the above problem in O(N logN) time. &lt;br /&gt;
&lt;pre&gt;sort(a) // O(N log N) time, O(1) space using Heap Sort

k = a[1]
for i = 2 to N
  if a[i] == k: a[i] = NaN
  else: k = a[i]
&lt;/pre&gt;Using heap sort, we can make the above algorithm run in O(N log N) time in worst case and it would take O(1) extra space (apart from N for the array). Using hashtable, we can solve this problem in O(N) time (amortized) and O(N) space (for the hash table). The algorithm looks like following:&lt;br /&gt;
&lt;pre&gt;for i = 1 to N
  if hash.has_key(a[i]) == false:
    print a[i]
    hash.put(a[i])
&lt;/pre&gt;Above algorithm stores an unseen element in hash-table and ignores the seen element. To check if an element is seen or not, hash table provides storage/retrieval methods in O(1) time.&lt;/div&gt;&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Problem 2&lt;/span&gt;: Find intersection of K unsorted array of N elements each. Intersection consists of elements that appear in all the K arrays.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Problem 3&lt;/span&gt;: How to make a linked list support operations in O(1) time. The operations on linked list can be insertion after any arbitrary valued node, deletion of any arbitrary valued node. &lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Problem 4&lt;/span&gt;: Find all unique pairs of element in an array that sum to S. For ex. If array = {2,4,6,4,6} and S = 8 then answer is {(2,6), (4,4)}&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Problem 5&lt;/span&gt;: Consider an array containing unique elements. Find a triplet of elements in the array that sum to S (extension of problem 4). Can hash-tables improve the running time of your algorithm.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Problem 6&lt;/span&gt;: Consider two strings of size M, N. Perform string matching in size O(M+N).</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/7952057948689461397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2010/03/problems-solvable-using-hashtable.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/7952057948689461397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/7952057948689461397'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2010/03/problems-solvable-using-hashtable.html' title='Problems solvable using Hashtable'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-6644000873175006268</id><published>2010-03-19T09:24:00.001-07:00</published><updated>2010-03-19T09:52:17.960-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="puzzle"/><title type='text'>Dragon and Knight</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Problem&lt;/span&gt;: A dragon and knight live on an island. This island has seven poisoned wells, numbered 1 to 7. If you drink from a well, you can only save yourself by drinking from a higher numbered well. Well 7 is located at the top of a high mountain, so only the dragon can reach it.&lt;br /&gt;
&lt;br /&gt;
One day they decide that the island isn&#39;t big enough for the two of them, and they have a duel. Each of them brings a glass of water to the duel, they exchange glasses, and drink. After the duel, the knight lives and the dragon dies.&lt;br /&gt;
&lt;br /&gt;
Why did the knight live? Why did the dragon die?&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;#&quot; id=&quot;dk0310_a&quot; onclick=&quot;return toggleMenuAdi(&#39;dk0310_a&#39;,&#39;dk0310_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;div id=&quot;dk0310_s&quot; style=&quot;display:none&quot;&gt;Dragon knows that knight cant reach well 7. So he thinks that if i give knight water from well 6 or 7, knight would die for sure. So he would get water from well 6 or 7 for knight.&lt;br /&gt;
&lt;br /&gt;
Knight knew that no matter from which well he gives the water, dragon will go and drink from well 7 and live. So he got normal water for dragon and before duel drank water from well 1. &lt;br /&gt;
&lt;br /&gt;
When they exchanged glasses and drank water, dragon rushed to well 7 and drank poison from it, thinking that it would cure the poison he just drank (but he drank normal water), so dragon died. Knight on the other hand already had poison from well 1 so what dragon gave him effectively cured him. So he lived.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Problem&lt;/span&gt;: Now consider that Dragon and Knight are equally intelligent then who is expected to die. &lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Answer&lt;/span&gt;: &lt;font color=&quot;white&quot;&gt;Both survive the battle.&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;#&quot; id=&quot;dk10310_a&quot; onclick=&quot;return toggleMenuAdi(&#39;dk10310_a&#39;,&#39;dk10310_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;div id=&quot;dk10310_s&quot; style=&quot;display:none&quot;&gt;After the battle, dragon drinks from well 1 in order to guarantee that he is poisoned. He then drinks from well 7 to cure himself. Even if knight gets normal water or poison from well 1-6, dragon is now cured and survives. &lt;br /&gt;
&lt;br /&gt;
As for the knight, he drinks from well 1 before the duel. If dragon has got poison for him then he is cured. But if dragon got normal water then he has to ensure that he cures by drinking poison from higher than well 1. So after the battle, knight re-drinks from well 1. This guarantees that he is poisoned from well 1. Then he goes and drinks from well 2 to cure himself. &lt;br /&gt;
&lt;br /&gt;
So both dragon and knight survive the battle.&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/6644000873175006268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2010/03/dragon-and-knight.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/6644000873175006268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/6644000873175006268'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2010/03/dragon-and-knight.html' title='Dragon and Knight'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-3936445213744355055</id><published>2010-03-18T15:40:00.009-07:00</published><updated>2012-08-02T09:39:04.934-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="maths"/><category scheme="http://www.blogger.com/atom/ns#" term="puzzle"/><title type='text'>Number and Age of David&#39;s Kids</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Problem&lt;/span&gt;: The product of the ages of David&#39;s children is the square of the sum of their ages. David has less than eight children. None of his children have the same age. None of his children is more than 14 years old. All of his children is at least two years old. How many children does David have, and what are their ages? &lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Answer&lt;/span&gt;: &lt;font color=&quot;white&quot;&gt;(12,6,4,2)&lt;/font&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;#&quot; id=&quot;nadk0310_a&quot; onclick=&quot;return toggleMenuAdi(&#39;nadk0310_a&#39;,&#39;nadk0310_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;div id=&quot;nadk0310_s&quot; style=&quot;display:none&quot;&gt;A way to mathematically analyze this problem is to write the general form of equations, differentiate and maximize w.r.t to largest age. That leads to a Fibonacci number series. But after that complex heuristics have to be employed to devise the solution (and we cannot guarantee if that is the unique). &lt;br /&gt;
&lt;br /&gt;
This is a constraint satisfaction problem. The best way to solve it is write the code. The following code solves the problem in general sense:&lt;br /&gt;
&lt;pre&gt;Function find_ages(kidAges)  
   s = sum(kidAges)
   p = product(kidAges)
   if s*s == p
      print kidAges

   l = length(kidAges)
   if l &gt;= 7
      return
   else if l == 0
      x = 14
   else
      x = kidAges[l]
   end

   for i = 2 to x-1
      kidAges1 = clone(kidAges)
      kidAges1.add(i)
      find_ages(kidAges1)
   end
end

// call
find_ages([])
&lt;/pre&gt;&lt;br /&gt;
After running the code, we see the following solution&lt;br /&gt;
&lt;pre&gt;[12, 6, 4, 2]&lt;/pre&gt;Note that in the above pseudo code, we cloned the kidAges array. If we dont clone then it wont work properly. Down side of cloning is that now we use a huge amount of memory. How do we write code without cloning? Check the python script attached below.&lt;/div&gt;&lt;br/&gt;&lt;br /&gt;
&lt;i&gt;Source Code&lt;/i&gt;: &lt;a href=&quot;https://github.com/n1balgo/algo/blob/master/david_kids_ages.py&quot;&gt;david_kids_ages.py&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/3936445213744355055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2010/03/number-and-age-of-davids-kids.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/3936445213744355055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/3936445213744355055'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2010/03/number-and-age-of-davids-kids.html' title='Number and Age of David&#39;s Kids'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-7020364072598218509</id><published>2010-03-11T12:53:00.005-08:00</published><updated>2012-07-21T16:08:08.141-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>Largest Sum of Consecutive Numbers</title><content type='html'>&lt;span style=&quot;font-weight: bold;&quot;&gt;Problem&lt;/span&gt;: Given an array of N integers (both positive and negative), find the sub-sequence with largest sum.&lt;br /&gt;
&lt;br /&gt;
For ex: Let A = {1 2 -5 4 5 -1 2 -11} then largest sum is 10 (start = 4, end = 7)&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;http://www.blogger.com/post-edit.g?blogID=759530137113893554&amp;amp;postID=7020364072598218509#&quot; id=&quot;lscn0310_a&quot; onclick=&quot;return toggleMenuAdi(&#39;lscn0310_a&#39;,&#39;lscn0310_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;lscn0310_s&quot; style=&quot;display: none;&quot;&gt;The naive solution to this problem can be formulated and coded in O(N^3) time. Consider every possible pair of start and end index and calculate sum of the elements within those index and keep track of the max sum. The following code performs that&lt;br /&gt;
&lt;pre&gt;max = - Inf
imax = jmax = -1
for i = 1 to N
  for j = i to N
    
    // get sum of elements enclosed in index (i,j)
    s = 0
    for k = i to j
      s += A[k]

    if s &amp;gt; max
      max = s
      imax = i
      jmax = j
&lt;/pre&gt;Clearly the above algorithm is O(N^3). We can definitely improve the running time of the above algorithm. After observing carefully, we can see that an operation that is run several times (O(N^2) times) is computing the sum of elements between indices i,j. Can we do it quickly. Indeed we can. &lt;br /&gt;
&lt;br /&gt;
If we save the cumulative sum of elements in an array CSUM, then CSUM[i] indicates the sum of elements enclosed in indices (1,i), CSUM[j]-CSUM[i-1] would then indicate the sum of elements enclosed in indices (i,j). The following algorithm captures this intuition.&lt;br /&gt;
&lt;pre&gt;csum[0] = 0
for i = 1 to N
  csum[i] = csum[i-1] + A[i]

max = - Inf
imax = jmax = -1
for i = 1 to N
  for j = i to N
    s = CSUM[j] - CSUM[i-1]
    if s &amp;gt; max 
      max = s
      imax = i 
      jmax = j
&lt;/pre&gt;This is the best we can do with this approach. This problem can be done in O(N) time using a clever approach. Consider a sub-sequence with sum s &amp;gt; 0. Let the next element n is such that s + n &amp;lt; 0. Clearly this sub-sequence cannot be part of largest subsequence that contains s and n as removing s,n from that sub-sequence we get a larger sum. Easy to prove using contradiction. This idea is captured in the following O(N) algorithm &lt;br /&gt;
&lt;pre&gt;max = -Inf
imax = jmax = -1
i_temp = -1
s_temp = 0
for i = 1 to N 
  s_temp += A[i]

  if s_temp &amp;gt; max
    // keep track of max so far
    max = s_temp
    imax = i_temp
    jmax = i

  if s_temp &amp;lt; 0
    // abort this sub-sequence
    s_temp = 0
    i_temp = i + 1

  
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Problem&lt;/span&gt;: Given an array of N integers (both positive and negative), find the sub-sequence with largest &lt;b&gt;absolute&lt;/b&gt; sum. This problem differs from the one at the top as we want the absolute sum (taking mod)&lt;br /&gt;
&lt;br /&gt;
For ex: Let A = {1 2 -5 4 5 -1 2 -11} then largest absolute sum is 11.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;http://www.blogger.com/post-edit.g?blogID=759530137113893554&amp;amp;postID=7020364072598218509#&quot; id=&quot;lscn10310_a&quot; onclick=&quot;return toggleMenuAdi(&#39;lscn10310_a&#39;,&#39;lscn10310_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;lscn10310_s&quot; style=&quot;display: none;&quot;&gt;Simply keep track of max and min at the same time in the above O(N) solution. &lt;br /&gt;
&lt;br /&gt;
Assuming that we have to use the above algorithm without modification, then we can take these steps to get max absolute sum in O(N) time:&lt;br /&gt;
&lt;pre&gt;1. Run O(N) algorithm on array A to get the max
2. Create array B by multiply all numbers in A by -1
3. Run O(N) algorithm on array B to get the max
4. Pick the max between the output of two runs of the algorithm&lt;/pre&gt;&lt;br /&gt;
Instead of trying the above two methods, we can try a very nice and simple approach&lt;br /&gt;
&lt;pre&gt;// build csum matrix as before
csum[0] = 0
for i = 1 to N
  csum[i] = csum[i-1] + A[i]

answer = max(csum) - min(csum)
&lt;/pre&gt;The answer is maximum element of csum minus the minimum element of csum.&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/7020364072598218509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2010/03/largest-sum-of-consecutive-numbers.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/7020364072598218509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/7020364072598218509'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2010/03/largest-sum-of-consecutive-numbers.html' title='Largest Sum of Consecutive Numbers'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-3589179022869127771</id><published>2010-02-03T11:41:00.008-08:00</published><updated>2012-07-21T16:08:48.909-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="maths"/><title type='text'>Polynomial Evaluation</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Problem&lt;/span&gt;: Given a polynomial with degree bound of n=m^r. How do we evaluate the polynomial at n different points such that the polynomial can be recovered from these n points (i.e. the coefficients can be calculated back using the points). &lt;br /&gt;
&lt;br /&gt;
Note: We do not want to recover the coefficients but cleverly choosing the points as that impacts the running time of the algorithm. &lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;#&quot; id=&quot;pe0210_a&quot; onclick=&quot;return toggleMenuAdi(&#39;pe0210_a&#39;,&#39;pe0210_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;div id=&quot;pe0210_s&quot; style=&quot;display:none&quot;&gt;Let the polynomial be A(x) = a0 + a1 x + a2 x^2 + ... + a(n-1) x^(n-1).&lt;br /&gt;
&lt;br /&gt;
A(x) has a degree bound of n. Its actual degree can be lower than n-1 if a(n-1) equals zero but that doesn&#39;t matter here.&lt;br /&gt;
&lt;br /&gt;
Using Horner&#39;s rule, we can compute a polynomial in O(n) time by arranging the terms as follows:&lt;br /&gt;
&lt;br /&gt;
A(x) = a0 + x (a1 + x (a2 + ... + x (a(n-2) + x a(n-1))))&lt;br /&gt;
&lt;br /&gt;
So it will take O(n^2) time to compute polynomial at n different points. But we can use divide and conquer to do better than that i.e. in O(n lg n). We can create &quot;m&quot; different polynomials such that each term of ith polynomial has degree mod m = i. &lt;br /&gt;
&lt;br /&gt;
=&gt; A(x) = [ a0 + a(m)&amp;nbsp;x^m + a(2m)&amp;nbsp;x^2m ... ] + &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[ a1 + a(m+1)&amp;nbsp;x^(m+1) + a(2m+1)&amp;nbsp;x^(2m+1) ... ] + &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;. &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;. &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[ a(m-1)&amp;nbsp;x^(m-1) + a(2m-1)&amp;nbsp;x^(2m-1) + ... ]&lt;br /&gt;
&lt;br /&gt;
=&gt; A(x) = A[0](y) + x A[1](y) + ... + x^i A[i](y) + ... + x^(m-1) A[m-1](y)&lt;br /&gt;
&lt;br /&gt;
where y = x^m, and&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A[i](x) = a(i) + a(m+i) . x + ... + a(n-m+i) . x^(n/m-1)&lt;br /&gt;
&lt;br /&gt;
Still the recurrence for evaluation each point is T(n) = m T(n/m) + O(m) = O(n). So evaluating polynomial at n points leads to O(n^2) which is not great. &lt;br /&gt;
&lt;br /&gt;
Now we can choose the n points cleverly. Lets set w as principal nth root of unity. &lt;br /&gt;
=&gt; w^n = 1 &lt;br /&gt;
=&gt; w = e^(2 . pi . i / n) &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;= cos (2 . pi /n) + i . sin(2 . pi / n)&lt;br /&gt;
&lt;br /&gt;
The two interesting properties of w are&lt;br /&gt;
1. w^(n/2) = -1 &lt;br /&gt;
2. [w^(kn/m + p)]^m = w^(kn + mp) = w^(mp)&lt;br /&gt;
&lt;br /&gt;
So the n points on which the polynomial can be evaluated are w^0, w^1, ..., w^(n-1). Now we need to evaluate lower order polynomials of size n/m at only first m powers of w as afterwards it cycles again and we can reuse the computation. This comes from the observation that&lt;br /&gt;
&lt;br /&gt;
A(w^p) = A[0](w^(mp)) + w^p A[1](w^(mp)) + ... + w^(m-1) A[m-1](w^(mp))&lt;br /&gt;
&lt;br /&gt;
Also,&lt;br /&gt;
A(m^(kn/m+p)) = A[0](w^(mp)) + w^(kn/m+p) A[1](w^(mp)) + ... + [w^(kn/m+p)]^(m-1) A[m-1](w^(mp))&lt;br /&gt;
&lt;br /&gt;
So A[0], ... A[m-1] are evaluated at p = { 0, 1, ..., m-1 }, and the computation is used for all the other n-m powers of w. &lt;br /&gt;
&lt;br /&gt;
The general recurrence of this algorithm is: &lt;br /&gt;
&lt;br /&gt;
T(n) = m T(n/m) + O(n) &lt;br /&gt;
=&gt; T(n) = O(n lg n)&lt;br /&gt;
&lt;br /&gt;
m = 2 works well in practice and is employed by Fast Fourier Transform in order to intrapolate the coefficients of the polynomial. This is generally used for multiplying two polynomials to get higher order polynomial. The steps are to first evaluate the lower order polynomials at n points and then use the multiplication of the point values to generate the coefficients of the higher order polynomial.&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/3589179022869127771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2010/02/polynomial-evaluation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/3589179022869127771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/3589179022869127771'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2010/02/polynomial-evaluation.html' title='Polynomial Evaluation'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-6397781499975484364</id><published>2009-02-15T10:34:00.008-08:00</published><updated>2012-07-12T15:17:50.744-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>Longest Monotone Sequence and Palindromes</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Problem&lt;/span&gt;: Given an array of integers, find the longest subsequence of elements which monotonically increases. for ex. array = {1 4 8 2 5 7 3 4 6}, the longest subsequence = {1 2 3 4 6}&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;#&quot; id=&quot;lmsap0109_a&quot; onclick=&quot;return toggleMenuAdi(&#39;lmsap0109_a&#39;,&#39;lmsap0109_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;div id=&quot;lmsap0109_s&quot; style=&quot;display:none&quot;&gt;Let us construct the solution using the LCS problem. LCS is longest common subsequence, which says that given two string X, Y find the longest common subsequence between them, for ex. if X = {a b c a b c} and Y = {b a c b a c} then a possible LCS(X, Y) = {b c b c}. LCS problem can be solved using dynamic programming in O(n^2). &lt;br /&gt;
&lt;br /&gt;
We can solve the longest monotonically increasing sequence problem using the solution to LCS. Let X = original string. Let Y = sort X (increasing order). LCS(X, Y) gives the desired answer (easy to observe).&lt;br /&gt;
&lt;br /&gt;
There is a faster O(n log n) algorithm (for details check &lt;a href=&quot;http://www.algorithmist.com/index.php/Longest_Increasing_Subsequence#Faster_Algorithm&quot;&gt;here&lt;/a&gt;)&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Problem&lt;/span&gt;: Given a string, find the longest size palindrome in the string. for ex. string = &quot;aaabbccaccbaaa&quot;, solution = &quot;bccaccb&quot;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;#&quot; id=&quot;lmsap0209_a&quot; onclick=&quot;return toggleMenuAdi(&#39;lmsap0209_a&#39;,&#39;lmsap0209_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;div id=&quot;lmsap0209_s&quot; style=&quot;display:none&quot;&gt;The trivial solution is to check if a palindrom of all possible size starts from a given index. For a index i in array, the possible possitions to test are i &lt; j &lt;= n. Total time taken = O(n^3). We can  solve this problem using &lt;a href=&quot;http://en.wikipedia.org/wiki/Longest_common_substring_problem&quot;&gt;Longest Common Substring&lt;/a&gt; and suffix trees to solve this problem in O(n) time.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/6397781499975484364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/longest-monotone-sequence-and.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/6397781499975484364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/6397781499975484364'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/longest-monotone-sequence-and.html' title='Longest Monotone Sequence and Palindromes'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-9214003419683462133</id><published>2009-01-31T00:52:00.014-08:00</published><updated>2010-03-28T20:03:28.408-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>Loops in Linked List</title><content type='html'>Problems with linked lists occur mainly while building or using a bad memory manager. Let us discuss two well known linked list problems.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Problem:&lt;/b&gt; Find if two linked lists short at some node. Find the node at which the two lists short. &lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution:&lt;/span&gt; &lt;a href=&quot;#&quot; id=&quot;lill09_a&quot; onclick=&quot;return toggleMenuAdi(&#39;lill09_a&#39;,&#39;lill09_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;div id=&quot;lill09_s&quot; style=&quot;display:none&quot;&gt;Subtract the length of smaller list from the larger one. Move a pointer ahead on larger list by the difference of lengths. Now put a pointer on head of smaller list. More two pointers together. The point at which they meet is the point where they short. The following code gives the idea. 
&lt;pre&gt;
d = length(head1) - length(head2)
l1, l2 = head1, head2
if d &lt; 0
  d *= -1 
  l1, l2 = head2, head1

ptr1 = l1
for i &lt;- 1 to d
  ptr1 = ptr1-&gt;next

ptr2 = l2
while ptr1 != null
  if ptr2 == ptr1
    return ptr1

ptr1 = ptr1-&gt;next
ptr2 = ptr2-&gt;next
&lt;/pre&gt;
We can use this idea to find the shorted node to find the solution to next problem.&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Problem:&lt;/b&gt; A linked list might contain a loop. How do we detect existence of the loop and find the node from which loop starts. Propose an O(n) time algorithm that doesn&#39;t take extra space and doesn&#39;t modify the linked list. &lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution:&lt;/span&gt; &lt;a href=&quot;#&quot; id=&quot;lill109_a&quot; onclick=&quot;return toggleMenuAdi(&#39;lill109_a&#39;,&#39;lill109_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;div id=&quot;lill109_s&quot; style=&quot;display:none&quot;&gt;To find if the linked list contains a loop, run two pointers over the linked list, one that move one node at a time and other that moves two nodes at a time. Both of these pointers meet if the linked list contains a loop, otherwise the pointer moving with twice speed reaches the end while the slower pointer reaches midway.
&lt;pre&gt;
fastptr = head
slowptr = head

while fastptr != null and fastptr-&gt;next != null
  fastptr = fastptr-&gt;next-&gt;next
  slowptr = slowptr-&gt;next
  if fastptr == slowptr
    return &quot;loop exists&quot;
return &quot;loop doesnt exist&quot;
&lt;/pre&gt;
If loop exists, then fast pointer meets the slow pointer before slow pointer completes one rotation of the loop. This fact can be easily proved. Once the pointers meet, we can count the number of nodes in the loop.
&lt;pre&gt;
loopNodeCount = 0
do 
  loopNodeCount += 1
  slowptr = slowptr-&gt;next
while slowptr != fastptr
return loopNodeCount
&lt;/pre&gt;
Now using the trick used in the two linked list shorting problem above, we start two pointers, one from the head and other after advancing &quot;loopNodeCount&quot; nodes ahead. The node at which both the pointers meet is the loop node. 
&lt;pre&gt;
advptr = head
for i in range(1, loopNodeCount)
  advptr = advptr-&gt;next

normalptr = head
while normalptr != advptr
  normalptr = normalptr-&gt;next
  advptr = advptr-&gt;next
return advptr&lt;/pre&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/9214003419683462133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/loops-in-linked-list.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/9214003419683462133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/9214003419683462133'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/loops-in-linked-list.html' title='Loops in Linked List'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-1817981059083972078</id><published>2009-01-31T00:14:00.009-08:00</published><updated>2012-07-21T16:09:45.747-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="maths"/><category scheme="http://www.blogger.com/atom/ns#" term="probability"/><title type='text'>Monty Hall Problem</title><content type='html'>This is a very famous probability problem. This problem illustrates that probability is sometimes more convincing than &quot;what we perceive as obvious&quot;. I&#39;ll post another problem that defeats &quot;obvious reasoning&quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Monty_Hall_problem&quot;&gt;Monty Hall problem&lt;/a&gt;:&lt;/b&gt; Suppose you&#39;re on a game show, and you&#39;re given the choice of three doors: Behind one door is a car; behind the others, goats. You pick a door, say No. 1, and the host, who knows what&#39;s behind the doors, opens another door, say No. 3, which has a goat. He then says to you, &quot;Do you want to pick door No. 2?&quot; Is it to your advantage to switch your choice?&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;#&quot; id=&quot;mhp3109_a&quot; onclick=&quot;return toggleMenuAdi(&#39;mhp3109_a&#39;,&#39;mhp3109_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;div id=&quot;mhp3109_s&quot; style=&quot;display:none&quot;&gt;Well for a mathematician stuck on the game show, I would suggest tossing the unbiased coin. The reason being that Game Show host might be clever and seeing that mathematician got the prize behind door 1, would play this card in order to entice the mathematician to switch. Mathematician can be well aware of this trick of Game show host and might not switch. But game show host thought so .. errr. This is a recursive logic and would go to infinity. &lt;br /&gt;
&lt;br /&gt;
Under the assumption that game show host has no hidden motive and performs this step always, the best choice is to switch. That increases the chances by 33.33%. There is a very simple explanation to this. The prize could be behind any doors. Since you pick door 1. Assume game show hosts says that either keep door 1 or take both door 2 and 3, you would go for both door. That doubles up wining chances to 66%. He opens door 3 for you and you open door 2 when you say switch. &lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Red Green Cards:&lt;/b&gt; A box has three cards. First card has both sides green, second card has both sides red, third card has one side green and one side red. A card is picked at random and its one side is observed to be green. What is the probability that the other side of the card is also green.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution&lt;/span&gt;: &lt;a href=&quot;#&quot; id=&quot;mhp3109_1a&quot; onclick=&quot;return toggleMenuAdi(&#39;mhp3109_1a&#39;,&#39;mhp3109_1s&#39;);&quot;&gt;show&lt;/a&gt;&lt;div id=&quot;mhp3109_1s&quot; style=&quot;display:none&quot;&gt;Well it seems that answer should be 1/2. But its 2/3. For explanation, let us label card 1 as g1|g2, second card as r1|r2, third card as g3|r3. Now since one side of the card is green. It can either be g1, g2, g3. Three events and two point to first card.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/1817981059083972078/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/monty-hall-problem.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/1817981059083972078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/1817981059083972078'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/monty-hall-problem.html' title='Monty Hall Problem'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-4741038432292026615</id><published>2009-01-30T20:04:00.002-08:00</published><updated>2012-08-02T13:33:38.501-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>Finding Second Smallest Element</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Jargon:&lt;/span&gt; Order Statistics problem is to find the kth smallest element in an unsorted array A[1..n]. This problem can be solved in O(n) time in average case using randomized select algorithm or in O(n) time in worst case time using an algorithm that chooses the pivot element carefully.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Problem:&lt;/span&gt; How to find second smallest element in an array A[1..n] of size n. We would like to do in much less than 2n comparisons.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Answer:&lt;/span&gt; Time Complexity = n + ceil(log n) - 2&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution:&lt;/span&gt; &lt;a href=&quot;#&quot; id=&quot;fsse08_a&quot; onclick=&quot;return toggleMenuAdi(&#39;fsse08_a&#39;,&#39;fsse08_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;fsse08_s&quot; style=&quot;display:none&quot;&gt;Finding the smallest element is trivial. The following code would find the smallest element using n-1 comparisons.&lt;br /&gt;
&lt;pre&gt;min = A[1]
for i = 2 to n
  if A[i] &lt; min 
    min = A[i]
return min
&lt;/pre&gt;
The trivial algorithm to find the second minimum is to keep another variable (smin) along with min and if an element knocks out smin then check if it knocks out min and accordingly do the book-keeping. It can be done using 2n-3 comparisons and takes constant space. 

A point to observe is that the second smallest element is knocked out by the smallest one at some stage. If we preserve which element is knocked out by whom then finding the second smallest element would just require us to find the smallest amongst the elements knocked out by the smallest element.

But in order to do that we need to build the algorithm in a way that we are playing a pair wise tournament. Lets say we play a tournament and knockout n/2 elements after n/2 comparisons. The recurrence relation looks like this: 
&lt;pre&gt;T(n) = T(n/2) + n/2
&lt;/pre&gt;Solving this recurrence gives that T(n) = n - 1. The height of the recurrence tree is lg n. So if we just check these elements knocked by root (min) we get the second minimum.For. E.x.
&lt;pre&gt;1   5 2   6  
\ /   \ /  
 1     2
  \   /
    1&lt;/pre&gt;As soon as we build the tree using n-1 comparisons, we can check the second largest amongst the number knocked out by 1. i.e. 2, 5. so the second minimum is 2. The number of comparison is n + ceil(log n) - 2, where log is taken to the base 2. We implement this algorithm by maintaining a list of indices knocked by an element. The python code is towards the end of this post. &lt;br/&gt;&lt;br/&gt;
Another algorithm that is very easy to implement but sadly takes 2n - 2logn - 1 in terms of array element comparisons. Simply build a min heap (rooted at 1). Return the smaller of numbers at index 2 or 3 in the array. The cost of min heap building is = 2 * [n/4 + 2n/8 + ...... + (logn - 1) * n / 2^logn]. The solution to this arithmetic - geometric series is 2n - 2logn - 2. Comparing elements at 2nd and 3rd index adds one to the cost. Its very easy to implement though.&lt;/div&gt;&lt;br/&gt;
&lt;i&gt;Code for n + log n - 2 algorithm:&lt;/i&gt; &lt;a href=&quot;https://github.com/n1balgo/algo/blob/master/second_smallest.py&quot;&gt;second_smallest.py&lt;/a&gt;&lt;br/&gt;
&lt;i&gt;Alternate implementation using linked list:&lt;/i&gt; &lt;a href=&quot;https://github.com/n1balgo/algo/blob/master/second_smallest_linkedlist.py&quot;&gt;second_smallest_linkedlist.py&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/4741038432292026615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2008/12/finding-second-smallest-element.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/4741038432292026615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/4741038432292026615'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2008/12/finding-second-smallest-element.html' title='Finding Second Smallest Element'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-584799462191142009</id><published>2009-01-23T18:59:00.007-08:00</published><updated>2012-08-02T08:46:13.636-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>String Permutations</title><content type='html'>Printing all permutations of a string is a very common interview question. We&#39;ll discuss this problem and some interesting variations of it. The original problem of string permutation says, &quot;&lt;i&gt;print all permutations of a string&lt;/i&gt;&quot;. As an example, if the string is &quot;abc&quot; there are 6 permutations {abc, acb, bac, bca, cab, cba}. Assume that string contains no duplicate elements.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Solution:&lt;/span&gt; &lt;a href=&quot;#&quot; id=&quot;sp109_a&quot; onclick=&quot;return toggleMenuAdi(&#39;sp109_a&#39;,&#39;sp109_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;sp109_s&quot; style=&quot;display: none;&quot;&gt;There are many ways in which this problem can be solved. The most easiest of the ways is to code it using simple yet powerful recursion technique.&lt;br /&gt;
&lt;pre&gt;function permute(str, d)
  if d == length(str)
    print str
  else
    for i &amp;lt;- d to length(str)
      swap(str[d] &amp;lt;-&amp;gt; str[i]) // swap character for permutation
      permute(str, d + 1)
      swap(str[d] &amp;lt;-&amp;gt; str[i]) // undo swap for parent call
&lt;/pre&gt;Above code performs the swapping operation twice. First time to generate all possible permutations of character at that level and second time to restore to the original string. It is important to restore to the original string (as passed to this call), otherwise the algorithm ends up printing redundant permutations. Additionally, this code assumes that there are no duplicates in the string, else it fails. &lt;br /&gt;
&lt;br /&gt;
There are other ways in which string permutation can be printed that require circular shifting, but it cant get any simpler than above.&lt;/div&gt;&lt;br /&gt;
&lt;i&gt;Source Code&lt;/i&gt;: &lt;a href=&quot;https://github.com/n1balgo/algo/blob/master/permute_unique_chars.py&quot;&gt;permute_unique_chars.py&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Lets us assume that string can contain duplicates. How do we print all non-redundant permutations of the string. For ex. If string is &quot;abab&quot; the permutations are {baab, abba, abab, baba, bbaa, aabb}&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Solution:&lt;/span&gt; &lt;a href=&quot;#&quot; id=&quot;sp209_a&quot; onclick=&quot;return toggleMenuAdi(&#39;sp209_a&#39;,&#39;sp209_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;sp209_s&quot; style=&quot;display: none;&quot;&gt;Clearly the solution to first problem fails here. This is due to fact that we generate all permutations of the string after the swapping step. Same character could get swapped to dth spot again, leading to redundant permutations. A very simple trick solves the game. The trick is to &lt;span style=&quot;font-weight: bold;&quot;&gt;pre-sort&lt;/span&gt; the string on alphabetical order. Now we need to ensure that while we are swapping, to generate permutation for that particular character, if that matches the last swapped character we ignore generating permutations. Effectively, we are doing a cyclic shift and before the end of the call we reset the cyclic shift. The following code implements the same:&lt;br /&gt;
&lt;pre&gt;function permute(str, d)
  if d == length(str)
    print str
  else
    lastSwap = Nil
    for i &amp;lt;- d to length(str)
      if lastSwap == str[i]
        continue
      else
        lastSwap = str[i]

      swap(str[d] &amp;lt;-&amp;gt; str[i]) // swap character for permutation
      permute(str, d + 1)

    for i &amp;lt;- d to length(str)-1
       str[i] = str[i+1]
    str[length(str)] = last
&lt;/pre&gt;If the string is pre-sorted alphabetically then the above algorithm works magically. Note that in this case, after permute is called, we do not undo the swap. This ensures that we are cyclic shifting and hence the intermediate str from d to l is also sorted. After the for loop call, we reverse the cyclic shift. The reason is that sorting ensures that if there are duplicates then the second occurrence of the duplicate element is picked immediately after we finish generating permutations for the first occurrence of the duplicate element.   If sorting is not allowed, then you need to maintain a local hashtable (local to each function call), that maintains characters swapped to dth spot and ensures that duplicate candidates are discarded. Presort and make life simple.&lt;/div&gt;&lt;br /&gt;
&lt;i&gt;Source Code&lt;/i&gt;: &lt;a href=&quot;https://github.com/n1balgo/algo/blob/master/permute_chars.py&quot;&gt;permute_chars.py&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Some other constraints could be added to make the problem more interesting. One such constrain could be of partial ordering of characters. For Ex. &#39;a&#39; should appear before &#39;c&#39;, and &#39;b&#39; should appear before &#39;c&#39; in all permutations. There can exist ordering that leads to no permutation of the string such as &#39;a&#39; precedes &#39;b&#39;, &#39;b&#39; precedes &#39;c&#39;, &#39;c&#39; precedes &#39;a&#39;. Additionally implementing the permutation algorithm in these cases require checking for ordering violation at each permutation level or just at the leaf of recursion, depending on whether checking for ordering violations is more costly or generating all permutations. &lt;br /&gt;
&lt;br /&gt;
An interesting problem, that talks of special kind of ordering and can be very efficiently computed is as follows: Assume that the string is made up of equal number of &#39;{&#39; and &#39;}&#39;. You need to print all permutations of this string which could satisfy a C compiler i.e. an ending bracket is balanced by an opening bracket. For ex. for &#39;{{}}&#39; the permutations are [{{}}, {}{}].   &lt;span style=&quot;font-weight: bold;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;Solution:&lt;/span&gt; &lt;a href=&quot;#&quot; id=&quot;sp309_a&quot; onclick=&quot;return toggleMenuAdi(&#39;sp309_a&#39;,&#39;sp309_s&#39;);&quot;&gt;show&lt;/a&gt; &lt;br /&gt;
&lt;div id=&quot;sp309_s&quot; style=&quot;display: none;&quot;&gt;The hard question is how many such permutations exist. For N open and N close brackets, the number of such permutations is Nth Catalan number = 1/(n+1) * factorial(2*N)/factorial(N)^2. The solution is derived from the problem: &lt;a href=&quot;http://www.n1b-algo.blogspot.com/2012/07/number-of-paths-in-rectangular-grid.html&quot;&gt;Number of paths in rectangular grid&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Permutation problems can be easily solved using recursion. The trick is to formulate all the possible cases at a particular level and code according to the formulation. The steps used below illustrate this approach. Let&#39;s formulate the problem in general sense. Assume that at a given step of recursion, we have n open brackets and m closed brackets that are not used so far. Now we can formuate each and every case for a given (n,m) and code the possible substeps.&lt;br /&gt;
&lt;pre&gt;Problem Formulation:
(n,m) ---&amp;gt; NOT POSSIBLE,   if m &amp;lt; n
(n,m) ---&amp;gt; PRINT AND DONE, if m = 0 and n = 0
(n,m) ---&amp;gt; (n-1, m)        if n &amp;gt; 0   
              +
           (n, m-1)        if m &amp;gt; 0 and m &amp;gt; n&lt;/pre&gt;The above formulation is generic and takes into account all possible input values of (n,m). If we put following constraint on the initial value of n and m such as following, then actual implementation can omit some of the above cases:&lt;br /&gt;
&lt;pre&gt;Constraints: 
n &amp;gt; 0
m == n&lt;/pre&gt;The actual implementation that follows above constraints and problem formuation: &lt;br /&gt;
&lt;pre&gt;function permute(str, n, m)
  if m == 0
    print str
  else
    if n &amp;gt; 0
      permute (str + &#39;{&#39;, n - 1, m);

    if m &amp;gt; n
      permute (str + &#39;}&#39;, n, m - 1);
&lt;/pre&gt;To enforce the above mentioned constraints, permute function should be kept as inner/private function and the actual function that should be exposed is as follows:&lt;br /&gt;
&lt;pre&gt;function GenerateCStyleBrackets(N)
  if N &amp;lt;= 0
    return

  str = new String[2 * N]
  permute(str, N, N) // str is passed as pointer.&lt;/pre&gt;The memory cost is O(N). The maximum stack depth is also O(N). So total space cost is O(N).&lt;/div&gt;&lt;br /&gt;
&lt;i&gt;Source Code&lt;/i&gt;: &lt;a href=&quot;https://github.com/n1balgo/algo/blob/master/permute_brackets.py&quot;&gt;permute_brackets.py&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/584799462191142009/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/string-permutations.html#comment-form' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/584799462191142009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/584799462191142009'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/string-permutations.html' title='String Permutations'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-8700720063122659535</id><published>2009-01-22T21:01:00.011-08:00</published><updated>2010-03-27T11:31:38.699-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>Party Friends</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Problem:&lt;/span&gt; In any party, there exists two people with same number of friends. Is is true or false. Assume that party has more than one people.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution:&lt;/span&gt; &lt;a href=&quot;#&quot; id=&quot;pf09_a&quot; onclick=&quot;return toggleMenuAdi(&#39;pf09_a&#39;,&#39;pf09_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;pf09_s&quot; style=&quot;display:none&quot;&gt;Yes, The statement is true. We can prove it by contradiction. &lt;br /&gt;
&lt;br /&gt;
Let there be N people at the party. &lt;br /&gt;
Let all the N people have different number of friends. &lt;br /&gt;
&lt;br /&gt;
Since a person can have maximum of N-1 friends and a minimum of 0 friends. Hence the possible number of friends for a person is 0, 1, 2, ..., N-1. Since, we are assuming that there are no two people with same number of friends, so everyone has different number of friends. This means that someone has 0 friend, someone has 1 friend, so on and someone has N-1 friends. But 0 &amp; N-1 cannot coexist. This is because if a person has N-1 friends then that means he is friend with every one, including the one who has 0 friends, which is a contradiction. Hence by pigeon hole principle at least two people should have the same number of friends.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/8700720063122659535/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/party-friends.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/8700720063122659535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/8700720063122659535'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/party-friends.html' title='Party Friends'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-4253022370541528304</id><published>2009-01-18T21:30:00.017-08:00</published><updated>2012-07-21T16:20:49.395-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="puzzle"/><title type='text'>Innocents and Criminals: Finding Minority Entity</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Problem:&lt;/span&gt; There are two types of people in a particular city, innocents and criminals. All you know is that innocents are in majority and would like to get rid of criminals and criminals would like to protect themselves from persecution. You can ask &lt;span style=&quot;font-weight:bold;font-style:italic;&quot;&gt;any number&lt;/span&gt; of questions, with &lt;span style=&quot;font-weight:bold;font-style:italic;&quot;&gt;yes/no type answer&lt;/span&gt;, from any person in the city. Propose an algorithm which requires asking the minimum number of questions. &lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Hint:&lt;/span&gt; &lt;span style=&quot;color:white;&quot;&gt;Trivial solution requires asking O(n^2) questions. You can do it in less than 2n questions.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-weight:bold;&quot;&gt;Solution:&lt;/span&gt; &lt;a href=&quot;#&quot; id=&quot;iacfme09_a&quot; onclick=&quot;return toggleMenuAdi(&#39;iacfme09_a&#39;,&#39;iacfme09_s&#39;);&quot;&gt;show&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;iacfme09_s&quot; style=&quot;display:none&quot;&gt;The trivial solution is very simple and is in-fact O(n^2) time algorithm. Round up every person and ask him about the status of everyone else. People with majority vote of criminal are criminals and people with minority vote of criminal are innocents. Following code solves it:&lt;br /&gt;
&lt;pre&gt;for i = 1 to N
   for j = 1 to N
      if person[i].isCriminal(j)  // doesnt matter if i == j
         vote[j] += 1
      else
         vote[j] -= 1

for j &lt;- 1 to n 
   if vote[j] &gt; 0
      person[j].persecute()
&lt;/pre&gt;&lt;br /&gt;
The most efficient algorithm requires asking only 2N-2 questions. The key to solution of this problem lies in the solution to the problem of &lt;a href=&quot;http://n1b-algo.blogspot.com/2008/12/finding-majority-element.html&quot;&gt;Finding Majority Element&lt;/a&gt;. If we can find one innocent person in the city, then he can label everyone else truthfully. We know for sure that an innocent will tell the truth. Criminals can lie or say truth depending on circumstances.&lt;br /&gt;
&lt;br /&gt;
Assume that we formulate the problem this way. Let us consider a pool of people, who claim to be innocents. Also let us say that we declare that we will pick the first person in the pool to be our innocent man and he will reveal the identity of everyone else. Then definitely both innocents and criminals would try their best to capture the first spot in the pool.&lt;br /&gt;
&lt;br /&gt;
Now, we play a game like this. We choose a person randomly to represent the first person in the pool. Now we select a new person randomly and ask him should the last person inducted in the pool is Innocent. If he says Yes, then we add him to the pool. If he says No then we remove him and the last person from the pool and discard them from further selection. If the pool is empty we select a person not selected previously to get the first spot in the pool.&lt;br /&gt;
&lt;br /&gt;
We repeat the process until we don&#39;t have anymore people to consider. The intuition is that even if all Criminals join the pool initially (by lying), then innocents would boot them out as they are in majority. If more innocents join the pool initially then criminals will not be able to boot all innocents out. Hence the first person remaining in the pool is indeed an innocent. We can see this argument working inductively as well.&lt;br /&gt;
&lt;br /&gt;
The following code implements above logic with the help of a stack:&lt;br /&gt;
&lt;pre&gt;stack.push(person[1])
for i &lt;- 2 to N
   if !stack.isEmpty() &amp;&amp; person[i].isCriminal(stack.top())
      stack.pop()
   else
      stack.push(person[i])
return stack.bottom()
&lt;/pre&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/4253022370541528304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/innocents-and-criminals-finidng.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/4253022370541528304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/4253022370541528304'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/innocents-and-criminals-finidng.html' title='Innocents and Criminals: Finding Minority Entity'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-4271806807578546302</id><published>2009-01-16T17:24:00.010-08:00</published><updated>2014-07-16T16:43:05.241-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>Finding First Non-Zero Digit of N Factorial</title><content type='html'>Find the first non-zero digit of N!. Assume N! to be extremely large. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Solution:&lt;/b&gt;&lt;br /&gt;
If we assume that the product doesnt contain either of 2&#39;s and 5&#39;s, then finding last digit is trivial. Simple multiply the result with next number and take its mod 10. The problem is complicated as 2&#39;s and 5&#39;s lead to trailing 0&#39;s. So the first step is to remove 2&#39;s and 5&#39;s. Then solve the problem. The cancel 5&#39;s with 2&#39;s and multiply back the left over 2&#39;s. &lt;br /&gt;
&lt;br /&gt;
For Ex. 7! = 1 * 2 * 3 * 4 * 5 * 6 * 7. We extract 2&#39;s and 5&#39;s so the product is 1 * 3 * 3 * 7. The trailing digit is 3. We have extracted four 2&#39;s and one 5. So we get 3 extra 2&#39;s. So multiply to 3 we get 4 as the answer. To check 7! = 5040&lt;br /&gt;
&lt;pre&gt;d = 1&amp;nbsp;
n2 = 1&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;for i = 3 to n
  j = i

  while j%10 == 0 //remove trailing zeros
    j /= 10

  while j%2 == 0 //count of 2&#39;s
    j /= 2
    n2 += 1

  while j%5 == 0 //cancel a 5 with a 2
    j /= 5
    n2 -= 1    

  d = (d * j) % 10

d = (d * 2^n2) % 10 //multiply remaining 2&#39;s to d
return d&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/4271806807578546302/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/finding-first-non-zero-element-of-n.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/4271806807578546302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/4271806807578546302'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/finding-first-non-zero-element-of-n.html' title='Finding First Non-Zero Digit of N Factorial'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-6525443400109476624</id><published>2009-01-13T13:36:00.010-08:00</published><updated>2014-07-16T16:34:00.689-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>Count Trailing Zeros in N Factorial</title><content type='html'>How many trailing zeros does N factorial contain, for ex. 5! = 120 so ans is 1. Propose an algorithm to count trailing zeros. Assume that N! is very large and does not fit into word size of the computer.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Solution:&lt;/b&gt;&lt;br /&gt;
This problem is straight forward. N! = 1*2*3*4*5* .... *N. If we count all 5&#39;s in this product, then that many trailing zeros are there. This is because a 5 is countered by 2 to produce a zero. Additionally, there are more 2&#39;s than 5&#39;s so counting 5&#39;s gives the right answer. The following pseudo-code does that:  &lt;br /&gt;
&lt;pre&gt;count = 0
i = 5
while i &amp;lt;= n
  j = i
  while j%5 == 0
    j = j/5
    count += 1
  i += 5
return count&lt;/pre&gt;
This algorithm takes n/5 outer loop iterations and is bounded by log n [base=5] inner loop iterations, hence it takes O(n log n) time. We can clearly do better than this.&lt;br /&gt;
&lt;br /&gt;
Actually, we can solve this problem in O(log n) time. For a given i the term i/5 gives total number of 5&#39;s that come before it. For ex. 17/5 is 3, there are 3 numbers that contain fives which are less than 17 i.e. 5, 10, 15. So we count number of 5, then number of 25, then so on. &lt;br /&gt;
&lt;pre&gt;count = 0
d = r = 1
while r &amp;gt; 0
  d *= 5
  r = [n/d] // [x] is greatest integer less than x
  count += r
return count
&lt;/pre&gt;
This algorithm runs in O(log n) time and an asymptotic improvement on the previous algorithm.</content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/6525443400109476624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/count-trailing-zeros-in-n-factorial.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/6525443400109476624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/6525443400109476624'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/count-trailing-zeros-in-n-factorial.html' title='Count Trailing Zeros in N Factorial'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-759530137113893554.post-4387693824312284361</id><published>2009-01-12T13:49:00.006-08:00</published><updated>2014-07-16T16:27:18.854-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="maths"/><title type='text'>Picking k Elements Randomly from Stream</title><content type='html'>Consider the problem of picking K elements randomly from a stream of N elements. Solve the problem for known and unknown (but finite N). &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Solution:&lt;/b&gt;&lt;br /&gt;
For K=1, the solution is posted in my previous blog post &lt;a href=&quot;http://n1b-algo.blogspot.com/2009/01/picking-element-randomly-from-stream.html&quot;&gt;Picking an Element Randomly from Stream&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
Case 1: N is known&lt;br /&gt;
In this case problem can be solved in O(N) time using O(K) space. The idea is that pick the first element with probability K/N. If the element is picked then pick the next element with probability (K-1)/(N-1) otherwise pick it with probability K/(N-1). To see that the second element is still picked with probability K/N. There are two cases. &lt;br /&gt;
&lt;ol&gt;&lt;li&gt;First element is picked. So second element is picked with probability = K/N * (K-1)/(N-1). &lt;/li&gt;
&lt;li&gt;First element is not picked. So second element is picked with probability = (1-K/N) * K/(N-1).&lt;/li&gt;
&lt;/ol&gt;So the selection probability of second element is = K/N*(K-1)/(N-1) + (1-K/N)*K/(N-1) = K/N. Similar logic extends further. The following code implements this approach. &lt;br /&gt;
&lt;pre&gt;for i = 1 to N
   if rand &amp;lt;= K/(N+1-i)
      print A[i]
      K -= 1
      if K == 0
         break
      end
   end
end
if K != 0
  print A[N-K:N]
end
&lt;/pre&gt;Case 2: N is unknown. &lt;br /&gt;
If we do not know N beforehand, and yet we want to guarantee that all elements are selected with probability K/N, we can use &lt;a href=&quot;http://en.wikipedia.org/wiki/Reservoir_sampling&quot;&gt;Reservoir Sampling&lt;/a&gt; algorithm.&lt;br /&gt;
&lt;pre&gt;for i = 1:K
   S[i] = A[i]
end

for i = K+1:length(A)
   j = random(1,i)
   if j &amp;lt;= K
      S[j] = A[i]
   end 
end
&lt;/pre&gt;The first K elements of the stream are automatically selected. So for N = K this solves the problem. Now consider N = K+1. For i &amp;lt;= N-1 all elements are selected with probability 1 so far. The last element should be selected with probability K/N and so should others be. The index j is less than or equal to K with probability K/(K+1), so last element is rejected with probability 1/(K+1). For the elements in the array at index j they can be rejected if last element is accepted and its index is j. The chances of that is K/(K+1) * 1/K = 1/(K+1). So all elements are rejected with 1/(K+1) probability.   Now consider N = K+2. Until index i=K+1 all elements are rejected with probability 1/(K+1). Using same logic as we applied above, we can see that an element gets rejected with probability 2/(K+2).  </content><link rel='replies' type='application/atom+xml' href='http://n1b-algo.blogspot.com/feeds/4387693824312284361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/picking-k-elements-randomly-from-stream.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/4387693824312284361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/759530137113893554/posts/default/4387693824312284361'/><link rel='alternate' type='text/html' href='http://n1b-algo.blogspot.com/2009/01/picking-k-elements-randomly-from-stream.html' title='Picking k Elements Randomly from Stream'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>