Monday, November 24, 2014

Word Ladder

Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:
  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.
Note:
  • Return 0 if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
Idea: Use BFS.
To do: make it more concise.
class Solution {
public:
  int ladderLength(string start, string end, unordered_set<string> &dict) {
   queue<string> curLevel;
   queue<string> nextLevel;
   string mid = start;
   bool find = false;
   string oStart = start;
   curLevel.push(start);
   int c = 1;
   while (!curLevel.empty() || !nextLevel.empty())
   {
    if (curLevel.empty())
    {
     curLevel.swap(nextLevel);
     c++;
    }
    start = curLevel.front();
    curLevel.pop();
    if (start == end)
    {
     find = true;
     break;
    }
    int n = start.size();
    for (int i = 0; i < n; i++)
    {
     for (int j = 0; j < 26; j++)
     {
      mid = start;
      if (start[i] != 'a' + j)
      {
       mid[i] = 'a' + j;
       if (dict.find(mid) != dict.end() || mid == end)  // To push the last element into the queue!
       {
        nextLevel.push(mid);
        if (dict.find(mid) != dict.end())
         dict.erase(mid); //
we need to get rid of the visited word to avoid circles.
       }
       else
       {
        continue;
       }
      }
     }
    }
   }
   if (find)
    return c;
   else
    return 0;
  }
};

Friday, November 21, 2014

Letter Combinations of a Phone Number

Given a digit string, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below.

Input:Digit string "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
Note:
Although the above answer is in lexicographical order, your answer could be in any order you want.

1. Backtracking:
My first answer was wrong and I started to realize I hadn't quite understood the essence of backtracking.

http://stackoverflow.com/questions/27069642/passing-parameter-recursion-c-letter-combinations-of-a-phone-number

class Solution {
public:
    const vector<string> keyboard { " ", "", "abc", "def", // '0','1','2',...
        "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };
       
    vector<string> letterCombinations(string digits) {
      
        vector<string> res;
        string combo;
        bt( res, combo,digits);
        return res;
    }
   
  void bt(vector<string> &res, string combo, string digits)
  {
      int i=combo.size();
      int len =digits.size();
   if ( i == len)
   {
    res.push_back(combo);
   
    return;
   }
   int idx = digits[i] - '0';
   string tmp = keyboard[idx];
   int s = tmp.size();
   for (int j = 0; j<s; j++)
   {
    bt(res, combo + tmp[j], digits);
   }
  }
};

2. Iterative
 class Solution {
public:
    const vector<string> keyboard { " ", "", "abc", "def", // '0','1','2',...
        "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };
       
    vector<string> letterCombinations(string digits) {
      
        vector<string> res(1, "");
        string combo;
       
        int n=digits.size();
        vector<string> tmp;
        for(int i=0; i<n; i++)
        {
            int m = keyboard[digits[i]-'0'].size();
            int rsize =res.size();
            for (int k=0; k<rsize; k++)
            {
                string ts = res[k];
                for (int j=0; j<m; j++)
                   {
                    res[k] = res[k] + keyboard[digits[i]-'0'][j];
                    tmp.push_back(res[k]);
                    res[k] = ts;
                   }
            }
            res = tmp;
            tmp.clear();
        }
        return res;
    }
};

Wednesday, November 19, 2014

Combinations

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
For example,
If n = 4 and k = 2, a solution is:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

For what permutations and combinations are, this is a good explanation:

http://betterexplained.com/articles/easy-permutations-and-combinations/

This problem has been asked on the internet a lot.
http://stackoverflow.com/questions/127704/algorithm-to-return-all-combinations-of-k-elements-from-n

Recursion and backtracking is a way to do it.

http://stackoverflow.com/questions/9552295/using-recursion-and-backtracking-to-generate-all-possible-combinations

class Solution {
public:
    vector<vector<int> > combine(int n, int k) {
        vector<vector<int>> res;
        if (n==0||k==0) return res;
        vector<int> path;
        bt(n, k, 1, 0, res, path);
        return res;
    }
   
    void bt(int n, int k, int start, int cur, vector<vector<int>> &r, vector<int> &p)
    {
        if (k==cur)
        {
            r.push_back(p);
            return;
        }
        else
        {
            for (int i=start; i<=n; i++)
            {
                p.push_back(i);
                bt(n,k,i+1,cur+1, r, p);
                p.pop_back();
            }
        }
    }
};


TO add iterative solution later.

Tuesday, November 18, 2014

Permutations

This is a very interesting article on permutations.

http://wordaligned.org/articles/next-permutation

For this problem, permutations is basically switching all the elements. See below for more details.
Permutations
Given a collection of numbers, return all possible permutations.
For example,
[1,2,3] have the following permutations:
[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1].

Idea: We start from the head element and will be exchange it with the other elements one by one while backtracking till the end.

class Solution {
public:
    vector<vector<int> > permute(vector<int> &num) {
        int n = num.size();
       
        vector<vector<int>> ret;
        bt(ret, num,0,n-1);
       
        return ret;
    }
   
    void bt(vector<vector<int>> &r,  vector<int> num, int k, int n)
    {
        if (k==n)
        {
            r.push_back(num);
        }
        else
        {
            for (int i=k;i<=n;i++)
            {
                //switch num[i] and num[k]
                int tmp = num[i];
                num[i] = num[k];
                num[k] = tmp;
               
                bt(r,num, k+1,n);
            }
        }
    }
};

What if there are duplicates? We need to decide when to do the switches.

class Solution {
public:
    vector<vector<int> > permuteUnique(vector<int> &num) {
        vector<vector<int> > ret;
        int n = num.size();
        perm(num,0,n-1,ret);
        return ret;
    }
   
    bool swap(int k, int i, const vector<int> num){
        for (int j=k;j<i;j++){
            if (num[j]==num[i]){
                return false;
            }
        }
        return true;
    }

 
    void perm(vector<int> num, int k, int n, vector<vector<int>> &ret)
    {
        if (k==n)
        {
        ret.push_back(num);
        }
        else
        {  
            for (int i=k;i<=n;i++)
            {
                if (swap(k,i,num))
                {
                   int t = num[i];
                   num[i] = num[k];
                   num[k] = t;
           
                   perm(num, k+1,  n, ret);
       
                }
            }
        }
    }      
};

Friday, November 14, 2014

Subsets

Subsets
Given a set of distinct integers, S, return all possible subsets.
Note:
•Elements in a subset must be in non-descending order.
•The solution set must not contain duplicate subsets.

For example,
 If S = [1,2,3], a solution is:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

 1. (a)
I would like to call it induction
•For n=1, the set of subsets is {{}, {S[0]}}
•For n>1, find the subsets of 1,...,n-1. Make two copies of it. For one of them, add n to each subset.
Then take the union of the two copies.

For example,
•The set of subsets of {S[0]} is {{}, {S[0]}}
•For {S[0], S[1]}, take {{}, {S[0]}}, add S[1],  to each subset to get {{ S[1]}, { S[0], S[1]}} and take the union with {{}, { S[0]}} to get {{}, {S[0]}, {S[1]}, {S[0], S[1]}}
•Repeat till you reach S[n-1] (or finish all the elements)

class Solution {
public:
    vector<vector<int> > subsets(vector<int> &S) {
        vector<vector<int>> res;
        if (S.empty()) return res;
       
        int n = S.size();
        sort(S.begin(),S.end());
        vector<int> empty;
        res.push_back(empty);
       
        for (int i=0; i<n; i++)
        {
            vector<vector<int>> tmp=res;
            for (int j=0; j<tmp.size();j++)
            {
                tmp[j].push_back(S[i]);
            }
           
            for (int j=0; j<tmp.size();j++)
            {
                res.push_back(tmp[j]);
            }
        }
       
        return res;
    }
};


1(b). Same idea, different implementation. 增量构造法 Ref: http://m.blog.csdn.net/blog/mysee1989/39619401

Using vector::back() will simplify the code
http://www.cplusplus.com/reference/vector/vector/back/

  vector<vector<int> > subsets(vector<int> &s) {
               vector<vector<int>> res;
             
               if (s.empty()) return res;
               sort(s.begin(), s.end());
               res.clear();
               res.resize(1);
               int n = s.size();
               for (int i = 0; i<n; i++)
                   {
                       int size = res.size();
                          for (int j = 0; j<size; j++)
                          {
                                 res.push_back(res[j]);
                                 res.back().push_back(s[i]);
                          }
                   }
                    return res;
  }

2. Backtracking with recursion. We need to set a bool vector as the solution vector a
class Solution {
public:
    vector<vector<int> > subsets(vector<int> &s) {
        vector<vector<int>> ret;
        int n=s.size();
        //if (n==0) return ret;
        sort(s.begin(),s.end());
        vector<bool> a(n,false);
        helper(s,a,ret,n,0);
       
        return ret;
    }
   
   
    void helper(vector<int> &s, vector<bool> &a, vector<vector<int>> &r, int n, int k)
    {
        if (k==n)
        {
            //process sol
            vector<int> v;
              for (int j = 0; j<n; j++)
               {
                    if (a[j] == true)
                     v.push_back(s[j]);
                   }
            r.push_back(v);
            return;
        }
        else
        {
            a[k]=true;
            helper(s,a,r,n,k+1);
            a[k]=false;
            helper(s,a,r,n,k+1);
        }
    }
};

3. This is to use an int's bits as a mask for solution vector. If i's position is 1, then choose S[i], otherwise, do not include S[i] in the solution vector.
For example, for n=3 or {1,2,3}, lets assign bits to each outcome  -> First bit to 1 , Second bit to 2 and third bit to 3
Has = 1
No = 0
0) 0 0 0  -> No 3 , No 2 , No 1 = { }
1) 0 0 1  -> No  3 , No 2 ,   Has 1       =  {1 }
2) 0 1 0  -> No 3 ,    Has 2  , No 1 = { 2 }
3) 0 1 1  -> No 3 ,    Has 2 ,      Has 1    = { 1 , 2 }
4) 1 0 0  ->    Has 3      , No  2  , No 1 = { 3 }
5) 1 0 1  ->    Has 3      , No  2  ,     Has 1     = { 1 , 3 }
6) 1 1 0  ->    Has 3      ,    Has 2       , No 1 = { 2 , 3 }
7) 1 1 1  ->    Has 3     ,      Has 2     ,      Has 1     = { 1 , 2 , 3 }

class Solution {
public:
    vector<vector<int> > subsets(vector<int> &S) {
        vector<vector<int>> res;
        if (S.empty()) return res;
       
        sort(S.begin(),S.end());
        int n=S.size();
       
        int numVec = pow(2,n);
       
        for (int i=0; i<numVec; i++)
        {
            vector<int> v;
            for (int j=0; j<n; j++)
            {
                if (i&1<<j)
                    v.push_back(S[j]);

            }
            res.push_back(v);
            v.clear();
        }
      
       return res; 
    }
};

Tuesday, November 11, 2014

Search Insert Position

Problem:
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You may assume no duplicates in the array.
Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0

Solution:
This is relatively simple problem, just a small modification of the binary search. Pay attention to =.

class Solution {
public:
    int searchInsert(int A[], int n, int target) {
        int low=0, hi=n-1,mid=0;
       
        while(low<=hi)
        {
            mid=low+(hi-low)/2;
            if (target>A[mid])
            {
                low=mid+1;
            }
            else if(target<A[mid])
            {
                hi=mid-1;
            }
            else
            {
                return mid;
            }
        }       
        return low;
    }
};

Monday, November 10, 2014

Sort Colors (Dutch National Flag problem)

Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue.
Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
Note:
You are not suppose to use the library's sort function for this problem.
 
Follow up:
A rather straight forward solution is a two-pass algorithm using counting sort.
First, iterate the array counting number of 0's, 1's, and 2's, then overwrite array with total number of 0's, then 1's and followed by 2's.
Could you come up with an one-pass algorithm using only constant space?

Algorithm:
http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Sort/Flag/
Three-way partition where 3 pointers are used, 1 for left, 1 for right.
Assume that the array has starting point at lo and ending point at hi.


Reference: This picture is from http://algs4.cs.princeton.edu/23quicksort/

It's based on a single left-to-right  pass through the array that maintains a pointer left such that a[lo...left-1] is less than v, a pointer right such that a[right+1,...hi] is greater than v, and a pointer i such that a[left, i-1] are equal to v,  and a[i...right] are not yet examined.

class Solution {
public:
    void sortColors(int A[], int n) {
        int left = 0, right = n-1, i=left, v = 1;
       
        while(i<=right)  //See above picture, needs to make sure i<=right
        {
            if (A[i]>v)
            {
                swap(A[i],A[right]);
                right--;
            }
            else if (A[i]<v)
            {
                swap(A[i],A[left]);
                i++;
                left++;
            }
            else
               i++;           
        }       
    }
};
 

First Missing Positive

Given an unsorted integer array, find the first missing positive integer.
For example,
Given [1,2,0] return 3,
and [3,4,-1,1] return 2.
Your algorithm should run in O(n) time and uses constant space.

The challenging part of this problem is to 'uses constant space'. We need to find out how to manipulate the array itself to achieve this goal.

For A[n] to contain {1,2,3,4,......},  A[I]=I+1 or I = A[I]-1; If this condition doesn't hold, swap A[I] with A[A[I]-1] till we can't swap them anymore.

More specifically,
For n numbers, the answer must be in [1, n + 1].
1. If n numbers are 1, 2, 3, ..., n, then the answer is n + 1.
2. use a number x (x <= 0 || x > n) to replace a number in 1, 2, 3, ..., n. There must be a number less than n+1.

This is the key to write the following code.

class Solution {
public:
    int firstMissingPositive(int A[], int n) {
        for (int i=0; i<n; i++)
        {
            while (A[i]>0 && A[i]<=n && A[i]!=A[A[i]-1])
            {
                swap(A[i], A[A[i]-1]);
            }
        }
        for (int i=0; i<n; i++)
        {
            if (A[i]!=i+1)
               return i+1;
        }
        return n+1;
    }
};

Friday, November 7, 2014

MergeSort

For arrays:

1. Top-down:

Any better way to write this code?

 vector<int> aux;
 void merge(vector<int>& a, int lo, int mid, int hi)
 {
       int i = lo, j = mid + 1;
       for (int k = lo; k <= hi; k++)
      {
           aux[k] = a[k];
       }
       for (int k = lo; k <= hi; k++)
       {
             if (i > mid)
              a[k] = aux[j++];
             else if (j > hi)
              a[k] = aux[i++];
             else if (aux[i] > aux[j])
              a[k] = aux[j++];
             else
              a[k] = aux[i++];
       }
 }

 void sort(vector<int> &a, int lo, int hi)
 {
       if (hi <= lo) return;
       int mid = lo + (hi - lo) / 2;
       sort(a, lo, mid);
       sort(a, mid + 1, hi);
       merge(a, lo, mid, hi);
 }

 void mergeSort(vector<int> &a)
 {
       int len = a.size();
       aux = a;
       sort(a, 0, len - 1);
 }

2. Bottom up

void mergesortBU(vector<int> &a, int l, int r)

        for (int m=l; m<=r-l; m=m+m)
           for (int i=l; i<=r-m; i+=2*m)
                merge(a, i, i+m-1; min(i+2*m-1,r));
}

For singly linked list:
1. Top down:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *sortList(ListNode *head) {
        if (head==NULL||head->next==NULL) return head;
        ListNode *a=head, *b = head->next;
       
        while(b!=NULL&&b->next!=NULL)
        {
            a=a->next;
            b = b->next->next;
        }
        b=a->next;
        a->next=NULL;
        return merge(sortList(head), sortList(b));
    }
   
    ListNode *merge(ListNode *a, ListNode *b)
    {
        if (a==NULL) return b;
        if (b==NULL) return a;
        ListNode dummy(-1);
        ListNode *cur = &dummy;
       
        while(a!=NULL&&b!=NULL)
        {
            if ( a->val<b->val)
            {
                cur->next = a;
                cur = a;
                a=a->next;
            }
            else
            {
                cur->next = b;
                cur = b;
                b=b->next;
            }
        }
        cur->next = a!=NULL?a:b;
        return dummy.next;
    }
};

2. Bottom up: (Sort a linked list in O(n log n) time using constant space ) Is this constant space?
class Solution {
public:
    ListNode *sortList(ListNode *head) {
        if (head==NULL||head->next==NULL) return head;
       
        queue<ListNode *>  Q;
        for (ListNode *a=NULL; head!=NULL; head=a)
        {
            a = head->next;
            head->next = NULL;
            Q.push(head);
        }
       
        ListNode *t = Q.front();
        Q.pop();
       
        while(!Q.empty())
        {
            Q.push(t);
            t = Q.front();
            Q.pop();
            ListNode *p = Q.front();
            Q.pop();
            t = merge(t,p);
        }
       
        return t;
    }
   
    ListNode *merge(ListNode *a, ListNode *b)
    {
        if (a==NULL) return b;
        if (b==NULL) return a;
        ListNode dummy(-1);
        ListNode *cur = &dummy;
       
        while(a!=NULL&&b!=NULL)
        {
            if ( a->val<b->val)
            {
                cur->next = a;
                cur = a;
                a=a->next;
            }
            else
            {
                cur->next = b;
                cur = b;
                b=b->next;
            }
        }
        cur->next = a!=NULL?a:b;
        return dummy.next;
    }
};



Monday, November 3, 2014

Insertion Sort



Background:

https://en.wikipedia.org/wiki/Sorting_algorithm

Insertion sort and selection sort are quite similar.
http://en.wikipedia.org/wiki/Insertion_sort

http://en.wikipedia.org/wiki/Selection_sort

'Among simple average-case Θ(n2) algorithms, selection sort almost always outperforms bubble sort and gnome sort. Insertion sort is very similar in that after the kth iteration, the first k elements in the array are in sorted order. Insertion sort's advantage is that it only scans as many elements as it needs in order to place the k + 1st element, while selection sort must scan all remaining elements to find the k + 1st element.'

As its name suggests, it's a sort to be used while elements are being inserted into the array (or vector or whatever it is you're using), or sometimes when the array is "almost sorted". For an unsorted array, it's better to use quick sort or merge sort if it needs to be stable. Note, however, that insertion sort is actually faster when sorting while inserting.

http://mathbits.com/MathBits/CompSci/Arrays/Insertion.htm

http://www.programiz.com/article/insertion-sort-algorithm-programming

http://see.stanford.edu/materials/icspacs106b/Lecture15.pdf

Intuitively, inserting into a list is easier than inserting into an array as one has to move the elements in an array that are bigger than cur to the right. In terms of implementation, insertion sort an array compares from cur back as j-- till head of the array, while insertion sort a list compares from the head of the list and proceed down the list till end of the list.

1. Sort an array using insertion sort.
  void InsertionSort(vector<int> &v)
 {
       int j, len = v.size();
       for (int i = 1; i <len; i++)
       {
              int cur = v[i];
             // Slide cur down into position to left,
            // and move all the elements bigger than cur to be one more position to the right
              for (j = i - 1; j >= 0 && v[j]>cur; j--)
             {
                   v[j + 1] = v[j];
              }
              v[j+1] = cur;
        }
 }


2. Sort a linked list using insertion sort.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *insertionSortList(ListNode *head) {
        if (head==NULL||head->next==NULL) return head;
        ListNode *ret=NULL;
       
        ListNode *cur;
       
        while(head!=NULL)
        {
            cur = head;
            head = head->next;

           // insert into the head of the sorted list
            // or as the first element into an empty sorted list
            if (ret==NULL||cur->val< ret->val)
            {               
                cur->next = ret;
                ret = cur;
            }
            else
            {
                // insert current element into proper position in non-empty sorted list
                ListNode *p = ret;
                while(p!=NULL)
               {
                  if (p->next==NULL||cur->val<p->next->val)
                  {

                     // insert into middle of the sorted list or as the last element
                    cur->next = p->next;
                    p->next = cur;
                    break;
                  }

                p=p->next;
               }
            }
        }       
        return ret;       
    }
};