Wednesday, April 30, 2014

LeetCode: Wildcard Matching

Implement wildcard pattern matching with support for '?' and '*'.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false


Since '*' matches any sequence of characters, we need to check every possibility within string s. Instead of using recursion, we can use iteration with two variables recording position of last '*' in pattern string and corresponding position in string s.

C++ Code:

/*
 * func: wildcard_match
 * goal: wildcard pattern match with support for '?' and '*'
 * @param s: string to be checked
 * @param p: pattern to be used
 * return: true or false
 */
bool wildcard_match(const char* s, const char* p){
    if(! *s && ! *p){
        return true;
    }
    char* start_s = nullptr;
    char* start_p = nullptr;
    
    while(*s != '\0'){
        if(*p == *s || *p == '?'){
            ++p;
            ++s;
        }else if(*p == '*'){
            //skip continuous '*'
            while(*p == '*'){
                ++p;
            }
            //If '*' is the last letter, return true
            if(*p == '\0'){
                return true;
            }
            
            start_p = const_cast<char*>(p);
            start_s = const_cast<char*>(s);
        }else if((*p != '\0' || *p != *s) && start_p != nullptr){
            //If current char is not matched, include it to the * and backtrace
            s = ++start_s;
            p = start_p;
        }else{
            return false;
        }
    }
    
    //Check if remaining part of pattern is all of '*'
    while(*p != '\0'){
        if(*p++ != '*'){
            return false;
        }
    }
    
    return true;
}

Python Code:

# func: wildcard pattern match with support for '?' and '*'
# @param s: an input string
# @param p: a pattern string
# @return: True or False
def wildcard_match(s, p):
    s_index = 0
    p_index = 0
    star = -1
    while s_index < len(s) and p_index <= len(p):
        if p_index != len(p):
            if p[p_index] == '?' or p[p_index] == s[s_index]:
                s_index += 1
                p_index += 1
                continue
            if p[p_index] == '*':
                star = p_index
                p_index += 1
                #Record the current index of s when a '*' occur in p
                s_star = s_index
                continue
        if star != -1:
            p_index = star + 1
            s_index = s_star + 1
            s_star += 1
            continue
        return False
    #Remove '*' in the remaining part
    while p_index < len(p) and p[p_index] == '*':
        p_index += 1

    if p_index == len(p):
        if s_index == len(s):
            return True
        else:
            return False
    else:
        return False

Reference Link:

[closed] Wildcard Matching - LeetCode http://discuss.leetcode.com/questions/222/wildcard-matching

Monday, April 28, 2014

LeetCode: Multiply Strings

Given two numbers represented as strings, return multiplication of the numbers as a string.

Note: The numbers can be arbitrarily large and are non-negative.


The idea is to compute each digit of the final product iteratively.

C++ Code:

/*
 * func: multiply_string
 * goal: multiply two numbers represented by strings
 * @param num1: number 1
 * @param num2: number 2
 * return: the product
 */
string multiply_string(string num1, string num2){
    int num1_length = static_cast<int>(num1.length());
    int num2_length = static_cast<int>(num2.length());
    int ret_length = num1_length + num2_length;
    int offset = ret_length-1;
    
    string result(ret_length,'0');
    vector<int> num(ret_length, 0);
    
    for(int i = ret_length-1, carry = 0; i >= 0; --i){
        //Compute the current digit
        for(int j = std::max(0, i - num2_length); j < num1_length && i - 1 - j >= 0; ++j){
            num[i] += (num1[j]-'0') * (num2[i-1-j] - '0');
        }
        //Add carry digit from last sum
        num[i] += carry;
        //Re-calculate carry digit
        carry = num[i]/10;
        //push back result
        result[i] = num[i]%10 + '0';
        if(result[i] != '0')
            offset = i;
    }
    
    return string(result.begin() + offset, result.end());
}

Python Code:

# func: multiply two big integers represented by string
# @param num1: input integer 1
# @param num2: input integer 2
# @return: the product
def multiply_strings(num1, num2):
    #Reverse the string first to make it more straight forward
    num1 = num1[::-1]
    num2 = num2[::-1]
    num1_len = len(num1)
    num2_len = len(num2)
    ret_len = num1_len + num2_len

    ret = [0] * ret_len
    for i in xrange(num1_len):
        for j in xrange(num2_len):
            ret[i + j] += int(num1[i]) * int(num2[j])

    result = ''
    carry = 0
    #Construct the final result
    for i in xrange(ret_len):
        digit = (ret[i] + carry) % 10
        carry = (ret[i] + carry) / 10
        result = str(digit) + result

    i = 0
    while i < len(result) and result[i] == '0':
        i += 1

    if i == len(result):
        return '0'
    else:
        return result[i:]

Reference Link:

[leetcode] Multiply Strings | 大整数的字符串乘法| Lexi's ... http://leetcodenotes.wordpress.com/2013/10/20/leetcode-multiply-strings-%E5%A4%A7%E6%95%B4%E6%95%B0%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%98%E6%B3%95/

Friday, April 25, 2014

LeetCode: Trapping Rain Water

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.

For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.


The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!


We can find the left bound and right bound for each slot when iterating the array.

C++ Code:

/*
 * func: trapping_rain_water
 * goal: Given n non-negative integers representing an elevation map 
 *       where the width of each bar is 1, compute how much water it 
 *       is able to trap after raining.
 * @param A: input array A
 * @param n: size of the array
 * return: the maximum volume
 */
/*
 * Set up left bound and right bound and keep finding available container
 * complexity: time O(n), space O(1)
 */
int trap(int A[], int n){
    assert(n>=0);
    for(int i=0; i<n; i++){
        assert(A[i] >= 0);
    }
    
    //Initialize left bound and right bound
    int left = 0;
    int right = n-1;
    int max_volume = 0;
    while(left < right){
        //If A[left] <= A[right], there may be water between them
        if(A[left] <= A[right]){
            //keep finding the next left bound and adding water at the same tiem
            int k = left + 1;
            //If left bound is larger than current bound, we can store water
            while(A[left] > A[k]){
                max_volume += A[left] - A[k];
                ++k;
            }
            left = k;
        }else{
            int k = right-1;
            while(A[right] > A[k]){
                max_volume += A[right] - A[k];
                --k;
            }
            right = k;
        }
    }
    return max_volume;
}

Python Code:

# func: Given n non-negative integers representing an elevation map
#       where the width of each bar is 1, compute how much water it
#       is able to trap after raining.
# @param A: a list of integers
# @return: the maximum value
def trap_water(A):
    assert (x >= 0 for x in A)

    left = 0
    right = len(A)-1
    max_volume = 0
    while left < right:
        if A[left] <= A[right]:
            k = left + 1
            while A[k] < A[left]:
                max_volume += A[left] - A[k]
                k += 1
            left = k
        else:
            k = right - 1
            while A[k] < A[right]:
                max_volume += A[right] - A[k]
                k -= 1
            right = k

    return max_volume

LeetCode: 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 trick point for this problem is that the index of the array can be utilized as a ordered hash table. While iterating the array, if we find one positive integer that is not in the position of value-1, swap it to that spot. After swapping, we can find the first index where A[index] != index+1. Then it will be the first missing positive.

C++ Code:

/*
 * func: first_missing_positive
 * goal: find the first missing positive integer in the array
 * @param A[]: input array A
 * @param n: the size of the array
 * return: the first missing positive value
 */
/*
 * Put value within range 1 to len(A) to A[index-1]. Then find the 
 * first one that doesn't match.
 * complexity: time O(n), space O(1)
 */
int first_missing_positive(int A[], int n){
    assert(n > 0);
    int index = 0;
    while(index < n){
        if(A[index] > 0 && A[index] <= n && A[A[index]-1] != A[index]){
            std::swap(A[A[index]-1], A[index]);
        }else{
            index += 1;
        }
    }
    
    index = 0;
    while(index < n && A[index] == index + 1){
        ++index;
    }
    
    return index+1;
}

Python Code:

# func: find the first missing positive values in the array
# @param A: input list A
# @return: an integer
# complexity: time O(n), space O(1)
def find_missing_positive(A):
    index = 0
    while index < len(A):
        #If the current value is in the range but not in the right spot
        #Swap it to its spot
        if 0 < A[index] <= len(A) and A[A[index]-1] != A[index]:
            tmp = A[A[index]-1]
            A[A[index]-1] = A[index]
            A[index] = tmp
        else:
            index += 1

    index = 0
    while index < len(A) and A[index] == index+1:
        index += 1

    return index + 1

Thursday, April 24, 2014

LeetCode: Combination Sum II

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

Each number in C may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.

For example, given candidate set 10,1,2,7,6,1,5 and target 8,
A solution set is:
[1, 7]
[1, 2, 5]
[2, 6]
[1, 1, 6]


We can use the same idea as the previous one to solve this problem. Just to remind, if the current candidate number is equal to the previous one, then we can skip to eliminate duplicate solutions. For C++, I chose to use a different way. I use unordered_set to remove duplicate solutions from final sets. In this case we have to write our own hash functional class and equal functional class.

C++ Code:

//Hash functional class for unordered_set
class HashVector{
public:
    const size_t operator()(const vector<int>& vec) const{
        int value = 0;
        for(const auto &it: vec)
            value ^= it;
        return static_cast<size_t>(value);
    }
};
//Equal functional class for unordered_set
class EqualVector{
public:
    const bool operator()(const vector<int>& left, const vector<int> &right) const{
        if(left.size() != right.size()){
            return false;
        }
        for(int i=0; i<left.size(); i++){
            if(left[i] != right[i]){
                return false;
            }
        }
        return true;
    }
};
//helper function for combination sum
void combination_sum_helper(vector<int> candidates, int target, vector<int> candidate_combination, unordered_set<vector<int>, HashVector, EqualVector>& result){
    if(target == 0){
        result.emplace(candidate_combination);
        return;
    }
    else if(target < 0){
        return;
    }else{
        for(int i = 0; i < candidates.size(); ++i){
            if(candidates[i] <= target){
                vector<int> formed_vector(candidates.begin()+i+1, candidates.end());
                candidate_combination.emplace_back(candidates[i]);
                combination_sum_helper(formed_vector, target - candidates[i], candidate_combination, result);
                candidate_combination.pop_back();
            }
        }
    }
}
vector<vector<int> > combination_sum_ii(vector<int> &candidates, int target) {
    unordered_set<vector<int>, HashVector, EqualVector> result_set;
    vector<vector<int> > result;
    sort(candidates.begin(), candidates.end());
    if(candidates.size() == 0 || candidates[0] > target){
        return result;
    }
    vector<int> candidate_combination;
    combination_sum_helper(candidates, target, candidate_combination, result_set);
    for(const auto &it : result_set)
        result.emplace_back(it);
    return result;
}

Python Code:

# func: helper function for combination sum
# @param candidates: candidates numbers
# @param target: target value
# @param result: final result set
# @param candidate_solution: current solution list
# @return:
def combination_sum_helper(candidates, target, result, candidate_solution):
    if target == 0:
        result.append(candidate_solution)
    elif target < 0:
        return
    else:
        for i in xrange(len(candidates)):
            if i > 0 and candidates[i] == candidates[i-1]:
                continue
            if candidates[i] <= target:
                combination_sum_helper(candidates[i+1:], target - candidates[i], result, candidate_solution + [candidates[i]])


# func: find all unique combinations in candidate set where the candidate numbers sum to T
#       each number may only be used once in the combination
# @param candidates: candidate set
# @param target: the target value
# @return: a list of lists of numbers
def combination_sum(candidates, target):
    candidates.sort()
    if len(candidates) == 0 or candidates[0] > target:
        return []
    result = []
    combination_sum_helper(candidates, target, result, [])

    return result

LeetCode: Combination Sum

Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

The same repeated number may be chosen from C unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.

For example, given candidate set 2,3,6,7 and target 7,
A solution set is:
[7]
[2, 2, 3]


Use Depth-First-Search to find possible solutions.

C++ Code:

/*
 * func: combination_sum_helper
 * goal: helper function to perform a depth first search
 * @param candidates: a set of candidate numbers
 * @param target: target value
 * @param candidate_combination: current possible solution
 * @param result: final solution set
 * return:
 */
void combination_sum_helper(vector<int> candidates, int target, vector<int> candidate_combination, vector<vector<int> >& result){
    if(target == 0){
        result.emplace_back(candidate_combination);
        return;
    }
    else if(target < 0){
        return;
    }else{
        for(int i = 0; i < candidates.size(); ++i){
            if(candidates[i] <= target){
                vector<int> formed_vector(candidates.begin()+i, candidates.end());
                candidate_combination.emplace_back(candidates[i]);
                combination_sum_helper(formed_vector, target - candidates[i], candidate_combination, result);
                candidate_combination.pop_back();
            }
        }
    }
}

/*
 * func: combination_sum
 * goal: find all unique combinations where candidate numbers sum to T
 * @param candidates: a set of candidate numbers
 * @param target: target value
 * return: all possible combinations
 */
vector<vector<int> > combination_sum(vector<int> &candidates, int target){
    vector<vector<int> > result;
    sort(candidates.begin(), candidates.end());
    if(candidates.size() == 0 || candidates[0] > target){
        return result;
    }
    vector<int> candidate_combination;
    combination_sum_helper(candidates, target, candidate_combination, result);
    return result;
}

Python Code:

# func: helper function for combination sum
# @param candidates: candidates numbers
# @param target: target value
# @param result: final result set
# @param candidate_solution: current solution list
# @return: 
def combination_sum_helper(candidates, target, result, candidate_solution):
    if target == 0:
        result.append(candidate_solution)
    elif target < 0:
        return
    else:
        for i in xrange(len(candidates)):
            if candidates[i] <= target:
                combination_sum_helper(candidates[i:], target - candidates[i], result, candidate_solution + [candidates[i]])

# func: find all unique combinations in candidate set where the candidate numbers sum to T
# @param candidates: candidate set
# @param target: the target value
# @return: a list of lists of numbers
def combination_sum(candidates, target):
    candidates.sort()
    if len(candidates) == 0 or candidates[0] > target:
        return []
    result = []
    combination_sum_helper(candidates, target, result, [])

    return result

LeetCode: Count and Say

The count-and-say sequence is the sequence of integers beginning as follows:
1, 11, 21, 1211, 111221, ...

1 is read off as "one 1" or 11.
11 is read off as "two 1s" or 21.
21 is read off as "one 2, then one 1" or 1211.

Given an integer n, generate the nth sequence.

Note: The sequence of integers will be represented as a string.


Just follow the rules and generating one by one

C++ Code:

/*
 * func: count_and_say
 * goal: given an integer n, generate the nth count-and-say sequence
 * @param n:
 * return: string of the sequence
 */

string count_and_say(int n){
    assert(n > 0);
    string result = "1";
    int counter = 1;
    
    while(counter < n){
        size_t index = 0;
        string iter_result = "";
        int iter_counter = 1;
        while(index < result.length()-1){
            if(result[index+1] == result[index]){
                ++index;
                ++iter_counter;
            }else{
                iter_result += iter_counter + '0';
                iter_result += result[index];
                ++index;
                iter_counter = 1;
            }
        }
        
        //count the last digit
        iter_result += iter_counter + '0';
        iter_result += result[index];
        
        ++counter;
        result = iter_result;
    }
    
    return result;
}

Python Code:

# func: given an integer n, generate nth count-and-say sequence
# @param n: input integer n
# @return: the nth sequence as a string
def count_and_say(n):
    assert n > 0

    result = '1'
    counter = 1
    while counter < n:
        digit_counter = 1
        i = 0
        inner_result = ''
        while i < len(result)-1:
            if result[i] == result[i+1]:
                digit_counter += 1
                i += 1
            else:
                inner_result += str(digit_counter) + result[i]
                i += 1
                digit_counter = 1

        inner_result += str(digit_counter) + result[i]
        result = inner_result
        counter += 1

    return result

Wednesday, April 23, 2014

LeetCode: Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells.

Empty cells are indicated by the character '.'.

You may assume that there will be only one unique solution.


A sudoku puzzle...


...and its solution numbers marked in red.


Use backtracking strategy to solve this problem. First find a blank spot. Then find available candidate values. And go to find next blank spot. If the current solution is unresolvable, go back on step and try another one.

C++ Code:

/*
 * func: find_available
 * goal: find available candidates for current spot
 * @param candidates: candidates set
 * @param board: current sudoku board
 * @param row: row index
 * @param column: column index
 * return:
 */
void find_available(vector<bool>& candidates, const vector<vector<char> > &board, int row, int column){
    for(int i = 0; i < 9; ++i){
        if(board[i][column] != '.'){
            candidates[board[i][column] - '1'] = false;
        }
        
        if(board[row][i] != '.'){
            candidates[board[row][i]-'1'] = false;
        }
        
        if(board[row/3*3 + i/3][column/3*3 + i%3] != '.'){
            candidates[board[row/3*3 + i/3][column/3*3 + i%3] - '1'] = false;
        }
    }
}
/*
 * func: solve_sudoku_helper
 * goal: solve the sudoku problem in backtracking
 * @param board: the sudoku board
 * @param row: current row index
 * @param column: current column index
 * return: true or false
 */
bool solve_sudoku_helper(vector<vector<char> > &board, int row, int column){
    //Find the next empty position
    while(row < 9 && board[row][column] != '.'){
        row = (column == 8) ? row + 1 : row;
        column = (column + 1) % 9;
    }
    if(row == 9){
        return true;
    }
    //Find available candidate for the current spot
    vector<bool> candidates(9, true);
    find_available(candidates, board, row, column);
    for(int i = 0; i < 9; i++){
        if(candidates[i]){
            board[row][column] = i + '1';
            if(solve_sudoku_helper(board, row, column)){
                return true;
            }
        }
    }
    board[row][column] = '.';
    return false;
}
/*
 * func: solve_sudoku
 * goal: solve the given sudoku problem
 * @param board: input sudoku board
 * return: 
 */
void solve_sudoku(vector<vector<char> > &board){
    solve_sudoku_helper(board, 0, 0);
}

For Python code, we can just convert the C++ code and it can pass the test. Here I introduced another solution which looks simpler but cannot pass because of time limit.

def same_row(i, j):
    return i/9 == j/9

def same_col(i, j):
    return (i-j) % 9 == 0

def same_block(i, j):
    return i/27 == j/27 and i%9/3 == j%9/3

def solve_sudoku_helper(board_list, board):
    spot = board_list.find('.')

    if spot == -1:
        for i in xrange(9):
            board[i] = board_list[i*9: (i+1)*9]
        return

    excluded_numbers = set()
    for i in range(81):
        if same_row(spot, i) or same_col(spot, i) or same_block(spot, i):
            excluded_numbers.add(board_list[i])

    for candidate in '123456789':
        if candidate not in excluded_numbers:
            solve_sudoku_helper(board_list[:spot] + candidate + board_list[spot+1:], board)

# func: solve sudoku problem
# @param board: current sudoku board
# @return:
def solve_sudoku(board):
    boardlist = ''.join(x for row in board for x in row)
    solve_sudoku_helper(boardlist, board)

Reference Link:

1.Simple Sudoku solver in python | Bite Sized Python Tips: http://freepythontips.wordpress.com/2013/09/01/sudoku-solver-in-python/

LeetCode: Valid Sudoku

Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules.

The Sudoku board could be partially filled, where empty cells are filled with the character '.'.


A partially filled sudoku which is valid.

Note:
A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated.


Just follow the rules, check every row, every column and every block.

C++ Code:

/*
 * func: valid_sudoku
 * goal: to check if the sudoku board is valid
 * @param board: vector of sudoku board
 * return: true or false
 */
bool valid_sudoku(vector<vector<char> > &board){
    assert(board.size() == 9);
    for(int i=0; i<9; i++){
        assert(board.at(i).size() == 9);
    }
    
    vector<int> check_helper(9, 0);
    //Check each row
    for(int row=0; row<9; row++){
        for(int column=0; column<9; column++){
            if(board[row][column] != '.'){
                if(check_helper[board[row][column] - '0'] != 0){
                    return false;
                }else{
                    check_helper[board[row][column] - '0'] = 1;
                }
            }
        }
        fill(check_helper.begin(), check_helper.end(), 0);
    }
    
    //Check each column
    for(int column=0; column<9; column++){
        for(int row=0; row<9; row++){
            if(board[row][column] != '.'){
                if(check_helper[board[row][column] - '0'] != 0){
                    return false;
                }else{
                    check_helper[board[row][column] - '0'] = 1;
                }
            }
        }
        fill(check_helper.begin(), check_helper.end(), 0);
    }
    
    //Chech each block
    for(int row = 0; row < 9; row += 3){
        for(int column = 0; column < 9; column += 3){
            for(int row_offset = 0; row_offset < 3; row_offset++){
                for(int column_offset = 0; column_offset < 3; column_offset++){
                    if(board[row + row_offset][column + column_offset] != '.'){
                        if(check_helper[board[row + row_offset][column + column_offset] - '0'] != 0){
                            return false;
                        }else{
                            check_helper[board[row + row_offset][column + column_offset] - '0'] = 1;
                        }
                    }
                }
            }
            fill(check_helper.begin(), check_helper.end(), 0);
        }
    }
    
    return true;
}

Python Code:

# func: To check if the current Sudoku board is a valid one
# @param board: sudoku board
# @return: True or False
def valid_sudoku(board):
    assert len(board) == 9
    for row in board:
        assert len(row) == 9

    #Check every row
    check_helper = set()
    for row in board:
        for element in row:
            if element != '.':
                if element in check_helper:
                    return False
                else:
                    check_helper.add(element)

        check_helper.clear()

    #Check every column
    for column in xrange(9):
        for row in xrange(9):
            if board[row][column] != '.':
                if board[row][column] in check_helper:
                    return False
                else:
                    check_helper.add(board[row][column])
        check_helper.clear()

    #Check every block
    for row in [0, 3, 6]:
        for column in [0, 3, 6]:
            for row_offset in xrange(3):
                for column_offset in xrange(3):
                    if board[row + row_offset][column + column_offset] != '.':
                        if board[row + row_offset][column + column_offset] in check_helper:
                            return False
                        else:
                            check_helper.add(board[row + row_offset][column + column_offset])
            check_helper.clear()
    return True

LeetCode: Search Insert Position

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


This is just regular binary search. If we found, return its position. If not, return the search start position.

C++ Code:

/*
 * func: search_range_helper
 * goal: binary search for the target
 * @param A: input integer array A
 * @param start: start index
 * @param end: end index
 * @param target: target value
 * return: the index of target
 */
int search_insert_helper(int A[], int start, int end, int target){
    if(start > end){
        return start;
    }
    int mid = start + (end-start) / 2;
    if(A[mid] == target){
        return mid;
    }else if(A[mid] > target){
        return search_insert_helper(A, start, mid-1, target);
    }else{
        return search_insert_helper(A, mid+1, end, target);
    }
    
}

/*
 * func: search_insert
 * goal: find the index if the target is found. If not, return the index where it 
 *       would be if it were inserted in order
 * @param A: integer array A
 * @param n: size of the array A
 * @param target: target value
 * return: the insert position if not found
 */
int search_insert(int A[], int n, int target){
    assert(n > 0);
    return search_insert_helper(A, 0, n-1, target);
}

In Python, it just mimic the function bisect.bisect_left() for list without duplicate elements.

Python Code:

# func: 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.
# @param A: input list A
# @param target: target value
# @return: target position
def search_insert(A, target):
    if not A:
        return 0
    start = 0
    end = len(A)-1
    while start <= end:
        mid = start + (end-start)/2
        if A[mid] == target:
            return mid
        elif A[mid] < target:
            start = mid+1
        else:
            end = mid-1
    return start

LeetCode: Search for a Range

Given a sorted array of integers, find the starting and ending position of a given target value.

Your algorithm's runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].


The idea is the similar to binary search. One more thing to keep in mind is that we need to check the current index just found is left bound or right bound or neither of them.

C++ Code:

/*
 * func: search_range_helper
 * goal: binary search for the target
 * @param A: input integer array A
 * @param start: start index
 * @param end: end index
 * @param target: target value
 * return: the index of target
 */
int search_range_helper(int A[], int start, int end, int target){
    if(start > end){
        return -1;
    }
    int mid = start + (end-start) / 2;
    if(A[mid] == target){
        return mid;
    }else if(A[mid] > target){
        return search_range_helper(A, start, mid-1, target);
    }else{
        return search_range_helper(A, mid+1, end, target);
    }
    
}
/*
 * func: search_range
 * goal: find the starting and ending index of the target in
 *       a sorted array
 * @param A: input integer array A
 * @param n: the length of array A
 * @param target: target value
 * return: a vector containing the starting index and end index
 *         If there doesn't exist, return {-1, -1}
 */
vector<int> search_range(int A[], int n, int target){
    vector<int> result;
    assert(n > 0);
    int target_start = -1;
    int target_end = -1;
    //Use binary search to find the target's first appearence
    int first_found = search_range_helper(A, 0, n-1, target);
    if(first_found == -1){
        result = {target_start, target_end};
        return result;
    }else{
        //Find its left bound
        int left_index = first_found;
        target_start = left_index;
        while(left_index > 0 && A[left_index-1] == target){
            left_index = search_range_helper(A, 0, left_index-1, target);
            if(left_index != -1){
                target_start = left_index;
            }
        }
        
        //Find its right bound
        int right_index = first_found;
        target_end = right_index;
        while(right_index != -1 && right_index < n-1 && A[right_index + 1] == target){
            right_index = search_range_helper(A, right_index+1, n-1, target);
            if(right_index != -1){
                target_end = right_index;
            }
        }
        result = {target_start, target_end};
        return result;
    }
}

Python Code:

# func: find the starting and ending position of a given target value
# @param A: integer list
# @param target: target value
# @return: a list of index [start, end]. If not found, return [-1, -1]
def search_range(A, target):
    if not A:
        return [-1, -1]

    else:
        result = [len(A)-1, 0]
        search_range_helper(A, target, 0, len(A)-1, result)

        if result[0] == len(A)-1 and result[1] == 0 and A[0] != target:
            return [-1, -1]
        else:
            return result

# func: helper function for search_range
# @param A: integer list A
# @param target: target value
# @param start: searching start position
# @param end: searching end position
# @param result: result list
# @return:
def search_range_helper(A, target, start, end, result):
    if start > end:
        return
    else:
        mid = start + (end-start)/2
        #If target value is found
        if A[mid] == target:
            if mid == 0:
                result[0] = 0
            if mid == len(A) - 1:
                result[1] = len(A) - 1

            if 0 < mid < result[0] and A[mid-1] != target:
                result[0] = mid
            else:
                search_range_helper(A, target, start, mid-1, result)

            if result[1] <= mid < len(A)-1 and A[mid+1] != target:
                result[1] = mid
            else:
                search_range_helper(A, target, mid+1, end, result)

        elif A[mid] > target:
            search_range_helper(A, target, start, mid-1, result)
        else:
            search_range_helper(A, target, mid+1, end, result)

There is a cheating way for Python. We can use system library bisect to perform binary search in a list

Python Code Cheating:

def searchRange(self, A, target):
    if not A:
        return [-1, -1]

    left_index = bisect.bisect_left(A, target)
    if left_index == len(A) or A[left_index] != target:
        return [-1, -1]

    right_index = bisect.bisect_right(A, target)
    return [left_index, right_index-1]

Tuesday, April 22, 2014

LeetCode: Search in Rotated Sorted Array

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.


It is the same idea as binary search. But we need to add some more cases to consider. If the left part is in ascending order and target may be found in this part. Do binary search on this part to find the target. If it is not, just find the target in the right part.

C++ Code:

/*
 * func: search_rotated_sorted_array_helper
 * goal: helper function of search_rotated_sorted_array
 * @param A: input integer array
 * @param start: start index of the array
 * @param end: end index of the array
 * @param target: target value
 * return the index of the target, if not exist, return -1
 */
int search_rotated_sorted_array_helper(int A[], int start, int end, int target){
    if(start >= end){
        return A[start] == target ? start : -1;
    }
    int mid = start + (end-start)/2;
    if(target == A[mid]){
        return mid;
    }else if(A[mid] >= A[start]){
        if(A[start] <= target && target < A[mid]){
            return search_rotated_sorted_array_helper(A, start, mid-1, target);
        }else{
            return search_rotated_sorted_array_helper(A, mid+1, end, target);
        }
    }else{
        if(A[mid] < target && target <= A[end]){
            return search_rotated_sorted_array_helper(A, mid+1, end, target);
        }else{
            return search_rotated_sorted_array_helper(A, start, mid-1, target);
        }
    }
}
/*
 * func: search_rotated_sorted_array
 * goal: find the target value in a rotated sorted array
 * @param A: input integer array
 * @param n: size of array
 * @param target: target value
 * return: the index of the target, if not exist, return -1
 */
/*
 * same idea as binary search, just need different conditions
 * complexity: time O(log n), space O(1)
 */
int search_rotated_sorted_array(int A[], int n, int target){
    assert(n > 0);
    return search_rotated_sorted_array_helper(A, 0, n-1, target);
}

Python Code:

# func: search a target in a rotated sorted array
# @param A: integer list A
# @param target: target value
# complexity: time O(log n), space O(1)
def search_rotated_sorted_array(A, target):
    start = 0
    end = len(A) - 1
    while start <= end:
        mid = start + (end-start)/2
        if A[mid] == target:
            return mid
        #If the left part is in ascending order
        elif A[start] <= A[mid]:
            #If the target may be in the normal order part
            if A[start] <= target < A[mid]:
                end = mid-1
            else:
                start = mid+1
        else:
            if A[mid] < target <= A[end]:
                start = mid+1
            else:
                end = mid-1
    return -1

Monday, April 21, 2014

LeetCode: Longest Valid Parentheses

Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.

For "(()", the longest valid parentheses substring is "()", which has length = 2.

Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4.


Just like parentheses matching, we can use a stack to keep the starting index of each valid substring.

C++ Code:

/*
 * func: longest_valid_parentheses
 * goal: find the length of the longest valid parentheses substring
 * @param s: input string s
 * return: the maximum length
 */
int longest_valid_parentheses(string s){
    int max_length = 0;
    int last = -1;
    vector<int> helper;
    for(int i=0; i<static_cast<int>(s.length()); ++i){
        if(s.at(i) == '('){
            helper.emplace_back(i);
        }else{
            if(helper.empty()){
                last = i;
            }else{
                helper.pop_back();
                if(helper.empty()){
                    max_length = max(max_length, i - last);
                }else{
                    max_length = max(max_length, i - helper.back());
                }
            }
                
        }
    }
    return max_length;
}

Python Code:

# func: find the length of the longest valid
#       (well-formed) parentheses substring
# @param s: input parentheses string
# @return: the maximum length
# complexity: time O(n), space O(1)
def longest_valid_parentheses(s):
    #start index of each valid substring
    left = -1

    index = 0
    max_len = 0

    #list for indices of open parentheses
    open_stack = []

    while index < len(s):
        #If it is open parenthesis, add it to the stack
        if s[index] == '(':
            open_stack.append(index)
        else:
            #If we are starting with close parenthesis, we
            #need to change left index of the valid substring
            if not open_stack:
                left = index
            else:
                open_stack = open_stack[:-1]
                if not open_stack:
                    #If the stack is empty, the length will be index - left
                    max_len = max(max_len, index - left)
                else:
                    max_len = max(max_len, index - open_stack[-1])
        index += 1

    return max_len

LeetCode: Next Permutation

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place, do not allocate extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,31,3,2
3,2,11,2,3
1,1,51,5,1


There are four steps to solve this problem:

1. Find the largest element index that num[index] < num[index+1].

2. If there doesn't exist such index, then the list will be in descending order. Reverse the whole list.

3. Find the largest element index' that num[index'] > num[index] and swap them.

4. Reverse the list from index+1 to the end.

C++ Code:

/*
 * func: next_permutation
 * goal: get the next permutation of numbers which is lexicographically next greater one
 * @param num: the vector of numbers
 * return:
 */
void next_permutation(vector<int> &num){
    if(num.size() <= 1){
        return;
    }
    //Start from the end, find the largest index where num[index] < num[index + 1]
    int index = static_cast<int>(num.size()-2);
    while(index >= 0){
        if(num[index] >= num[index+1]){
            --index;
        }else{
            break;
        }
    }
    
    //If there doesn't exist that i, reverse the whole vector
    if(index < 0){
        reverse(num.begin(), num.end());
    }else{
        //Find the largest index' where num[index'] > num[index]
        int index_g = static_cast<int>(num.size()-1);
        while(index_g > index){
            if(num[index_g] > num[index]){
                break;
            }else{
                --index_g;
            }
        }
        //Swap num[index'] and num[index]
        swap(num[index_g], num[index]);
        
        //Reverse from index+1 to the end
        reverse(num.begin()+index+1, num.end());
    }
}

Python Code:

# func: Implement next permutation, which rearranges numbers into the
#       lexicographically next greater permutation of numbers.
# @param num: input number list
# @return: return next permutation
def next_permutation(num):
    if len(num) <= 1:
        return num

    #Find the largest index where num[index] < num[index+1]
    index = len(num)-2
    while index >= 0:
        if num[index] < num[index+1]:
            break
        else:
            index -= 1

    #If there doesn't exist that index, reverse the whole list
    if index < 0:
        return num[::-1]

    #Find the largest index' that num[index'] > num[index]
    index_g = len(num)-1
    while index_g > index:
        if num[index_g] > num[index]:
            break
        else:
            index_g -= 1

    #Swap index_g and index
    tmp = num[index]
    num[index] = num[index_g]
    num[index_g] = tmp

    #Reverse from index + 1 to the end
    num[index+1:] = reversed(num[index+1:])

    return num

LeetCode: Substring with Concatenation of All Words

You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.

For example, given:
S: "barfoothefoobarman"
L: ["foo", "bar"]

You should return the indices: [0,9].
(order does not matter).


The basic idea is to check every possible substring of the given length. Another idea is from online, also start from every possible position, the trick is that when we have n words matched, no matter the n words can formed a valid substring, we can test the next possibility by move forward by one word instead of all words. For example, if the string is "barfoothefoobarman", assume we have "barfoo" now, we can check "foothe" for the next time. Another case, if the string is "barbarfoofoobarman", assume we have "barbar" now, we also can check "barfoo" for the next time. I implemented the first approach in C++, second one in Python.

C++ Code:

/*
 * func: test_substring
 * goal: test if the current subtring match the requirements
 * @param current: current string
 * @param word_length: length of each word
 * @param word_dict: given word dict
 * return: true of false
 */
bool test_substring(const string &current, const size_t& word_length, unordered_map<string, int> word_dict){
    for(int i = 0; i < current.length() - word_length + 1; i += word_length){
        string current_word = current.substr(i, word_length);
        if(word_dict.find(current_word) != word_dict.end() && word_dict[current_word] >= 1){
            word_dict[current_word] -= 1;
        }else{
            return false;
        }
    }
    //Test if all count in word_dict is 0
    for(const auto& it : word_dict){
        if(it.second > 0){
            return false;
        }
    }
    return true;
}

/*
 * func: find_substring_all_concatenation
 * goal: find the starting indices of substrings made of all words once in the set
 * @param S: target string S
 * @param L: vector of words
 * return: vector of starting indices
 */
/*
 * Just test every possible substring
 * complexity: time O(m * n), space O(m) where m is the length of substring, n is the length
               of string S
 */
vector<int> find_substring_all_concatenation(const string& S, const vector<string>& L){
    vector<int> result;
    if(L.size() == 0 || S.size() < L.at(0).size() * L.size()){
        return result;
    }
    
    //Add all words to a map
    unordered_map<string, int> word_dict;
    for(const auto &it : L){
        if(word_dict.find(it) == word_dict.end()){
            word_dict.emplace(it, 1);
        }else{
            word_dict[it] += 1;
        }
    }
    //Test every possible substring with length L.at(0).size() * L.size()
    int length = static_cast<int>(L.at(0).size() * L.size());
    for(int i = 0; i < S.size() - length + 1; i++){
        string current = S.substr(i, length);
        if(word_dict.find(current.substr(0, L.at(0).size())) != word_dict.end()){
            if(test_substring(current, L.at(0).size(), word_dict)){
                result.emplace_back(i);
            }
        }
    }
    
    return result;
}

Python Code:

# func: Find all starting indices of substring(s) in S that is a
#       concatenation of each word in L exactly once and without
#       any intervening characters
# @param S: target string S
# @param L: word list
# @return: a list of starting indices
# complexity: time O(n * m), space O(m * size) where n is the size of string
#             m is the length of a word, size is the number of words in L
def find_substring_concatenation(S, L):
    if len(L) == 0 or len(S) < len(L) * len(L[0]):
        return []
    word_length = len(L[0])
    str_length = len(S)
    result = []
    # put all words in a dict
    word_dict = {}
    for word in L:
        if word in word_dict:
            word_dict[word] += 1
        else:
            word_dict[word] = 1

    for offset in xrange(word_length):
        match_dict = {}

        #start position of the substring
        start = offset

        #counter of the words
        count = 0

        end = offset
        while end + word_length <= str_length:
            current_str = S[end:end+word_length]
            if current_str in word_dict:
                if current_str in match_dict:
                    match_dict[current_str] += 1
                else:
                    match_dict[current_str] = 1

                #If the current word's frequency is less than the dict
                if match_dict[current_str] <= word_dict[current_str]:
                    count += 1

                if count == len(L):
                    result.append(start)

                #If len(L) words have been tested, we can move start forward by
                # one word length
                if (end-start)/word_length + 1 == len(L):
                    current_str = S[start: start+word_length]
                    match_dict[current_str] -= 1
                    if match_dict[current_str] < word_dict[current_str]:
                        count -= 1
                    start += word_length
            else:
                match_dict.clear()
                start = end + word_length
                count = 0

            end += word_length
    return result

Reference Link:

1.Substring with Concatenation of All Words - LeetCode: http://discuss.leetcode.com/questions/210/substring-with-concatenation-of-all-words

Saturday, April 19, 2014

LeetCode: Divide Two Integers

Divide two integers without using multiplication, division and mod operator.


The divide operation can be simulated by subtraction. Use the dividend to subtract divisor each time until the result comes negative. And we can times the divisor by 2 each time to boost the subtraction.

C++ Code:

/*
 * func: divide
 * goal: divide two integers without using mulitiplication, division and mode operator
 * @param dividend
 * @param divisor
 * return: the result
 */
int divide(int dividend, int divisor){
    if(dividend == 0){
        return 0;
    }
    if(divisor == 0){
        throw std::invalid_argument("INVALID DIVISOR");
    }

    long long new_dividend = dividend >= 0 ? static_cast<long long>(dividend) : -static_cast<long long>(dividend);
    long long new_divisor = divisor >= 0 ? static_cast<long long>(divisor) : -static_cast<long long>(divisor);
        
    long long ret = 0;
    while (new_dividend >= new_divisor) {
        long long current_divisor = new_divisor;
        for (int i = 0; new_dividend >= current_divisor; ++i, current_divisor <<= 1) {
            new_dividend -= current_divisor;
            ret += 1 << i;
        }
    }
    //we right shift 31 bits to get the sign bit
    return static_cast<int>(((dividend^divisor)>>31) ? (-ret) : (ret));
}

There is a really weird thing when I tried to submit. Before doing the division, the dividend and divisor had to be casted to long numbers. But that doesn't work if I casted them to long, the system will show time limit exceeded. When I casted them to long long, it works well. But if fact, there should be no difference between long type and long long type, both of which will take 8 bytes.

Python Code:

# func: Divide two integers without using multiplication, division and mod operator.
# @param dividend:
# @param divisor:
# @return:
def divide(dividend, divisor):
    if divisor == 0:
        return None
    #if 3/4 return 0, if -3/4 return -1
    if abs(dividend) < abs(divisor):
        return 0
    #common case
    else:
        new_dividend = abs(dividend)
        new_divisor = abs(divisor)
    
        new_divisor <<= 1
        result = 2
        #keep left shifting until divisor is larger than dividend
        while new_dividend >= new_divisor:
            new_divisor <<= 1
            result <<= 1
    
        #add remaining part
        new_divisor >>= 1
        result >>= 1
        final_result = 0
        while new_dividend >= abs(divisor):
            if new_dividend >= new_divisor:
                new_dividend -= new_divisor
                final_result += result
    
            new_divisor >>= 1
            result >>= 1
    
        if (dividend > 0 and divisor > 0) or (dividend < 0 and divisor < 0):
            return final_result
        else:
            return 0-final_result

Thursday, April 17, 2014

LeetCode: Implement strStr()

Implement strStr().

Returns a pointer to the first occurrence of needle in haystack, or null if needle is not part of haystack.


The naive approach for this problem is to compare from the start and when one mismatch is found, restart from the next position of the haystack. There are also some classic algorithm for this problem, such as Rabin–Karp string search algorithm, which is the similar idea as the naive one; Boyer–Moore string search algorithm, which is complicated but was used in the implementation of glibc. And Knuth–Morris–Pratt algorithm, which used a pre-computed table to boost the searching.

I implemented the naive idea in C++:

/*
 * func: str_str
 * goal: find the first occurence of needle in haystack
 * @param haystack: the source string
 * @param needle: the target string
 * return: the pointer to the first occurence of target string
 * complexity: time O(n^2) where n is the length of haystack
 */
char* str_str(char* haystack, char* needle){
    //If needle is null, return haystack
    if(needle == nullptr || haystack == nullptr){
        return haystack;
    }
    
    size_t haystack_len = strlen(haystack);
    size_t needle_len = strlen(needle);
    if(needle_len > haystack_len){
        return nullptr;
    }
    
    char* p_haystack = haystack;
    while(*(p_haystack+needle_len-1)){
        char* haystack_start = p_haystack;
        char* needle_start = needle;
        while(*haystack_start && *needle_start && *haystack_start == *needle_start){
            ++haystack_start;
            ++needle_start;
        }
        //If needle_start goes to the end, we have find one
        if(! *needle_start){
            return p_haystack;
        }
        ++p_haystack;
    }
    return nullptr;
}

Then I looked up online to find the how each compiler implemented this function. I found some source code from opensource.apple.com, which didn't seem to be real since the codes are not elegant and there were some risks. However, assuming they were true, they also applied the naive way to implement.

/*
 * func: strncmp_libc_apple
 * goal: compare the two string within size n
         http://www.opensource.apple.com/source/Libc/Libc-167/gen.subproj/i386.subproj/strncmp.c
 * @param s1: input string s1
 * @param s2: input string s2
 * @param n: length n
 * return: A zero value indicates that the characters compared 
           in both strings form the same string. A value greater than 
           zero indicates that the first character that does not match 
           has a greater value in str1 than in str2; And a value less 
           than zero indicates the opposite.
 */
int strncmp_libc_apple(s1, s2, n)
register const char *s1, *s2;
register size_t n;
{
    if(n == 0){
        return (0);
    }
    //They really like do while...
    do{
        if(*s1 != *s2++)
            return (*(unsigned char *)s1 - *(unsigned char *)--s2);
        //No check for nullptr?
        if(*s1++ == 0)
            break;
    }while(--n != 0);
    return (0);
}


/*
 * func: str_str_xnu
 * goal: find the first occurence of needle in haystack
         source code from Apple opensource
         http://www.opensource.apple.com/source/xnu/xnu-792.13.8/libsa/strstr.c
 * @param in: input string
 * @param str: target string
 * return: the pointer to the first occurence of target string
 */
char* str_str_xnu(const char *in, const char *str){
    char c;
    size_t len;
    //NOTE: Bad access will occur if str is nullptr
    c = *str++;
    if(!c){
        //Trivial empty string case
        return (char *) in;
    }
    
    len = strlen(str);
    do{
        char sc;
        do{
            sc = *in++;
            if(!sc){
                return (char *) 0;
            }
        }while(sc != c);
    }while(strncmp(in, str, len) != 0);
    
    return (char *)(in-1);
}

/*
 * func: str_str_gcc_apple
 * goal: find the first occurence of needle in haystack
         source code from Apple opensource
         http://opensource.apple.com/source/gcc/gcc-937.2/libiberty/strstr.c
 * @param s1: input string
 * @param s2: target string
 * return: the pointer to the first occurence of target string
 */
char* str_str_gcc_apple(char* s1, char* s2){
    register char *p = s1;
    extern char *strchr();
    extern int strncmp();
#if __GNUC__ == 2
    extern __SIZE_TYPE__ strlen;
#endif
    register int len = strlen(s2);
    
    for(;(p = strchr(p, *s2)) != 0; p++){
        if(strncmp(p, s2, len) == 0){
            return (p);
        }
    }
    return (0);
}

/*
 * func: str_str_sun_apple
 * goal: find the first occurence of needle in haystack
         source code from Apple opensource
 * @param string: input string
 * @param substring: target string
 * return: the pointer to the first occurence of target string
 */
char* str_str_sun_apple(register char *string, char *substring){
    register char *a, *b;
    /* First scan quickly through the two strings looking for a 
     * single-character match. When it's found, then compare the
     * rest of the substring.
     */
    b = substring;
    if(*b == 0){
        return string;
    }
    for(;*string != 0; string += 1){
        if(*string != *b){
            continue;
        }
        a = string;
        while(1){
            if(*b == 0){
                return string;
            }
            if(*a++ != *b++){
                break;
            }
        }
        b = substring;
    }
    return (char *) 0;
}

Then I implemented the KMP one with Python.

Python Code:

# func: implement strstr() function in c, which is used to find the
#       first appearance of target string in base text
# @param needle: target string
# @param haystack: base text string
# @return: the first appearance position of target string
# complexity: time O(m+n), space O(m) where m is the length of target string
#             n is the length of text
def str_str(needle, haystack):
    if not needle:
        return haystack
    else:
        #Build look up table for KMP
        kmp_pre = [-1] * len(needle)
        i = 0
        j = -1
        while i < len(needle):
            #If the current letter is not in the prefix
            #Go backward
            while j > -1 and needle[i] != needle[j]:
                j = kmp_pre[j]
            i += 1
            j += 1
            if needle[i] == needle[j]:
                kmp_pre[i] = kmp_pre[j]
            else:
                #The stop position of the prefix
                kmp_pre[i] = j

        #Start KMP matching
        i = 0
        j = 0
        while j < len(haystack):
            while i > -1 and needle[i] != haystack[j]:
                i = kmp_pre[i]
            i += 1
            j += 1
            if i >= len(needle):
                return j-i
        return None

But the submission results from Online Judge is not quite exciting. I compared the running time of KMP and naive way. The naive way is almost 100ms faster than KMP, which amazed me. I think the cause may be related to the contents of the test cases.

Reference Link:

1.Knuth–Morris–Pratt algorithm: http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm

2.Knuth-Morris-Pratt algorithm: http://www-igm.univ-mlv.fr/~lecroq/string/node8.html

3.Rabin–Karp algorithm: http://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_string_search_algorithm

4.Boyer–Moore string search algorithm: http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm

5.glibc: string/strstr.c Source File: http://fossies.org/dox/glibc-2.19/string_2strstr_8c_source.html

Wednesday, April 16, 2014

LeetCode: Remove Element

Given an array and a value, remove all instances of that value in place and return the new length.

The order of elements can be changed. It doesn't matter what you leave beyond the new length.


C++ Code:

/*
 * func: remove_element
 * goal: remove all elements of a given value in the array
 * @param A: integer array A
 * @param n: the size of the array
 * @param elem: target element
 */
int remove_element(int A[], int n, int elem){
    if(n <= 0){
        return n;
    }else{
        int i = 0;
        int j = n-1;
        while(i <= j){
            if(A[i] == elem){
                while(A[j] == elem){
                    --j;
                }
                if(i > j){
                    break;
                }
                std::swap(A[i], A[j]);
                --j;
            }else{
                ++i;
            }
        }
        return j+1;
    }
}

Python Code:

# func: remove all elements of a given value in the list
# @param A: the given list
# @param elem: target value
# @return: the new length of the list
def remove_list(A, elem):
    end = len(A) - 1
    for i in xrange(len(A)):
        if A[i] == elem:
            while end >= 0 and A[end] == elem:
                end -= 1
            if i >= end:
                break
            A[i] = A[end]
            A[end] = elem

    return end+1

LeetCode: Remove Duplicates from Sorted Array

Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this in place with constant memory.

For example,
Given input array A = [1,1,2],

Your function should return length = 2, and A is now [1,2].


Set up two indices, one for iterating the array, one for keep count of the non-duplicates.

C++ Code:

/*
 * func: remove_duplicates_from_sorted_array
 * goal: given a sorted array, remove the duplicate in place
 * @param A: input array
 * @param n: the length of the array
 * return: the length of the array without duplicates
 */
int remove_duplicates_from_sorted_array(int A[], int n){
    //If the length is less than 1, there is no need to remove
    if(n <= 1){
        return n;
    }
    int current = A[0];
    int i = 1;
    int new_i = 1;
    while(i<n){
        //If the next one is equal to the current one, move to the next
        if(A[i] == current){
            ++i;
        }else{
            //Store the next different element, and move two index forward
            A[new_i] = A[i];
            current = A[new_i];
            ++new_i;
            ++i;
        }
    }
    
    return new_i;
}

Python Code:

# func: remove duplicates from sorted array
# @param A: the list of array
# @return: the length of new array
def remove_duplicates_from_sorted_array(A):
    if len(A) <= 1:
        return len(A)
    else:
        j = 0
        for i in xrange(1, len(A)):
            if A[i] == A[j]:
                continue
            else:
                j += 1
                A[j] = A[i]
        return j+1

LeetCode: Reverse Nodes in k-Group

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.

If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.

You may not alter the values in the nodes, only nodes itself may be changed.

Only constant memory is allowed.

For example,
Given this linked list: 1->2->3->4->5

For k = 2, you should return: 2->1->4->3->5

For k = 3, you should return: 3->2->1->4->5


Find if there are enough nodes to reverse first, then do the reverse. I implemented iterative way in C++, recursive way in Python.

C++ Code:

/*
 * func: reverse_k_nodes
 * goal: reverse k nodes in a linked list. If there are less than k,
 we don't reverse
 * @param head: head node of the linked list
 * @param k: the number of nodes k
 * return: the new head of the linked list
 */
/*
 * 1. Check availability to reverse
 * 2. Get the node next to the kth node,
 and make it as the first previous node
 * 3. Make the head node as current node
 * 4. Make the node next ot head node as the first next node
 * 4. Make current node's next point to previous
 * 5. Change current node to next node
 * 6. Make next node move forward by 1
 */
ListNode* reverse_k_nodes(ListNode* head, int k){
    if(k <= 1 || head == nullptr){
        return head;
    }
    //To check if there are at least k nodes in the current linked list
    int count = 1;
    ListNode* new_head = head;
    while(new_head->next != nullptr && count < k){
        ++count;
        new_head = new_head->next;
    }
    
    if(count < k){
        return head;
    }else{
        //Get node next to the current tail
        ListNode* previous = new_head->next;
        ListNode* current = head;
        ListNode* next = current->next;
        while(current != new_head){
            current->next = previous;
            previous = current;
            current = next;
            next = next->next;
        }
        current->next = previous;
        return new_head;
    }
}

/*
 * func: reverse_k_group
 * goal: reverse the nodes of a linked list k at a time
 * @param head: head node of the linked list
 * @param k: the group number k
 * return: the modified linked list
 */
/*
 * keep reverse k nodes from the head until the reversing fails
 */
ListNode* reverse_k_group(ListNode *head, int k){
    ListNode *old_head = head;
    ListNode *new_head = reverse_k_nodes(old_head, k);
    ListNode *ret = new_head;
    while(new_head != old_head){
        //Get the previous tail node ahead of next k-group
        ListNode *previous_tail = old_head;
        //Get the old head for the next iteration
        old_head = old_head->next;
        //Get the new head for this iteration
        new_head = reverse_k_nodes(old_head, k);
        //Linked the previous tail node and current new head
        previous_tail->next = new_head;
    }
    
    return ret;
}

Python Code:

# func: reverse the nodes of a linked list k at a time and return its modified list
# @param head: head node of the linked list
# @param k: the number of nodes in a group
# return: head node of the modified linked list
def reverse_k_group(head, k):
    if not head or k <= 1:
        return head
    else:
        count = 1
        new_head = head
        while new_head.next and count < k:
            count += 1
            new_head = new_head.next

        #There are not enough to reverse
        if count < k:
            return head
        else:
            #head for the next iteration
            next_head = new_head.next
            current_node = head
            previous_node = next_head
            next_node = head.next
            while next_node != next_head:
                #Make current node point to the previous one
                current_node.next = previous_node
                #Change the previous one to the current one
                previous_node = current_node
                #Change current one to the next one
                current_node = next_node
                #Move next node forward
                next_node = next_node.next
            #Link the last one to the previous one
            current_node.next = previous_node
            #Go to the next iteration
            head.next = reverse_k_group(next_head, k)

            return new_head

Tuesday, April 15, 2014

LeetCode: Swap Nodes in Pairs

Given a linked list, swap every two adjacent nodes and return its head.

For example,
Given 1->2->3->4, you should return the list as 2->1->4->3.

Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed.


There is no trick for this problem. Just do it carefully.

C++ Code:

/*
 * func: swap_pairs
 * goal: swap every two adjacent nodes and return its head
 * @param head: head node of the list
 * return: new head of the list
 */
ListNode* swap_pairs(ListNode *head){
    //If it is a null list or there is only one node in the list, return
    if(head == nullptr || head->next == nullptr){
        return head;
    }
    
    ListNode* new_head = head->next;
    ListNode* current = head;
    ListNode* previous = nullptr;
    while(current != nullptr && current->next != nullptr){
        //Store next node needed to be swaped
        ListNode *next = current->next->next;
        //Link the previous one to the current one's next
        if(previous != nullptr){
            previous->next = current->next;
        }
        //Make current one's next linked to current one
        current->next->next = current;
        //Make current one linked to the next node
        current->next = next;
        //Continue to the next pair
        previous = current;
        current = current->next;
    }
    
    return new_head;
}

Python Code:

# func: swap every two adjacent nodes in a linked list
# @param head: head node of the linked list
# @return: new head
def swap_pairs(head):
    if not head or not head.next:
        return head
    else:
        new_head = head.next
        current = head
        previous = None
        while current and current.next:
            next = current.next.next
            if previous:
                previous.next = current.next

            current.next.next = current
            current.next = next

            previous = current
            current = current.next

        return new_head

Saturday, April 12, 2014

LeetCode: Merge k Sorted Lists

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.


I have two ideas for this problem. One is divide and conquer, merge every two linked lists recursively. The other one is use a heap to store head nodes of each linked list, and each node pop the smallest one and push its successor into the current heap until there is nothing in the heap. I implemented the first approach in C++ and the second one in Python.

C++ Code:

/*
 * func: merge_two_lists
 * goal: merge 2 linked lists into one linked list
 * @param list1: linked list 1
 * @param list2: linked list 2
 * return: the new linked list
 * complexity: time O(n), space O(1)
 */
ListNode* merge_two_lists(ListNode* list1, ListNode* list2){
    ListNode* iter1 = list1;
    ListNode* iter2 = list2;
    ListNode* result_head = nullptr;
    ListNode* result_iter = new ListNode(0);
    //Merge two lists
    while(iter1 != nullptr && iter2 != nullptr){
        if(iter1->val <= iter2->val){
            result_iter->next = iter1;
            iter1 = iter1->next;
        }else{
            result_iter->next = iter2;
            iter2 = iter2->next;
        }
        //Get the head of new list
        if(result_head == nullptr){
            result_head = result_iter->next;
        }
        result_iter = result_iter->next;
    }
    //Concatenate remaining of list1
    while(iter1 != nullptr){
        result_iter->next = iter1;
        iter1 = iter1->next;
        if(result_head == nullptr){
            result_head = result_iter->next;
        }
        result_iter = result_iter->next;
    }
    //Concatenate remaining of list1
    while(iter2 != nullptr){
        result_iter->next = iter2;
        iter2 = iter2->next;
        if(result_head == nullptr){
            result_head = result_iter->next;
        }
        result_iter = result_iter->next;
    }
    
    return result_head;
}

/*
 * func: merge_k_lists_helper
 * goal: recursive function to help merge lists
 * @param lists: vector of head node
 * @param begin: index of list 1
 * @param end: index of list 2
 * return: merged list
 */
ListNode* merge_k_lists_helper(vector<ListNode*> lists, int begin, int end){
    if(begin > end){
        return nullptr;
    }
    if(begin == end){
        return lists.at(begin);
    }
    if(begin + 1 == end){
        return merge_two_lists(lists.at(begin), lists.at(end));
    }
    int mid = begin + (end-begin)/2;
    ListNode* left = merge_k_lists_helper(lists, begin, mid);
    ListNode* right = merge_k_lists_helper(lists, mid+1, end);
    return merge_two_lists(left, right);
}


/*
 * func: merge_k_lists
 * goal: merge k linked list into one linked list
 * @param lists: vector of head node
 * return: the new linked list
 */
/*
 * divide and conquer
 * complexity: time O(nlogk), space O(1)
 */
ListNode* merge_k_lists(vector<ListNode*> lists){
    return merge_k_lists_helper(lists, 0, lists.size()-1);
}

Python Code:

# func: merge k linked list into one list
# @param lists: lists of head nodes
# @return: head node of merged list
def merge_k_lists(lists):
    if not lists:
        return None
    if len(lists) == 1:
        return lists[0]
    head = None
    curr_node = None

    heap = []
    for node in lists:
        if node is not None:
            heapq.heappush(heap, (node.val, node))

    #Use heap to construct
    while heap:
        value, min_node = heapq.heappop(heap)
        if head is None:
            head = min_node

        if curr_node is None:
            curr_node = min_node
        else:
            curr_node.next = min_node
            curr_node = curr_node.next

        min_node = min_node.next

        if min_node is not None:
            heapq.heappush(heap, (min_node.val, min_node))

    return head

Friday, April 11, 2014

LeetCode: Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

For example, given n = 3, a solution set is:

"((()))", "(()())", "(())()", "()(())", "()()()"


Use recursive function to generate each possible string. When there is no open parenthesis, add 1, when the current number of close parenthesis is less than the number of open parenthesis, add one close parenthesis.

C++ Code:

/*
 * func: generate_parenthesis_helper
 * goal: use recrusion to generate each combination
 * @param result: final sets of results
 * @param left_parenthesis: the number of left parenthesis
 * @param right_parenthesis: the number of right parenthesis
 * @param str: current string
 * return: void
 */
void generate_parenthesis_helper(vector<string> &result, int left_parenthesis, int right_parenthesis, string str){
    if(left_parenthesis == 0 && right_parenthesis == 0){
        result.emplace_back(str);
        return;
    }
    
    if(left_parenthesis > 0){
        generate_parenthesis_helper(result, left_parenthesis-1, right_parenthesis + 1, str + "(");
    }
    
    if(right_parenthesis > 0){
        generate_parenthesis_helper(result, left_parenthesis, right_parenthesis-1, str + ")");
    }
}

/*
 * func: generate_parenthesis
 * goal: generate n pairs of parenthesis and they are all well formed
 * @param n: the number of pairs
 * return: all possible pairs
 */
/*
 * Use DFS
 */
vector<string> generate_parenthesis(int n){
    vector<string> result;
    generate_parenthesis_helper(result, n, 0, "");
    return result;
}

Python Code:

# func: recursive function to help generating pairs of parenthesis
# @param result: final result list
# @param left_parenthesis: number of left parenthesis in current string
# @param right_parenthesis: number of right parenthesis in current string
# @param num: total number of pairs
# @param str: current string
# @return: nothing
def generate_parenthesis_helper(result, left_parenthesis, right_parenthesis, num, str):
    if left_parenthesis == num and right_parenthesis == num:
        result.append(str)
        return
    if left_parenthesis < num:
        generate_parenthesis_helper(result, left_parenthesis+1, right_parenthesis, num, str+'(')
    if right_parenthesis < left_parenthesis <= num:
        generate_parenthesis_helper(result, left_parenthesis, right_parenthesis+1, num, str+')')

# func: to generate all possible n pairs of parenthesis
# @param n: the number of pairs
# @return: return a list of possible pairs
def generate_parenthesis(n):
    if n <= 0:
        return []
    else:
        result = []
        generate_parenthesis_helper(result, 0, 0, n, '')
        return result

LeetCode: Valid Parentheses

Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.

The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not.


Use a stack to help matching

C++ Code:

/*
 * func: valid_parentheses
 * goal: to check if parentheses in current string match
 * @param s: input string
 * return: true or false
 */
/*
 * Use stack
 * complexity: time O(n), space O(n)
 */
bool valid_parentheses(const string &s){
    stack<char> stk;
    for(auto it = s.cbegin(); it != s.cend(); ++it){
        if(*it == '(' || *it == '[' || *it == '{'){
            stk.emplace(*it);
        }else if(!stk.empty()){
            if(*it == ')' && stk.top() == '('){
                stk.pop();
            }else if(*it == ']' && stk.top() == '['){
                stk.pop();
            }else if(*it == '}' && stk.top() == '{'){
                stk.pop();
            }else{
                return false;
            }
        }else{
            return false;
        }
    }
    if(stk.empty()){
        return true;
    }else{
        return false;
    }
}

Python Code:

# func: to check if parentheses in the string match
# @param s: input string
# @return: True or False
# complexity: time O(n), space O(n)
def valid_parentheses(s):
    if not s:
        return False
    else:
        stack = []
        for parenthesis in s:
            if parenthesis in '([{':
                stack.append(parenthesis)
            elif stack and (parenthesis == ']' and stack[-1] == '[' 
or parenthesis == ')' and stack[-1] == '(' or
            parenthesis == '}' and stack[-1] == '{'):
                stack = stack[:-1]
            else:
                return False

        if not stack:
            return True
        else:
            return False

LeetCode: Remove Nth Node From End of List

Given a linked list, remove the nth node from the end of list and return its head.

For example,

   Given linked list: 1->2->3->4->5, and n = 2.

   After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:
Given n will always be valid.
Try to do this in one pass.


We can use two pointers, one is fast and one is slow. Make the fast node move first n-1 steps, then start moving two nodes together.

C++ Code:

/*
 * func: remove_nth_from_end
 * goal: remove the nth node from the end the list in one pass
 * @param head: the head of the list
 * @param n: the nth
 * return: the head of the linked list
 */
/*
 * use two pointers, one slow pointer and one fast pointer, make the fast
 * pointer ahead of slow pointer n steps
 */
ListNode* remove_nth_from_end(ListNode *head, int n){
    if(head == nullptr || n < 1){
        return head;
    }
    ListNode *fast = head;
    ListNode *slow = head;
    //Record the previous node of slow
    ListNode *pre_slow = nullptr;
    int counter = 1;
    
    //Move fast ahead
    while(fast->next != nullptr && counter < n){
        fast = fast->next;
        ++counter;
    }
    //If there are not enough nodes
    if(counter < n){
        return head;
    }
    
    //Move all nodes
    while(fast->next != nullptr){
        fast = fast->next;
        pre_slow = slow;
        slow = slow->next;
        
    }
    
    //Cancatenate nodes
    if(pre_slow != nullptr){
        //Not head node removed
        pre_slow->next = slow->next;
    }else{
        head = head->next;
    }
    
    return head;
}

Python Code:

# func: remove the nth node from end of the list
# @param head: head node of the list
# @param n: input number n
# @return: the head node
def remove_nth_from_end(head, n):
    if not head or n < 1:
        return head
    else:
        #Fast node to move first
        fast = head
        #Slow node to move later
        slow = head
        #node ahead of slow node
        pre_slow = None
        counter = 1

        #Start moving fast node
        while fast.next is not None and counter < n:
            fast = fast.next
            counter += 1

        #Check if there are enough nodes
        if counter < n:
            return head

        #Move all nodes forward
        while fast.next is not None:
            fast = fast.next
            pre_slow = slow
            slow = slow.next

        #Remove node
        #If head node is removed
        if pre_slow is None:
            head = head.next
        else:
            pre_slow.next = slow.next

        return head

LeetCode: Letter Combinations of a Phone Number

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.


A easy problem. Do DFS to construct the results.

C++ Code:

/*
 * func: letter_combinations_helper
 * goal: DFS search function to construct results
 * @param digits: remaining digits string
 * @param output: current output string
 * @param result: result set
 * return: no return value needed
 */
void letter_combinations_helper(string digits, string output, vector<string> &result,){
    if(digits.size() == 0){
        //No more digits reading need
        result.emplace_back(output);
        return;
    }
    switch(digits[0]){
        case '2':
            letter_combinations(digits.substr(1), result, output + 'a');
            letter_combinations(digits.substr(1), result, output + 'b');
            letter_combinations(digits.substr(1), result, output + 'c');
            break;
        case '3':
            letter_combinations(digits.substr(1), result, output + 'd');
            letter_combinations(digits.substr(1), result, output + 'e');
            letter_combinations(digits.substr(1), result, output + 'f');
            break;
        case '4':
            letter_combinations(digits.substr(1), result, output + 'g');
            letter_combinations(digits.substr(1), result, output + 'h');
            letter_combinations(digits.substr(1), result, output + 'i');
            break;
        case '5':
            letter_combinations(digits.substr(1), result, output + 'j');
            letter_combinations(digits.substr(1), result, output + 'k');
            letter_combinations(digits.substr(1), result, output + 'l');
            break;
        case '6':
            letter_combinations(digits.substr(1), result, output + 'm');
            letter_combinations(digits.substr(1), result, output + 'n');
            letter_combinations(digits.substr(1), result, output + 'o');
            break;
        case '7':
            letter_combinations(digits.substr(1), result, output + 'p');
            letter_combinations(digits.substr(1), result, output + 'q');
            letter_combinations(digits.substr(1), result, output + 'r');
            letter_combinations(digits.substr(1), result, output + 's');
            break;
        case '8':
            letter_combinations(digits.substr(1), result, output + 't');
            letter_combinations(digits.substr(1), result, output + 'u');
            letter_combinations(digits.substr(1), result, output + 'v');
            break;
        case '9':
            letter_combinations(digits.substr(1), result, output + 'w');
            letter_combinations(digits.substr(1), result, output + 'x');
            letter_combinations(digits.substr(1), result, output + 'y');
            letter_combinations(digits.substr(1), result, output + 'z');
            break;
        default:
            letter_combinations(digits.substr(1), result, output);
            break;
    }
}

/*
 * func: letter_combinations_helper
 * goal: to find all possible combinations based on input digits
 * @param digits: input digits string
 * return: vector containing all possible combinations
 */
vector<string> letter_combinations(string digits) {
    vector<string> result;
    letter_combinations_helper(digits, "", result,);
    return result;
}

Python Code:

# func: to find all possible combinations based on input digits
# @param digits: input digits string
# @return: all possible combinations
def letter_combinations(digits):
    num_dict = {'2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl', '6': 'mno',
    '7': 'pqrs', '8': 'tuv', '9': 'wxyz'}
    result = ['']
    for digit in digits:
        if digit in '23456789':
            result = [x + letter for x in result for letter in num_dict[digit]]
            
    return result

LeetCode: 4Sum

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

  • Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, abcd)
  • The solution set must not contain duplicate quadruplets.

    For example, given array S = {1 0 -1 0 -2 2}, and target = 0.

    A solution set is:
    (-1,  0, 0, 1)
    (-2, -1, 1, 2)
    (-2,  0, 0, 2)


The basic idea for this problem is the same as 3Sum. Sort first and then try every combination.

C++ Code:

/*
 * func: four_sum
 * goal: to find four numbers in a vector that can sum up to the
 given target
 * @param num: input number vector
 * @param target: the given target
 * return: all combinations in non-descending order
 */
/*
 * Do in the same way as 3sum
 * complexity: time O(n^3), space O(1)
 */
vector<vector<int> > four_sum_a(vector<int> num, int target){
    vector<vector<int> > result;
    if(num.size() < 4){
        return result;
    }
    sort(num.begin(), num.end());
    int size = static_cast<int>(num.size());
    for(int i = 0; i < size; ++i){
        //Avoid duplicate cases
        if(i != 0 && num[i] == num[i-1]){
            continue;
        }
        for(int j = size-1; j > 0; --j){
            //Avoid duplicate cases
            if(j != size-1 && num[j] == num[j+1]){
                continue;
            }
            
            int left = i+1, right = j-1;
            while(left < right){
                int sum = num[i] + num[left] + num[right] + num[j];
                //Duplicate case
                if(left != i+1 && num[left] == num[left-1]){
                    ++left;
                }else if(right != j-1 && num[right] == num[right+1]){
                    --right;
                }else if(sum > target){
                    --right;
                }else if(sum < target){
                    ++left;
                }else{
                    result.push_back({num[i], num[left], num[right], num[j]});
                    ++left;
                    --right;
                }
            }
        }
    }
    return result;
}

Python Code:

# func: to find 4 numbers in a list that sum up to the target
# @param num: the input list
# @param target: the target value
# @return: all possible combinations
def four_sum(num, target):
    if len(num) < 4:
        return []
    else:
        result = []
        num.sort()
        for first in xrange(len(num)-3):
            if first > 0 and num[first] == num[first-1]:
                continue
            second = len(num) - 1
            while second > first:
                if second != len(num)-1 and num[second] == num[second+1]:
                    second -= 1
                    continue
                third = first+1
                fourth = second-1
                while third < fourth:
                    #Add these to boost so that it can pass large case
                    if num[first] + num[third] + num[third] + num[second] > target:
                        break
                    if num[first] + num[fourth] + num[fourth] + num[second] < target:
                        break
                    sum = num[first] + num[third] + num[fourth] + num[second]
                    if third != first+1 and num[third] == num[third-1]:
                        third += 1
                    elif fourth != second-1 and num[fourth] == num[fourth+1]:
                        fourth -= 1
                    elif sum > target:
                        fourth -= 1
                    elif sum < target:
                        third += 1
                    else:
                        result.append([num[first], num[third], num[fourth], num[second]])
                        third += 1
                        fourth -= 1

                second -= 1
        return result

For the Python code, at first I just translates the code from C++. But it cannot pass large case... So I searched online and found that the code can still be optimized. When the double value of third is larger than target or double value of fourth is smaller than the target, there is no need to perform searching any more. Since all elements behind third is larger than third and elements ahead of fourth is less than fourth. It made me know that I need to keep thinking how to avoid unnecessary calculations all the time. Good lesson.

There is another solution which said can run in O(n^2) times. The idea is keeping all pair values of the elements first and then the problem can be formed to a 2sum problem. The total running time is O(n^2). I tried to implement that but failed. We can keep the pair sum as key and elements indices that form the sum. There is a problem here, if there are multiple pairs of elements that can get the same sum. Then we need to consider every combinations. These will not complete within O(n^2) time. And it will make problem more complicated such as what if there is only one pair sum value after computation? ({0,0,0,0,0,0} and target is 0?)

Reference Link:

1.4Sum - LeetCode: http://discuss.leetcode.com/questions/199/4sum

2.Solution to 4Sum by LeetCode: http://codesays.com/2014/solution-to-4sum-by-leetcode/