Monday, January 27, 2014

[FW] How to Rock an Algorithms Interview, The Coding Interview

Link by KEVIN SIMLER :
http://www.palantir.com/2011/09/how-to-rock-an-algorithms-interview/
http://www.palantir.com/2011/10/the-coding-interview/#more-1925

Traveling salesman problem comic, originally from http://www.xkcd.com/399/
Comic courtesy of XKCD, via Creative Commons License
We do a lot of interviewing at Palantir, and let me tell you: it’s hard. I don’t mean that we ask tough questions (although we do). I mean that the task of evaluating a candidate is hard.
The problem? Given a whiteboard and one hour, determine whether the person across from you is someone you’d like to work with, in the trenches, for the next n years. A candidate’s performance during an interview is only weakly correlated with his or her true potential, but we’re stuck with the problem of turning the chickenscratch on the whiteboard into an ‘aye’ or ‘nay’. Sometimes it feels like a high-stakes game of reading tea leaves. Believe me we’re doing our best, but we’re often left with the nagging worry that we’re passing up brilliant people who just had a bad day or who didn’t click with a particular problem.
In an effort to improve this situation, we wanted to write up a guide that will help candidates make sense of this process, or at least the part known as an Algorithms Interview. At Palantir we ask questions that test for a lot of different skills — coding, design, systems knowledge, etc. — but one of our staple interviews is to ask you to design an algorithm to solve a particular problem.
It usually starts like this:
Given X, figure out an efficient way to do Y.
First: Make sure you understand the problem. You’re not going to lose points asking for clarifications or talking through the obvious upfront. This will also buy you time if your brain isn’t kicking in right away. Nobody expects you to solve a problem in the first 30 seconds or even the first few minutes.
Once you understand the problem, try to come up with a solution – any solution whatever. As long as it’s valid, it doesn’t matter if your solution is trivial or ugly or extremely inefficient. What matters is that you’ve made progress. This does two things: (1) it forces you to engage with the structure of the problem, priming your brain for improvements you can make later, and (2) it gives you something in the bank, which will in turn give you confidence. If you can achieve a brute force solution to a problem, you’ve cleared a major hurdle to solving it in a more efficient way.
Now comes the hard part. You’ve given an O(n^3) solution and your interviewer asks you to do it faster. You stare at the problem, but nothing’s coming to you. At this point, there are a few different moves you can make, depending on the problem at hand and your own personality. Almost all of these can help on almost any problem:
  1. Start writing on the board. This may sound obvious, but I’ve had dozens of candidates get stuck while staring at a blank wall. Maybe they’re not visual people, but still I think it’s more productive to stare at some examples of the problem than to stare at nothing. If you can think of a picture that might be relevant, draw it. If there’s a medium-sized example you can work through, go for it. (Medium-sized is better than small, because sometimes the solution to a small example won’t generalize.) Or just write down some propositions that you know to be true. Anything is better than nothing.

  2. Talk it through. And don’t worry about sounding stupid. If it makes you feel better, tell your interviewer, “I’m just going to talk out loud. Don’t hold me to any of this.” I know many people prefer to quietly contemplate a problem, but if you’re stuck, talking is one way out of it. Sometimes you’ll say something that clearly communicates to your interviewer that you understand what’s going on. Even though you might not put much stock in it, your interviewer may interrupt you to tell you to pursue that line of thinking. Whatever you do, please DON’T fish for hints. If you need a hint, be honest and ask for one.

  3. Think algorithms. Sometimes it’s useful to mull over the particulars of the problem-at-hand and hope a solution jumps out at you (this would be a bottom-up approach). But you can also think about different algorithms and ask whether each of them applies to the problem in front of you (a top-down approach). Changing your frame of reference in this way can often lead to immediate insight. Here are some algorithmic techniques that can help solve more than half the problems we ask at Palantir:
    • Sorting (plus searching / binary search)
    • Divide-and-conquer
    • Dynamic programming / memoization
    • Greediness
    • Recursion
    • Algorithms associated with a specific data structure (which brings us to our fourth suggestion…)

  4. Think data structures. Did you know that the top 10 data structures account for 99% of all data structure use in the real world? Probably not, because I just made those numbers up — but they’re in the right ballpark. Yes, on occasion we ask a problem whose optimal solution requires a Bloom filter or suffix tree, but even those problems tend to have a near-optimal solution that uses a much more mundane data structure. The data structures that are going to show up most frequently are:
    • Array
    • Stack / Queue
    • Hashset / Hashmap / Hashtable / Dictionary
    • Tree / binary tree
    • Heap
    • Graph
    You should know these data structures inside and out. What are the insertion/deletion/lookup characteristics? (O(log n) for a balanced binary tree, for example.) What are the common caveats? (Hashing is tricky, and usually takes O(k) time when k is the size of the object being hashed.) What algorithms tend to go along with each data structure? (Dijkstra’s for a graph.) But when you understand these data structures, sometimes the solution to a problem will pop into your mind as soon as you even think about using the right one.

  5. Think about related problems you’ve seen before and how they were solved. Chances are, the problem you’ve been presented is a problem that you’ve seen before, or at least very similar. Think about those solutions and how they can be adapted to specifics of the problem at hand. Don’t get tripped up by the form that the problem is presented – distil it down to the core task and see if matches something you’ve solved in the past.

  6. Modify the problem by breaking it up into smaller problems. Try to solve a special case or simplified version of the problem. Looking at the corner cases is a good way to bound the complexity and scope of the problem. A reduction of the problem into a subset of the larger problem can give a base to start from and then work your way up to the full scope at hand.
    Looking at the problem as a composition of smaller problems may also be helpful. For example, “find a number in a sorted array which has been shifted cyclically by an unknown constant k” can be solved by (1) first figuring out “k” and then (2) figuring out how to perform binary search on a shifted array).

  7. Don’t be afraid to backtrack. If you feel like a particular approach isn’t working, it might be time to try a different approach. Of course you shouldn’t give up too easily. But if you’ve spent a few minutes on an approach that isn’t bearing any fruit and doesn’t feel promising, back up and try something else. I’ve seen more candidates who overcommit than undercommit, which means you should (all else equal) be a little more willing to abandon an unpromising approach.
Incidentally, trying out a few different approaches (rather than sticking with a single approach) tends to work well in interviews, because the problems we choose for an interview usually have many different solutions. Happily, the same is true for the problems we solve on the job =)

Note: this part is part two of our series on doing your best in interviews. Part one: “How to Rock an Algorithms Interview”.
Here at Palantir algorithms are important, but code is our lifeblood. We live and die by the quality of the code we ship. It’s no surprise, then, that coding ability is what we stress the most in our interview process. A candidate can get by with mediocre algorithm skills (depending on the role), but no one can skimp on coding.
Suppose you’re confident in your ability to write great software. Your task in a coding interview (of which there will be several) is to show the interviewers that you in fact do have the programming chops — that you’re an experienced coder who knows how to write solid, production-quality code.
This is easier said than done. After all, coding in your favorite IDE from the comfort of$familiar_place is very different from coding on a whiteboard (on a problem you’re totally unfamiliar with) in a pressure-filled 45-minute interview. We realize that the interview environment is not the real world, and we adjust our expectations accordingly. Nonetheless, there are a number of things you can do to put your best foot forward during the interview.
First, though, we’d like to give you a sense for what we look for during a coding interview. Most important is the ability to write clean and correct code — it’s not enough just to be correct. A lot of people will be interacting with your code once you’re on the job, so it should be readable, maintainable, and extensible where appropriate. If your solution is clean and correct, and you produced it in a reasonable amount of time without a lot of help, you’re in good shape. But even if you stumble a bit, there are other ways to demonstrate your ability. As you work, we also watch for debugging ability, problem-solving and analytical skills, creativity, and an understanding of the ecosystem that surrounds production code.
With our evaluation criteria in mind, here are some suggestions we hope will help you perform at your very best.

Before you start coding

  • Make sure you understand the problem. Don’t hesitate to ask questions. Specifically, if any of the problem requirements seem loosely defined or otherwise unclear, ask your interviewer to make things more concrete. There is no penalty for asking for clarifications, and you don’t want to miss a key requirement or proceed on unfounded assumptions.
  • Work through simple examples. This can be useful both before you begin and after you’ve finished coding. Working through simple examples before coding can give you additional clarity on the nature of the problem — it may help you notice additional cases or patterns in the problem that you would otherwise have missed had you been thinking more abstractly.
  • Make a plan. Be wary of jumping into code without thinking about your program’s high-level structure. You don’t have to work out every last detail (this can be difficult for more meaty problems), but you should give the matter sufficient thought. Without proper planning, you may be forced to waste your limited time reworking significant parts of your program.
  • Choose a language. At Palantir, we don’t care what languages you know as long as you have a firm grasp on the fundamentals (decomposition, object-oriented design, etc.). That said, you need to be able to communicate with your interviewer, so choose something that both of you can understand. In general, it’s easier for us if you use Java or C++, but we’ll try to accommodate other languages. If all else fails,devise your own pseudo-code. Just make sure it’s precise (i.e. not hand-wavy) and internally consistent, and explain your choices as you go.

While you’re coding

  • Think out loud. Explain your thought process to your interviewer as you code. This helps you more fully communicate your solution, and gives your interviewer an opportunity to correct misconceptions or otherwise provide high-level guidance.
  • Break the problem down and define abstractions. One crucial skill we look for is the ability to handle complexity by breaking problems into manageable sub-problems. For anything non-trivial, you’ll want to avoid writing one giant, monolithic function. Feel free to define helper functions, helper classes, and other abstractions to reach a working solution. You can leverage design patterns or other programming idioms as well. Ideally, your solution will be well-factored and as a result easy to read, understand, and prove correct.
  • Delay the implementation of your helper functions. (this serves a corollary to the previous point) Write out the signature, and make sure you understand the contract your helper will enforce, but don’t implement it right away. This serves a number of purposes: (1) it shows that you’re familiar with abstractions (by treating the method as an API); (2) it allows you to maintain momentum towards the overall solution; (3) it results in fewer context-switches for your brain (you can reason about each level of the call stack separately); and (4) your interviewer may grant you the implementation for free, if he or she considers it trivial.
  • Don’t get caught up in trivialities. At Palantir we are much more interested in your general problem solving and coding abilities than your recall of library function names or obscure language syntax. If you can’t remember exactly how to do something in your chosen language, make something up and just explain to your interviewer that you would look up the specifics in the documentation. Likewise, if you utilize an abstraction or programming idiom which admits a trivial implementation, don’t be afraid to just write out the interface and omit the implementation so you can concentrate on more important aspects of the problem (e.g., “I’m going to use a circular buffer here with the following interface without writing out the full implementation”).

Once you have a solution

  • Think about edge cases. Naturally, you should strive for a solution that’s correct in all observable aspects. Sometimes there will be a flaw in the core logic of your solution, but more often your only bugs will be in how you handle edge cases. (This is true of real-world engineering as well.) Make sure your solution works on all edge cases you can think of. One way you can search for edge-case bugs is to…
  • Step through your code. One of the best ways to check your work is to simulate how your code executes against a sample input. Take one of your earlier examples and make sure your code produces the right result. Huge caveat here: when mentally simulating how your code behaves, your brain will be tempted to project what it wants to happen rather than what actually says happen. Fight this tendency by being as literal as possible. For example, if you’re calculating a string index with code likestr.length()-suffix.length(), don’t just assume you know where that index will land; actually do the math and make sure the value is what you were hoping for.
  • Explain the shortcuts you took. If you skipped things for reasons of expedience that you would otherwise do in a “real world” scenario, please let us know what you did and why. For example, “If I were writing this for production use, I would check an invariant here.” Since whiteboard coding is an artificial environment, this gives us a sense for how you’ll treat code once you’re actually on the job.
As an addendum, here are a few suggestions for books we like about the art of software construction:

[LeetCode] Maximal Rectangle


Link : http://oj.leetcode.com/problems/maximal-rectangle/

More information:
http://dp2.me/blog/?p=482

Thanks for your help. --> 无齿的兔子, 鹿杖客


 
#include <iostream>
#include <vector>

class Solution {
    public:
    int maximalRectangle(std::vector<std::vector<char> > &matrix) {
        int n = matrix.size();
        if(n==0) return 0;
        int m = matrix[0].size();
        if(m==0) return 0;
        std::vector<int> height(m, 0);
        std::vector<int> left(m, 0);
        std::vector<int> right(m, 0);
        int maxArea = 0;
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<m; j++)
            {
                height[j] = (matrix[i][j]=='1')? height[j]+1 : 0;
                left[j] = j;
                while(left[j]>0 && height[left[j]-1]>=height[j])
                left[j] = left[left[j]-1];
            }
            for(int j=m-1; j>=0; j--)
            {
                right[j] = j;
                while(right[j]<m-1 && height[j]<=height[right[j]+1])
                right[j] = right[right[j]+1];
            }
            for(int j=0; j<m; j++)
            maxArea = std::max(maxArea, (right[j]-left[j]+1)*height[j]);
        }
        return maxArea;
    }
};

Friday, January 24, 2014

[LeetCode] Classification

Sorting is enabled. Please click on the title to sort by specific column
Problem Classification Method
Evaluate Reverse Polish Notation Math Stack
Max Points on a Line Count Map
Sort List List, BST, Graph Merge Sort
LRU Cache Design Map, List
Binary Tree Postorder Traversal List, BST, Graph Stack
Binary Tree Preorder Traversal List, BST, Graph Stack
Reorder List List, BST, Graph Divide
Linked List Cycle II List, BST, Graph Two Pointers
Linked List Cycle List, BST, Graph Two Pointers
Word Break II List, BST, Graph DP
Word Break List, BST, Graph DP
Copy List with Random Pointer List, BST, Graph MAP, Copy&Break
Single Number II Math Bit
Single Number Math Bit
Candy Math Stack
Gas Station Math DP
Clone Graph List, BST, Graph Map
Palindrome Partitioning II String DP
Palindrome Partitioning String DP
Surrounded Regions List, BST, Graph BST
Sum Root to Leaf Numbers List, BST, Graph DSF
Longest Consecutive Sequence Math Set
Word Ladder II List, BST, Graph BST
Word Ladder List, BST, Graph BST
Valid Palindrome String Two Pointers
Binary Tree Maximum Path Sum List, BST, Graph DFS
Best Time to Buy and Sell Stock III Array Stack, DP
Best Time to Buy and Sell Stock II Array
Best Time to Buy and Sell Stock Array
Triangle Math DP
Pascal's Triangle II Math DP
Pascal's Triangle Math DP
Populating Next Right Pointers in Each Node II List, BST, Graph Two Pointers
Populating Next Right Pointers in Each Node List, BST, Graph Two Pointers
Distinct Subsequences String DP
Flatten Binary Tree to Linked List List, BST, Graph DFS, Wrapper
Path Sum II List, BST, Graph DFS
Path Sum List, BST, Graph DFS
Minimum Depth of Binary Tree List, BST, Graph DFS
Balanced Binary Tree List, BST, Graph DFS
Convert Sorted List to Binary Search Tree List, BST, Graph Divide and Conquer
Convert Sorted Array to Binary Search Tree List, BST, Graph Divide and Conquer
Binary Tree Level Order Traversal II List, BST, Graph List
Construct Binary Tree from Inorder and Postorder Traversal List, BST, Graph Divide and Conquer
Construct Binary Tree from Preorder and Inorder Traversal List, BST, Graph Divide and Conquer
Maximum Depth of Binary Tree List, BST, Graph DFS
Binary Tree Zigzag Level Order Traversal List, BST, Graph BSF, List
Binary Tree Level Order Traversal List, BST, Graph BSF, List
Symmetric Tree List, BST, Graph DFS, Divide & Conquer
Same Tree List, BST, Graph DFS, Divide & Conquer
Recover Binary Search Tree List, BST, Graph DFS, In-Order, Store
Recover Binary Search Tree List, BST, Graph DFS, In-Order, Store
Validate Binary Search Tree List, BST, Graph DFS, In-Order, Store
Interleaving String String DP
Unique Binary Search Trees II String DP
Unique Binary Search Trees String DFS, Divide & Conquer
Binary Tree Inorder Traversal String DFS, Divide & Conquer
Restore IP Addresses String DFS
Reverse Linked List II List, BST, Graph Two Pointers
Subsets II List, BST, Graph DFS
Decode Ways String, List, BST, Graph DFS
Gray Code Math, String, List, BST, Graph DFS, Math
Merge Sorted Array Sort Merge Sort
Scramble String String, List, BST, Graph DFS
Partition List List, BST, Graph Two Pointers
Maximal Rectangle List, BST, Graph DP
Largest Rectangle in Histogram List, BST, Graph DP
Remove Duplicates from Sorted List II List, BST, Graph Two Pointers
Remove Duplicates from Sorted List List, BST, Graph Two Pointers
Search in Rotated Sorted Array II List, BST, Graph Divided & Conquer, Binary Search
Remove Duplicates from Sorted Array II List, BST, Graph Two Pointers
Word Search List, BST, Graph DFS
Subsets List, BST, Graph DFS
Combinations List, BST, Graph DFS
Minimum Window Substring String, List, BST, Graph Count
Sort Colors Sort, List, BST, Graph Two Pointers
Search a 2D Matrix List, BST, Graph Binary Search, Transformation
Set Matrix Zeroes other other
Edit Distance String, List, BST, Graph DP
Simplify Path String, List, BST, Graph DP, Stack
Climbing Stairs List, BST, Graph DP
Sqrt(x) Math Binary Search, Bit Manipulation
Text Justification String Other
Plus One Math Other
Valid Number String Other
Merge Two Sorted Lists List, BST, Graph Merge Sort
Minimum Path Sum List, BST, Graph DFS
Unique Paths II List, BST, Graph DP
Unique Paths List, BST, Graph DP
Rotate List List, BST, Graph Two Pointers
Permutation Sequence Math Bit Manipulation
Spiral Matrix II Other Other
Length of Last Word String Other
Insert Interval Other Other
Merge Intervals Other Other
Jump Game List, BST, Graph DP
Spiral Matrix Other Other
Maximum Subarray List, BST, Graph DP
N-Queens II List, BST, Graph DFS
N-Queens List, BST, Graph DFS
Pow(x, n) Math Bit Manipulation
Anagrams String Count
Rotate Image Other Other
Permutations II Math Other
Permutations Math Other
Jump Game II List, BST, Graph DP
Wildcard Matching String, Pattern Greedy
Multiply Strings Math Other
Trapping Rain Water Math DP
First Missing Positive Math Two Pointers
Combination Sum II Math DP
Combination Sum Math DP
Count and Say String DP
Sudoku Solver List, BST, Graph Other
Valid Sudoku List, BST, Graph DFS
Search Insert Position List, BST, Graph Binary Search
Search for a Range List, BST, Graph Binary Search
Search in Rotated Sorted Array List, BST, Graph Binary Search
Longest Valid Parentheses String, List, BST, Graph DP
Next Permutation Math Other
Substring with Concatenation of All Words String, List, BST, Graph DFS
Divide Two Integers Math Bit Manipulation
Implement strStr() String, Pattern Brute Force, KMP
Remove Element List, BST, Graph Two Pointers
Remove Duplicates from Sorted Array List, BST, Graph Two Pointers
Reverse Nodes in k-Group List, BST, Graph Two Pointers
Swap Nodes in Pairs List, BST, Graph Two Pointers
Merge k Sorted Lists List, BST, Graph Heap, Compare
Generate Parentheses String, List, BST, Graph DP
Valid Parentheses String, List, BST, Graph Stack
Remove Nth Node From End of List List, BST, Graph Two Pointers
Letter Combinations of a Phone Number String, List, BST, Graph DFS, Backtrace
Letter Combinations of a Phone Number String, List, BST, Graph DFS, Backtrace
4 Sum Math, Combination Two Pointers
3 Sum Closest Math, Combination Two Pointers
3 Sum Math, Combination Two Pointers
Longest Common Prefix String, List, BST, Graph
Roman to Integer String Other, Pattern
Integer to Roman String Other, Pattern
Container With Most Water List, BST, Graph Two Pointers, Other
Regular Expression Matching String, List, BST, Graph DFS, Greedy
Palindrome Number String, List, BST, Graph Two Pointers
String to Integer (atoi) String Other
Reverse Integer Math Overflow
ZigZag Conversion Other Other
Longest Palindromic Substring String DP, Manacher's Algorithm
Add Two Numbers Other Other
Longest Substring Without Repeating Characters String Two Pointers
Median of Two Sorted Arrays Math Divide & Conquer
2 Sum Math Two Pointers




[LeetCode] LRU Cache


 
class LRUCache{
    public:
    typedef std::pair<int, int> ENTRY;
    LRUCache(int capacity) {
        max = capacity;
        count = 0;
    }
    
    int get(int key) {
        if(map.find(key)==map.end())
        return -1;
        else
        {
            entry.splice(entry.begin(), entry, map[key]);
            return (map[key])->second;
        }
    }
    
    void set(int key, int value) {
        if(map.find(key)==map.end())
        {
            entry.push_front(ENTRY(key, value));
            map[key] = entry.begin();
            if(++count>max)
            {
                int tmp = entry.back().first;
                entry.erase(--entry.end());
                count--;
                map.erase(tmp);
            }
        }
        else
        {
            entry.splice(entry.begin(), entry, map[key]);
            map[key]->second = value;
        }
    }
    
    int count;
    int max;
    std::list<std::pair<int, int>> entry;
    std::unordered_map<int, std::list<std::pair<int, int>>::iterator> map;
};

[LeetCode] Reorder List

Link : http://oj.leetcode.com/problems/reorder-list/

Analysis :
Two pointers, head and tail

head pointer : scans from the start
tail pointer  : first dig into the list until and last one. From there tail behaves as the node pointer pointing to the last node

head and tail scan from two ends and modify the link list as expected.
Be careful of the stop case.
 
/**
* Definition for singly-linked list.
* struct ListNode {
    *     int val;
    *     ListNode *next;
    *     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
    public:
    void reorderList(ListNode *head) {
        if(head==NULL)
            return;
        int n=0;
        ListNode dummy(0);
        dummy.next = head;
        ListNode * cursor = &dummy;
        reorder(cursor, cursor);
    }
    
    bool reorder(ListNode*& head, ListNode* tail)
    {
        // base case
        if(tail->next==NULL)
            return true;
        // tail point to second to last node
        
        // stop case
        if(!reorder(head, tail->next)||head==tail||head->next==tail);
            return false;
        ListNode* tmp = tail->next;
        tail->next=NULL;
        
        tmp->next = head->next;
        head->next = tmp;
        
        head = head->next->next;
        return true;
    }
};

Thursday, January 23, 2014

[LeetCode] Sort List


Link : http://oj.leetcode.com/problems/sort-list/
Sort a linked list in O(n log n) time using constant space complexity.

iterative version of merge sort.
Code is ugly and needs substantial modification.
class Solution {
    public:
    
    ListNode *sortList(ListNode *head) {
        if(!head) return NULL;
        ListNode dummy(0);
        dummy.next = head;
        // get length
        int n=0;
        ListNode* cursor=&dummy;
        ListNode* tmp;
        while(cursor->next) { n++; cursor=cursor->next; }
        
        ListNode* current_first=head;
        ListNode* next_first=NULL;
        
        ListNode* merge_head=NULL;
        ListNode* merge_tail=NULL;
        
        // scan using different step
        for(int step=1; step<n; step*=2)
        {
            // initialization
            cursor = &dummy;
            current_first = dummy.next;
            // for each step, merge two adjacent sub lists
            for(int i=0; i<n; i+=step*2)
            {
                next_first = moveNode(current_first, step*2-1);
                if(next_first) // cut link between different sub list
                {
                    tmp = next_first->next;
                    next_first->next = NULL;
                    next_first = tmp;
                }
                merge(current_first, step, merge_head, merge_tail);
                cursor->next = merge_head; // concatenation
                cursor = merge_tail; // ready for next concatenation
                current_first = next_first; // ready for next merge
            }
        }
        return dummy.next;
    }
    
    ListNode* moveNode(ListNode* p, int step)
    {
        while(step-->0&&p) p=p->next;
        return p;
    }
    
    void merge(ListNode* head, int step, ListNode*& merge_head, ListNode*& merge_tail)
    {
        if(head==NULL) return;
        ListNode dummy(0);
        ListNode* tmp;
        
        ListNode* cursor = &dummy;
        ListNode* l1 = head;
        // get second sub-list
        ListNode* l2 = head;
        // get the node pointing to the head of second sub-list
        l2 = moveNode(l2, step-1);
        if(l2) // cut link between different sub list
        {
            tmp = l2->next;
            l2->next = NULL;
            l2 = tmp;
        }
        
        while(l1||l2)
        {
            if((l1&&!l2)||(l1&&l2&& l1->val <= l2->val))
            {
                tmp = l1->next;
                l1->next=NULL;
                cursor->next = l1;
                
                l1=tmp;
                cursor=cursor->next;
            }
            else
            {
                tmp = l2->next;
                l2->next=NULL;
                cursor->next = l2;
                
                l2=tmp;
                cursor=cursor->next;
            }
        }
        merge_head = dummy.next;
        merge_tail = cursor;
    }
    
};

[LeetCode] Binary Tree Preorder Traversal


/**
* Definition for binary tree
* struct TreeNode {
    *     int val;
    *     TreeNode *left;
    *     TreeNode *right;
    *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };


class Solution {
public:
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> ret;
        if(root==NULL)
            return ret;
        std::stack<TreeNode*> ss;
        ss.push(root);
        TreeNode* node;
        while(ss.size()>0)
        {
            node = ss.top();
            ss.pop();
            ret.push_back(node->val);
            if(node->right)
                ss.push(node->right);
            if(node->left)
                ss.push(node->left);
            
        }
        return ret;
    }
};

[LeetCode] Binary Tree Postorder Traversal


/**
* Definition for binary tree
* struct TreeNode {
    *     int val;
    *     TreeNode *left;
    *     TreeNode *right;
    *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
    public:
    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> ret;
        if(root==NULL)
            return ret;
        TreeNode* current;
        stack<TreeNode*> s;
        s.push(root);
        while(s.size()>0)
        {
            current = s.top();
            s.pop();
            if(current==NULL)
            {
                current = s.top();
                s.pop();
                ret.push_back(current->val);
                continue;
            }
            s.push(current);
            s.push(NULL);
            if(current->right)
                s.push(current->right);
            if(current->left)
                s.push(current->left);
        }
        return ret;
    }
};

Wednesday, January 22, 2014

user defined hash function in C++ STL unordered_map and unordered_set

Reference :
http://mikecvet.wordpress.com/2011/01/28/customizing-tr1-unordered_map-hashing-and-equality-functions/
http://en.cppreference.com/w/cpp/utility/hash
http://stackoverflow.com/questions/17016175/c-unordered-map-using-a-custom-class-type-as-the-key

 template<class Key,
         class T,
         class Hash = hash<Key>,
         class Pred = std::equal_to<Key>,
         class Alloc = std::allocator<std::pair<const Key, T> > >


typedef struct
{
  long operator() (const AggregateKey &k) const { return my_hash_fnct (k); }
} AggregateKeyHash;
typedef struct
{
  bool operator() (const AggregateKey &x, const AggregateKey &y) const { return my_eq_test (x, y); }
} AggregateKeyEq;
AggregateKey k;
{...}
// Now, hash value generation and equality&nbsp;testing are
// defined for the AggregateKeyHash&nbsp;type, so declare the
// map using the functors&nbsp;above in the object's template list
std::tr1::unordered_map<AggregateKey, int, AggregateKeyHash, AggregateKeyEq> M;
M[k] = 1;
{...}


std::tr1::unordered_map<int, int> M;
const std::tr1::unordered_map<int, int>::hasher &hfn = M.hash_function ();
const std::tr1::unordered_map<int, int>::key_equal &eqfn = M.key_eq ();
long h = hfn (123);
bool b = eqfn (1, 2);






struct Key{
  std::string first;
  std::string second;
  int         third;

  bool operator==(const Key &other) const
  { return (first == other.first
            && second == other.second
            && third == other.third);
  }
};
namespace std {

  template <>
  struct hash<Key>
  {
    std::size_t operator()(const Key& k) const
    {
      using std::size_t;
      using std::hash;
      using std::string;

      // Compute individual hash values for first,
      // second and third and combine them using XOR
      // and bit shifting:

      return ((hash<string>()(k.first)
               ^ (hash<string>()(k.second) << 1)) >> 1)
               ^ (hash<int>()(k.third) << 1);
    }
  };

}
int main()
{
  std::unordered_map<Key,std::string> m6 = {
    { {"John", "Doe", 12}, "example"},
    { {"Mary", "Sue", 21}, "another"}
  };
}


struct Key{
  std::string first;
  std::string second;
  int         third;

  bool operator==(const Key &other) const
  { return (first == other.first
            && second == other.second
            && third == other.third);
  }
};
struct KeyHasher
{
  std::size_t operator()(const Key& k) const
  {
    using std::size_t;
    using std::hash;
    using std::string;

    return ((hash<string>()(k.first)
             ^ (hash<string>()(k.second) << 1)) >> 1)
             ^ (hash<int>()(k.third) << 1);
  }
};

int main()
{
  std::unordered_map<Key,std::string,KeyHasher> m6 = {
    { {"John", "Doe", 12}, "example"},
    { {"Mary", "Sue", 21}, "another"}
  };
}