Sunday, March 30, 2014

LeetCode: ZigZag Conversion

The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)

P   A   H   N
A P L S I I G
Y   I   R
And then read line by line: "PAHNAPLSIIGYIR"

Write the code that will take a string and make this conversion given a number of rows:

string convert(string text, int nRows);
convert("PAYPALISHIRING", 3) should return "PAHNAPLSIIGYIR".


The naive idea for this problem is to use a string container to process the letter one by one. This will take O(n) time and O(n) space. Another solution is to compute the indices for letters in each row and this will take O(n) time and O(1) space.

C++ Code:

/*
 *func: zigzag_convert
 *goal: convert a string to zigzag pattern
 *@param s: the input string
 *@param nRows: the number of rows
 *return: the converted string
 */
/*
 *idea: use a vector of string to store each row
 *complexity: time O(n), space O(n)
 */
string zigzag_convert(const string &s, const int &nRows){
    assert(nRows > 0);
    //Corner Case, length of s is less than nRows or nRows is 1
    if(s.length() <= nRows || nRows == 1){
        return string(s);
    }
    
    vector<string> container(nRows);
    
    //indicator for going up or down
    bool going_up = false;
    int current_row = 0;
    
    for(int i = 0; i< s.length(); ++i){
        if(going_up){
            container.at(current_row).push_back(s[i]);
            
            //If reach the top, going down, else going up
            current_row == 0 ? ++current_row : --current_row;
            going_up = current_row == 0 ? false : true;
        }else{
            container.at(current_row).push_back(s[i]);
            
            //If reach the bottom, going up, else going down
            current_row == nRows-1 ? --current_row : ++current_row;
            going_up = current_row == nRows-1 ? true : false;
            
        }
    }
    
    //Construct the result
    string result = "";
    for(auto it = container.begin(); it != container.end(); ++it){
        result += *it;
    }
    
    return result;
}
/*
 *func: zigzag_convert
 *goal: convert a string to zigzag pattern
 *@param s: the input string
 *@param nRows: the number of rows
 *return: the converted string
 */
/*
 *idea: compute every index row by row
 *complexity: time O(n), space O(1)
 */
string zigzag_convert(const string &s, const int &nRows){
    assert(nRows > 0);
    //Corner Case, length of s is less than nRows or nRows is 1
    if(s.length() <= nRows || nRows == 1){
        return string(s);
    }
    
    string result;
    for(int i = 0; i < nRows; ++i){
        //Compute the index row by row
        //For the given example string "PAYPALISHIRING" and nRows = 3
        //output is
        //P   A   H   N   
        //A P L S I I G   
        //Y   I   R      
        //[0,0]->[0]            [0,1]->[4]            [0,2]->[8]             [0,3]->[12]
        //[1,0]->[1] [1,1]->[3] [1,2]->[5] [1,3]->[7] [1,4]->[9] [1,5]->[11] [1,6]->[13]
        //[2,0]->[2]            [2,1]->[6]            [2,2]->[10]
        //For those column with full elements, the index will be (nRows+nRows-2)*j + i where i
        //is the current row number and j is the current column number
        //For those column without full elements, the index will be index + (nRows-i-1)*2
        for(int j = 0, index = i; index < s.size(); ++j, index = (2*nRows-2)*j+i){
            //elements for full-element column
            result.push_back(s[index]);
            
            //There won't be element right behind for the first line and the last line
            if(i == 0 || i == nRows-1){
                continue;
            }
            
            if((index + (nRows-i-1)*2) < s.length()){
                result.push_back(s[index + (nRows-i-1)*2]);
            }
        }
    }
    
    return result;
}

Python Code:

#func: convert the current string to a zigzag pattern
#@param s: input string s
#@param nRows: number of rows
#@return: the converted string
#complexity: time O(n), space O(n)
def zigzag_convert(s, nRows):
    assert nRows > 0

    #Corner Case: if the length of s is lees than nRows or nRows is 1
    if len(s) <= nRows or nRows == 1:
        return s

    #Container
    container = []
    for _ in xrange(nRows):
        container.append('')

    #indicator for going up or down
    going_up = False

    current_row = 0

    for char in s:
        container[current_row]+=char
        if going_up:
            if current_row != 0:
                current_row -= 1
            else:
                current_row += 1
                going_up = False
        else:
            #Update current row and indicator
            if current_row != nRows-1:
                current_row += 1
            else:
                current_row -= 1
                going_up = True

    #concatenate string in container
    result = ''
    for string in container:
        result += string

    return result
#func: convert the current string to a zigzag pattern
#@param s: input string s
#@param nRows: number of rows
#@return: the converted string
#complexity: time O(n), space O(1)
def zigzag_convert(s, nRows):
    assert nRows > 0

    #Corner Case: if the length of s is lees than nRows or nRows is 1
    if len(s) <= nRows or nRows == 1:
        return s

    result = ''
    for i in xrange(nRows):
        #Compute the index row by row
        #For the given example string "PAYPALISHIRING" and nRows = 3
        #output is
        #P   A   H   N  
        #A P L S I I G  
        #Y   I   R     
        #[0,0]->[0]            [0,1]->[4]            [0,2]->[8]             [0,3]->[12]
        #[1,0]->[1] [1,1]->[3] [1,2]->[5] [1,3]->[7] [1,4]->[9] [1,5]->[11] [1,6]->[13]
        #[2,0]->[2]            [2,1]->[6]            [2,2]->[10]
        #For those column with full elements, the index will be (nRows+nRows-1)*j + i where i
        #is the current row number and j is the current column number
        #For those column without full elements, the index will be index + (nRows-i-1)*2

        #Current row index
        index = i
        #Current column index
        j = 0
        while index < len(s):
            result += s[index]

            #There won't be element right behind for the first line and the last line
            if i == 0 or i == nRows-1:
                j += 1
                index = (2*nRows-2)*j + i
                continue

            if (index + (nRows-i-1)*2) < len(s):
                result += s[(index + (nRows-i-1)*2)]

            j += 1
            index = (2*nRows-2)*j + i

    return result

Reference Link:

1.[LeetCode] ZigZag Conversion 解题报告: http://fisherlei.blogspot.com/2013/01/leetcode-zigzag-conversion.html

Saturday, March 29, 2014

LeetCode: Longest Palindromic Substring

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.


One idea is to test every possible palindrome substring and get the longest one at last. For each index i, the center of palindrome could be s[i] or s[i] and s[i+1]. We can test these two cases and find the longest one. The running time for this one is O(n^2)

Another solution is Manacher's Algorithm, and the description is in the reference link below.

C++ Code:

/*
 *func: longest_palindrome_center
 *goal: find the longest palindrome based on the input center
 *@param s: the input string
 *@param center_l: the index of left centroid
 *@param center_r: the index of right centroid
 *return: the current longest palindrome
 */
string longest_palindrome_center(const string &s, int center_l, int center_r){
    assert(center_l >= 0 && center_l < s.length()), assert(center_r < s.length() && center_r >= 0);
    assert(center_l <= center_r);
    
    //If the current pair is equal, expand to the next pair
    while(center_l >= 0 && center_r < s.length() && s[center_l] == s[center_r]){
        --center_l;
        ++center_r;
    }
    
    return s.substr(center_l + 1, center_r - center_l - 1);
}

/*
 *func: longest_palindrome
 *goal: find the longest palindrome in the input string
 *@param s: the input string
 *return: the longest palindrome
 */
/*
 *basic idea: check the length of every possible palindrome
 *complexity: time O(n^2), space O(n)
 */
string longest_palindrome(const string &s){
    string result = "";
    //Corner Case 1: the string is null
    if(s.length() == 0){
        return result;
    }
    //Else the result at least contains 1 letter
    result = s.substr(0, 1);
    
    for(int i=0; i<s.size()-1; i++){
        //For the case that the palindrome is odd-length
        string palindrome_odd = longest_palindrome_center(s, i, i);
        //Update the result
        if(palindrome_odd.length() > result.length()){
            result = palindrome_odd;
        }
        
        //For the case that the palindrome is even-length
        string palindrome_even = longest_palindrome_center(s, i, i+1);
        //Update the result
        if(palindrome_even.length() > result.length()){
            result = palindrome_even;
        }
            
    }
    
    return result;
}
/*
 *func: manacher_helper
 *goal: insert special character into the string to simplify the problem
 *For example: "aba" to "^#a#b#a#$', assume these characters don't exist
 *in the string
 *@param s: the input string
 *return: string after processing
 */
string manacher_helper(const string &s){
    //Corner Case
    if(s.length() == 0){
        return "^$";
    }
    
    string result = "^";
    for(int i=0; i<s.length(); i++){
        result += "#" + s.substr(i,1);
    }
    result += "#$";
    return result;
}

/*
 *func: longest_palindrome
 *goal: find the longest palindrome in the input string
 *@param s: the input string
 *return: the longest palindrome
 */
/*
 *idea: Manacher's Algorithm
 *complexity: time O(n), space O(n)
 */
string longest_palindrome(const string &s){
    //string after pre-processing
    string curr = manacher_helper(s);
    
    int length = curr.length();
    
    //array for the panlindrome length
    int *p = new int[length];
    
    //the index of current center, the index of right bound of current palindrome
    int center = 0, right_bound = 0;
    
    for(int i = 1; i < length-1; ++i){
        //the mirror position of current position i
        int i_mirror = 2 * center - i;
        
        //if the current right bound is greater than i, then we set
        //p[i] to the min of p[i_mirror] and right_bound-i
        //For example:
        //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
        //^ # a # b # a # b # a  #  b  #  $
        //0 0 1 0 3 0
        //assume center is 4, and right_bound is 7, and current i is 6
        //i_mirror is 2, then p[i] will be 1
        //Another case:
        //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
        //^ # b # a # b # c # b  #  a  #  b  #  c  #  b  #  a  #  $
        //0 0 1 0 3 0 1 0 7 0 1  0  9  0  1  0
        //assume center is 12, and right_bound is 21, and current i is 16
        //i_mirror is 8, then p[i] will be 5 but not 7
        p[i] = (right_bound > i) ? min(right_bound-i, p[i_mirror]) : 0;
        
        //Expand palindrome centered at i
        while(curr[i + 1 + p[i]] == curr[i - 1 - p[i]]){
            p[i]++;
        }
        
        //If palindrome centered at i expand across right bound,
        //adjust center based on expanded palindrome
        if(i + p[i] > right_bound){
            center = i;
            right_bound = i + p[i];
        }
    }
    
    //Find the maximum element in p
    int max_len = 0;
    int center_index = 0;
    for(int i = 1; i < length-1; ++i){
        if(p[i] > max_len){
            max_len = p[i];
            center_index = i;
        }
    }
    
    //Clean array p
    delete[] p;
    
    return s.substr((center_index - 1 - max_len)/2, max_len);
    
}

Python Code:

#func: find the longest palindrome substring based on the current center
#@param s: the input string
#@param center_l: the index of left centroid
#@param center_r: the index of right centroid
#@return: the longest palindrome substring
def longest_palindrome_center(s, center_l, center_r):
    assert 0 <= center_l < len(s)
    assert 0 <= center_r < len(s)
    assert center_l <= center_r

    while center_l >= 0 and center_r < len(s) and s[center_l] == s[center_r]:
        center_l -= 1
        center_r += 1

    return s[center_l+1: center_r]

#func: find the longest palindrome substring in the input string
#@param s: the input string
#@return: the longest palindrome substring
#complexity: time O(n^2), space O(n)
def longest_palindrome(s):
    #Corner Case: the string is none
    if not s:
        return ''

    #Initialize the result to the first element of the string
    result = s[0]

    for i in xrange(len(s)-1):
        #get the palindrome of odd length
        palindrome_odd = longest_palindrome_center(s, i, i)

        result = palindrome_odd if len(palindrome_odd) > len(result) else result

        #get the palindrome of even length
        palindrome_even = longest_palindrome_center(s, i, i+1)

        result = palindrome_even if len(palindrome_even) > len(result) else result

    return result

Python Code:

#func: preprocessing for manacher algorithm
#example: aba ==> ^#a#b#a#$
#@param s: input string s
#@return: string after preprocessing
def manacher_helper(s):
    #Coner Case:the string is none
    if not s:
        return '^$'

    result = '^'
    for char in s:
        result += '#' + char

    result += '#$'

    return result


#func: find the longest palindrome substring using Manacher's algorithm
#@param s: input string s
#@return: longest palindrome substring
#complexity: time O(n), space O(n)
def longest_palindrome(s):
    #string after preprocessing
    curr = manacher_helper(s)

    #auxiliary list
    p = len(curr) * [0]

    #the index of current center
    center = 0
    #the index of right bound of the current palindrome
    right_bound = 0

    for i in xrange(1, len(curr)-1):
        #the mirror position of current position i
        i_mirror = 2*center - i;

        #if the current right bound is greater than i, then we set
        #p[i] to the min of p[i_mirror] and right_bound-i
        #For example:
        #0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
        #^ # a # b # a # b # a  #  b  #  $
        #0 0 1 0 3 0
        #assume center is 4, and right_bound is 7, and current i is 6
        #i_mirror is 2, then p[i] will be 1
        #Another case:
        #0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
        #^ # b # a # b # c # b  #  a  #  b  #  c  #  b  #  a  #  $
        #0 0 1 0 3 0 1 0 7 0 1  0  9  0  1  0
        #assume center is 12, and right_bound is 21, and current i is 16
        #i_mirror is 8, then p[i] will be 5 but not 7
        p[i] = min(right_bound-i, p[i_mirror]) if right_bound > i else 0

        #Expand palindrome centered at i
        while curr[i+1+p[i]] == curr[i-1-p[i]]:
            p[i] += 1

        #If palindrome centered at i expand across right bound
        #adjust current center based on expanded palindrome
        max_len = 0
        center_index = 0
        for i in xrange(1, len(curr)-1):
            if p[i] > max_len:
                max_len = p[i]
                center_index = i

    return s[(center_index-1-max_len)/2 : (center_index-1+max_len)/2]

Reference Link:

1.Longest Palindromic Substring Part I: http://leetcode.com/2011/11/longest-palindromic-substring-part-i.html

2.Longest Palindromic Substring Part II: http://leetcode.com/2011/11/longest-palindromic-substring-part-ii.html

3.Longest palindromic substring: http://en.wikipedia.org/wiki/Longest_palindromic_substring#Manacher.27s_Algorithm_for_Finding_a_Longest_Palindrome_in_a_String

LeetCode: Add Two Numbers

You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8


The idea is adding digit by digit with the use of carry_on bit. Note that after adding two linked list, we need to check if there are still remaining elements in either list.

C++ Code:

struct ListNode{
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL){}
};

/*
 *func: add_two_numbers
 *goal: add two non-negtive numbers represented by link list
 *@param l1: the head of linked list 1
 *@param l2: the head of linked list 2
 *return: the head of the new linked list representing the sum
 */
/*
 *Just Add one bit by one bit
 *Time complexity: O(m+n), space complexity: O(m+n) where m is the
 *length of l1 and n is the length of l2
 */
ListNode* add_two_numbers(ListNode *l1, ListNode *l2){
    //iterator for l1 and l2
    ListNode *iter1 = l1, *iter2 = l2;
    
    //head of final result and iterator of final result
    ListNode *head = NULL, *iter_ret = new ListNode(0);
    
    //carry on variable
    bool carry_on = false;
    
    while(iter1 != NULL && iter2!= NULL){
        int sum = iter1->val + iter2->val + carry_on;
        
        //Set carry_on bit
        carry_on = sum >= 10 ? true : false;
        
        //Create new node
        iter_ret->next = new ListNode(sum >= 10 ? sum-10 : sum);
        
        //Set head pointer
        if(head == NULL){
            head = iter_ret->next;
        }
        
        //Go to the next one
        iter_ret = iter_ret->next;
        iter1 = iter1->next;
        iter2 = iter2->next;
    }
    
    //Check tail of iter1
    while(iter1 != NULL){
        int sum = iter1->val + carry_on;
        
        //Set carry_on bit
        carry_on = sum >= 10 ? true : false;
        
        //Create new node
        iter_ret->next = new ListNode(sum >= 10 ? sum-10 : sum);
        
        //Set head pointer
        if(head == NULL){
            head = iter_ret->next;
        }
        
        //Go to the next one
        iter_ret = iter_ret->next;
        iter1 = iter1->next;
    }
    
    //Check tail of iter2
    while(iter2 != NULL){
        int sum = iter2->val + carry_on;
        
        //Set carry_on bit
        carry_on = sum >= 10 ? true : false;
        
        //Create new node
        iter_ret->next = new ListNode(sum >= 10 ? sum-10 : sum);
        
        //Set head pointer
        if(head == NULL){
            head = iter_ret->next;
        }
        
        //Go to the next one
        iter_ret = iter_ret->next;
        iter2 = iter2->next;
    }
    
    //Check carry on
    if(carry_on){
        iter_ret->next = new ListNode(1);
    }
    
    return head;
}

Python Code:

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

#func: add two numbers represented by linked list
#@param l1: the head of l1
#@param l2: the head of l2
#@return: the head of the final result
#Complexity: time O(m+n), space O(m+n)
def add_two_numbers(l1, l2):
    #iterator for l1 and l2
    iter1 = l1
    iter2 = l2

    #head of final result and iterator of final result
    iter_ret = ListNode(0)
    head = None

    #carry_on digit
    carry_on = False

    while iter1 and iter2:
        #Compute sum
        sum = iter1.val + iter2.val + carry_on
        #Set carry_on bit
        carry_on = True if sum >= 10 else False
        #Create new node
        iter_ret.next = ListNode(sum - 10 if sum >= 10 else sum)

        #Set head
        if not head:
            head = iter_ret.next

        #Go to the next one
        iter_ret = iter_ret.next
        iter1 = iter1.next
        iter2 = iter2.next

    #Check tail of iter1
    while iter1:
        #Compute sum
        sum = iter1.val + carry_on
        #Set carry_on bit
        carry_on = True if sum >= 10 else False
        #Create new node
        iter_ret.next = ListNode(sum - 10 if sum >= 10 else sum)

        #Set head
        if not head:
            head = iter_ret.next

        #Go to the next one
        iter_ret = iter_ret.next
        iter1 = iter1.next

    #Check tail of iter2
    while iter2:
        #Compute sum
        sum = iter2.val + carry_on
        #Set carry_on bit
        carry_on = True if sum >= 10 else False
        #Create new node
        iter_ret.next = ListNode(sum - 10 if sum >= 10 else sum)

        #Set head
        if not head:
            head = iter_ret.next
            
        #Go to the next one
        iter_ret = iter_ret.next
        iter2 = iter2.next

    #Check carry_on bit
    if carry_on:
        iter_ret.next = ListNode(1)

    return head

Friday, March 28, 2014

LeetCode: Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.


The idea is traversing the string, when we meet one letter already viewed, start from the next one of the previously recorded letter. For example, string is "abcadef", when we meet the second a, start counting from b and continue recording.

C++ Code:

/* func: length_of_longest_substring
 * goal: find the length of the longest substring which doesn't
    contain repeating characters
 * @param s: the input string
 * return: the length of the longest substring
 * complexity: near O(n)
 */
/*
 *basic idea: Check every possible substring when traversing the string
 */
int length_of_longest_substring(string s){
    //Use hash map to record the position of every letter
    unordered_map<char, int> charset;
    
    int result = 0;
    
    //iteration index
    int i = 0;
        
    while(i < s.size()){
        auto iter = charset.find(s.at(i));
        if(iter == charset.end()){
            //there is no duplication in current substring
            //insert the current one
            charset.emplace(s.at(i), i);
            ++i;
        }else{
            //find one duplication, record current length and
            //make start index as the duplication position
            result = result > charset.size() ? result : charset.size();
            
            i = iter->second + 1;
            charset.clear();
        }
    }
    
    return result > charset.size() ? result : charset.size();
}

Python Code:

# func: length_of_longest_substring
# goal: find the length of the longest substring which doesn't
#   contain repeating characters
# @param s: the input string
# @return: the length of the longest substring
# complexity: near O(n)
def length_of_longest_substring(s):
    #charset to record current substring
    charset = {}

    i = 0
    result = 0
    while i < len(s):
        #if current character in the substring, record current length
        #and start at the new point, then recounting
        if s[i] in charset:
            result = max(result, len(charset))
            i = charset[s[i]]+1
            charset.clear()
        #else retain the current letter
        else:
            charset[s[i]] = i
            i += 1

    return max(result, len(charset))

LeetCode: Median of Two Sorted Arrays

There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).


The naive idea for this problem is merge these two arrays first and then find the median, which will take O(m+n) time O(m+n) space. Another idea is utilizing binary search, each time we can shrink the array by comparison.

C++ Code:

/*
 * func: find_kth_sorted_arrays
 * goal: find the kth element in two sorted array
 * @param A[]: sorted array A
 * @param m: size of sorted array A
 * @param B[]: sorted array B
 * @param n: size of sorted array B
 * @param k: the kth index
 * return: the kth element of two sorted arrays
 */
int find_kth_sorted_arrays(int A[], int m, int B[], int n, int k){
    //check for k, m and n
    assert(k>0), assert(m>=0), assert(n>=0);
    assert(k <= m+n);
    
    //we try to put the smaller-sized array ahead to make it simple
    if(m > n){
        return find_kth_sorted_arrays(B, n, A, m, k);
    }
    
    //Corner Case1: if one array is empty
    if(m == 0){
        return B[k-1];
    }
    
    //Corner Case2: if k is 1
    if(k == 1){
        return A[0] > B[0] ? B[0] : A[0];
    }
    
    //Specify index in A and B
    int index_a = min(k/2, m);
    int index_b = k - index_a;
    
    //If A[index_a-1] <= B[index_b-1], elements from A[0] to A[index_a-1] can be
    //filtered since they are too small
    if(A[index_a-1] <= B[index_b-1]){
        return find_kth_sorted_arrays(A+index_a, m-index_a, B, n, k-index_a);
    }
    //The same situation for array B
    else{
        return find_kth_sorted_arrays(A, m, B+index_b, n-index_b, k-index_b);
    }
    
}

/*
 * func: find_median_sorted_arrays
 * goal: find the median of two sorted array
 * @param A[]: sorted array A
 * @param m: the size of sorted array A
 * @param B[]: sorted array B
 * @param n: the size of sorted array B
 * return: the median of two sorted arrays
 */
/*
 *Basic Idea: Use binary search to speed up searching
 */
double find_median_sorted_arrays(int A[], int m, int B[], int n){
    //Compute the total size first
    int total = m + n;
    //If the total size is odd, then the median is the middle element
    //Note >> has lower precedence than '+'; '+' will be evaluated first
    if(total & 1){
        return find_kth_sorted_arrays(A, m, B, n, (total>>1) + 1);
    }
    //Else, the median is the average of the two middle elements
    else{
        return double(find_kth_sorted_arrays(A, m, B, n, total>>1)
                      + find_kth_sorted_arrays(A, m, B, n, (total >> 1) + 1))/2;
        
    }
}

Python Code:

# func: find the kth element of two sorted arrays
# @param A: sorted array A
# @param B: sorted array B
# @param k: the kth index
# @return: the kth element
def find_kth_sorted_arrays(A, B, k):
    assert 0 < k <= len(A) + len(B), "Invalid input k"

    if len(A) > len(B):
        return find_kth_sorted_arrays(B, A, k)

    #Corner Case1: if one array is empty
    if not A:
        return B[k-1]

    #Corner Case2: if k is 1
    if k == 1:
        return min(A[0], B[0])

    #Decide searching index in A and B
    index_a = min(k/2, len(A))
    index_b = k - index_a

    #If A[index_a-1] <= B[index_b-1], then elements from A[0] to
    #A[index_a-1] could be too small
    if A[index_a-1] <= B[index_b-1]:
        return find_kth_sorted_arrays(A[index_a:], B, k-index_a)
    else:
        return find_kth_sorted_arrays(A, B[index_b:], k-index_b)


#func: find the median of two sorted arrays
#@param A: sorted array A
#@param B: sorted array B
#@return: the median value
def find_median_sorted_arrays(A, B):
    #the total length for two arrays
    total_length = len(A) + len(B)

    #If the length is odd, then return the middle element
    if total_length % 2 != 0:
        return find_kth_sorted_arrays(A, B, total_length/2+1)
    #else, return the average of the two middle elements
    else:
        return float(find_kth_sorted_arrays(A, B, total_length/2)+
        find_kth_sorted_arrays(A, B, total_length/2+1)) / 2

Extension: What if the question is changed to find the median of trillion numbers stored in several machines?

The idea is that we can use the thinking of quick sort, each time choose a pivot and keep a count of the elements bigger than the pivot and smaller than the pivot.


Reference Link:

1.Find the kth element: http://yucoding.blogspot.com/2013/01/leetcode-question-50-median-of-two.html

2.Utilization of binary search: http://hp.dewen.org/?p=1466

3.The median of a trillion numbers: http://matpalm.com/median/question.html

LeetCode:Two Sum

Given an array of integers, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.

You may assume that each input would have exactly one solution.

Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2


The naive idea for this problem is using two for loops to check every possible pairs. This method cannot pass the large case.

Another idea is that use a hashmap to record the elements that have been visited, and meanwhile find if there exists one can be added to the current element to reach the target.

C++ Code:

/*
 * function: twoSum
 * goal: find the index of two integers whose sum is equal to the target
 * @param numbers: vector of the integers
 * @param target: the given target sum
 * return: the index of two integers, first one should be less than the second one
 */
/*
 * Basic Idea: Store integers into hashmap to help find
 * Complexity: time O(n), space O(n)
 */
vector<int> twoSum(const vector<int> &numbers, const int &target){
    //vector for the final result
    vector<int> result;
    
    //Corner Case 1: numbers is empty
    if(numbers.size() == 0){
        return result;
    }
    //Corner Case 2: there is only one element in numbers
    //According to the system, we have to return that one element if it is equal to
    //the target
    else if(numbers.size() == 1){
        if(numbers.at(0) == target){
            result.emplace_back(1);
        }
        return result;
    }
    else{
        //Use unordered_map to store value : index pair
        unordered_map<int, int> hash_map;
        for(size_t i = 0; i < numbers.size(); ++i){
            if(hash_map.find(target - numbers.at(i)) != hash_map.end()){
                result.emplace_back(hash_map[target - numbers.at(i)] + 1);
                result.emplace_back(i + 1);
                return result;
            }else{
                hash_map.emplace(numbers.at(i), i);
            }
        }
        //No matches
        return result;
    }
}

Python Code:

# func: find the index of two integers whose sum is equal to the target
# @param num: a list of input integers
# @param target: the given target sum
# @return: a tuple (index1, index2) where index1 < index2
# Basic Idea: Use dict to store the value and corresponding index
# Complexity: time O(n), space O(n)
def two_sum(num, target):
    #Corner Case 1: num is empty
    if not num:
        return
    #Corner case 2: there is only one element in num
    elif len(num) == 1:
        #If the element is equal to target, return it
        if num[0] == target:
            return (target)
        else:
            return
    #Common case: use dict to record previous element
    else:
        hash_map = {}
        for i in xrange(len(num)):
            #If we find that pair, return it
            if (target - num[i]) in hash_map:
                return (hash_map[target-num[i]]+1, i+1)
            else:
                hash_map[num[i]] = i

        #No matches
        return