Saturday, May 31, 2014

LeetCode: Copy List with Random Pointer

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

Return a deep copy of the list.


We can copy each nodes first and make the copied node connected to the old one. And then it is easier to copy the random pointer by node.next.random = node.random.next because each node, its next node is its copied node.

C++ Code:

/*
 * func: copy_list_with_random_pointer
 * goal: deep copy a list with random pointer
 * @param head: head node of the list
 * return: new head node of the list
 */
RandomListNode *copy_list_with_random_pointer(RandomListNode *head){
    if(head == nullptr){
        return nullptr;
    }
    
    RandomListNode *iter = head;
    //Copy the list sequentially first
    //t1->t1_cpy->t2->t2_cpy->NULL
    while(iter != nullptr){
        //Get current node's next first
        RandomListNode *next = iter->next;
        //Copy current node
        iter->next = new RandomListNode(iter->label);
        //Connect copied node to the next node
        iter->next->next = next;
        //Go to the next node
        iter = next;
    }

    iter = head;
    while(iter != nullptr){
        //Get current node's next node first
        RandomListNode *next = iter->next->next;
        //Copy random pointer
        iter->next->random = iter->random == nullptr ? nullptr : iter->random->next;
        //Go to the next node
        iter = next;
    }
    
    //Set the new head
    RandomListNode *new_head = head->next;
    iter = head;
    while(iter != nullptr){
        RandomListNode *next = iter->next->next;
        //Connect the current node's next to the next node's copy node
        iter->next->next = next == nullptr ? nullptr : next->next;
        //Re-connect current node to its original next node
        iter->next = next;
        //Go to the next node
        iter = next;
    }


    return new_head;
}

Python Code:

# func: copy linked list with random pointers
# @param head: head node of the list
# @return: new head node
def copy_random_list(head):
    if not head:
        return None

    #Copy nodes first
    curr = head
    while curr:
        next_node = curr.next
        curr.next = RandomListNode(curr.label)
        curr.next.next = next_node
        curr = next_node

    #Copy random pointer
    curr = head
    while curr:
        next_node = curr.next.next
        curr.next.random = curr.random.next if curr.random else None
        curr = next_node

    #Split two lists
    new_head = head.next
    curr = head
    while curr:
        next_node = curr.next.next
        curr.next.next = next_node.next if next_node else None
        curr.next = next_node
        curr = next_node
    return new_head

LeetCode: Single Number II

Given an array of integers, every element appears three times except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?


We can solve this in bit level. Each integer is also a bit array of size 32. We can count the number of 1 occurred in each bit. If its 4 or 1, then the bit of the single number is also 1. Otherwise it is 0.

C++ Code:

/*
 * func: single_number
 * goal: find the single number in an array that occurs once
 * @param A: input array A
 * @param n: size of the array
 * return: the single number
 */
int singleNumber(int A[], int n) {
    vector<int> tmp;
    for(int i = 0; i < 32; ++i){
        int bit_count = 0;
        int curr_bit = 1 << i;
        for(int j = 0; j < n; j++){
            if(A[j] & curr_bit)
                ++bit_count;
        }
        (bit_count % 3) ? tmp.emplace_back(1) : tmp.emplace_back(0);
    }
    int num = 1;
    int result = 0;
    for(const int &digit : tmp){
        if(digit){
            result += num;
        }
        num <<= 1;
    }
    return result;
}

Python Code:

# func: find the single number in a list
# @param A: input list
# @return: single number
def single_numer(A):
    if not A:
        return 0
    digits = []
    for i in xrange(32):
        curr = 1 << i
        digit_count = 0
        for num in A:
            if num & curr:
                digit_count += 1
        if digit_count % 3:
            digits.append(1)
        else:
            digits.append(0)

    result = 0
    bit_helper = 1
    for digit in digits:
        if digit == 1:
            result += bit_helper
        bit_helper <<= 1

    if digits[-1] == 1:
        return result - (1 << 32)
    else:
        return result

LeetCode: Single Number

Given an array of integers, every element appears twice except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?


We can use the binary operation xor to find out the single number. Since a xor a = 0 and 0 xor 0 = 0 and 0 xor 1 = 1.

C++ Code:

/*
 * func: single_number
 * goal: find the single number in an array that occurs once
 * @param A: input array A
 * @param n: size of the array
 * return: the single number
 */
int single_number(int A[], int n){
    if(n <= 0){
        return 0;
    }
    int num = A[0];
    for(int i=1; i<n; ++i){
        num ^= A[i];
    }
    return num;
}

Python Code:

# func: find the single number in a list
# @param A: input list
# @return: single number
def single_numer(A):
    if not A:
        return 0
    result = A[0]
    for i in xrange(1, len(A)):
        result ^= A[i]

    return result

LeetCode: Candy

There are N children standing in a line. Each child is assigned a rating value.

You are giving candies to these children subjected to the following requirements:

  • Each child must have at least one candy.
  • Children with a higher rating get more candies than their neighbors.

What is the minimum candies you must give?


We can start distribution by giving each child 1 candy. And then if child i has a higher rating than child i-1, give him one more. Then from back to the front, if child i has a higher rating than child i+1, given him the number of candies as child i+1's plus 1.

C++ Code:

/*
 * func: candy
 * goal: find the minimum candies needed to distribute
 * @param ratings: ratings of the children
 * return: minimum candies
 */
/*
 * distribute from start to end and then from end to start
 * complexity: time O(n), space O(n)
 */
int candy(vector<int> &ratings){
    if(ratings.size() == 0){
        return 0;
    }
    vector<int> candies(ratings.size(), 0);
    candies[0] = 1;
    for(int i = 1; i < ratings.size(); ++i){
        //If the child's ratings at i is higher than i-1, he should have at least one more candy
        candies[i] = ratings[i] > ratings[i-1] ? candies[i-1]+1 : 1;
    }
    //check from end to the start to ensure every child get what they need to have
    int total_candy = candies[ratings.size() - 1];
    for(int i = ratings.size() - 2; i >= 0; --i){
        candies[i] = (ratings[i] > ratings[i+1] && candies[i+1] + 1 > candies[i]) ? candies[i+1] + 1 : candies[i];
        total_candy += candies[i];
    }
    return total_candy;
}

Python Code:

# func: find the minimum candies
# @param ratings: the ratings of child
# @return: minimum candies needed
# complexity: time O(n), space O(n)
def candy(ratings):
    if not ratings:
        return 0
    candies = [1] * len(ratings)
    for i in xrange(1, len(ratings)):
        if ratings[i] > ratings[i-1]:
            candies[i] = candies[i-1]+1

    total_candies = candies[-1]
    for i in xrange(len(ratings)-2, -1, -1):
        if ratings[i] > ratings[i+1] and candies[i] < candies[i+1] + 1:
            candies[i] = candies[i+1]+1
        total_candies += candies[i]

    return total_candies

LeetCode: Gas Station

There are N gas stations along a circular route, where the amount of gas at station i is gas[i].

You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.

Return the starting gas station's index if you can travel around the circuit once, otherwise return -1.

Note:
The solution is guaranteed to be unique.


Since it is a circle, we can assume the start point is 0, when the gas is not enough to use, we can make the start point backwards one stop and see if current start point is available.

C++ Code:

/*
 * func: can_complete_circuit
 * goal: find the starting gas station that can make the truck travel the circuit
 * @param gas: gas vector
 * @param cost: cost vector
 * return: starting index
 */
int can_complete_circuit(vector<int> &gas, vector<int> &cost){
    int stop_num = gas.size();
    int start = 0;
    int end = stop_num-1;
    int current = 0;
    int remaining = 0;
    while(current <= end){
        remaining += gas[current] - cost[current];
        while(remaining < 0 && end != current){
            start = end;
            end = end-1;
            remaining += gas[start] - cost[start];
        }
        ++current;
    }
    
    return remaining < 0 ? -1 : start;
}

Python Code:

# func: find the starting gas station that can make the truck travel the circuit
# @param gas: gas list
# @param cost: cost list
# @return: the start position
def can_complete_circuit(gas, cost):
    start = 0
    end = len(gas)-1
    current = 0
    remaining = 0
    while current <= end:
        remaining += gas[current] - cost[current]
        while remaining < 0 and current != end:
            start = end
            end -= 1
            remaining += gas[start] - cost[start]
        current += 1

    if remaining < 0:
        return -1
    else:
        return start

LeetCode: Clone Graph

Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.


We can use BFS to search the graph can clone it at the same time. A map can be used to store those nodes that are already cloned.

C++ Code:

/*
 * func: clone_graph_helper
 * goal: helper function to perform BFS
 * @param node: current node to be cloned
 * @param visited: node already existed in the new graph
 * return: newly cloned node
 */
UndirectedGraphNode *clone_graph_helper(UndirectedGraphNode *node, unordered_map<int, UndirectedGraphNode*> &visited){
    UndirectedGraphNode *new_node = new UndirectedGraphNode(node->label);
    visited[node->label] = new_node;
    for(int i = 0; i < node->neighbors.size(); ++i){
        if(visited.find(node->neighbors[i]->label) != visited.end()){
            new_node->neighbors.emplace_back(visited[node->neighbors[i]->label]);
        }else{
            new_node->neighbors.emplace_back(clone_graph_helper(node->neighbors[i], visited[node->neighbors[i]->label]));
        }
    }
    
    return new_node;
}

/*
 * func: clone_graph
 * goal: clone a undirected graph
 * @param node: a start node
 * return: a cloned start node
 */
UndirectedGraphNode *clone_graph(UndirectedGraphNode *node){
    if(node == nullptr){
        return nullptr;
    }
    unordered_map<int, UndirectedGraphNode*> visited;
    UndirectedGraphNode* new_node = clone_graph_helper(node, visited);
    return new_node;
}

Python Code:

# func: clone graph
# @param node: start node
# @return: new start node
def clone_graph(node):
    if not node:
        return None

    visited = {}
    def clone_graph_helper(start):
        new_node = UndirectedGraphNode(start.label)
        visited[start.label] = new_node
        for neighbor in start.neighbors:
            if neighbor.label in visited:
                new_node.neighbors.append(visited[neighbor.label])
            else:
                new_node.neighbors.append(clone_graph_helper(neighbor))
        return new_node

    return clone_graph_helper(node)

Friday, May 30, 2014

LeetCode: Palindrome Partitioning II

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.


The problem can be transformed to the following: minimum[i:n] means the minimum cut we needed for substring s[i:n], and it could be the minimum of minimum[j+1:n]+1 for all i <= j < n.

C++ Code:

/*
 * func: min_cut
 * goal: find the minimum number of min_cut so that each partition is a palindrome
 * @param s: input string
 * return: minimum cut
 */
int min_cut(string s){
    size_t str_length = s.length();
    if(str_length == 0){
        return 0;
    }
    //a 2D array which indicate if substring(i, j) is a palindrome
    vector<vector<bool> > palindrome(str_length, vector<bool>(str_length, false));
    for(int i = 0; i < str_length; ++i){
        //Check palindrome taking s[i] as symmetry axis
        int left = i;
        int right = i;
        while(left >= 0 && right < str_length && s[left] == s[right]){
            palindrome[left][right] = true;
            --left;
            ++right;
        }
        //Check palindrome taking s[i] s[i+1] as symmetry axis
        left = i;
        right = i+1;
        while(left >= 0 && right < str_length && s[left] == s[right]){
            palindrome[left][right] = true;
            --left;
            ++right;
        }
    }
    vector<int> minimum_cut(str_length, str_length);
    for(int i = 0; i < str_length; ++i){
        if(palindrome[0][i]){
            minimum_cut[i] = 0;
        }else{
            int min_cut_now = str_length;
            for(int j = 1; j <= i; ++j){
                if(palindrome[j][i] && min_cut_now > minimum_cut[j-1] + 1){
                    min_cut_now = minimum_cut[j-1] + 1;
                }
            }
            minimum_cut[i] = min_cut_now;
        }
    }
    return minimum_cut.back();
}

Python Code:

# func: find the minimum cut needed for a palindrome partitioning of string
# @param s: input string
# @return: minimum cut
def min_cut(s):
    if not s:
        return 0
    palindrome = [[False] * len(s) for _ in xrange(len(s))]
    minimum_cut = [len(s) - i for i in xrange(len(s)+1)]
    for i in xrange(len(s)-1, -1, -1):
        for j in xrange(i, len(s)):
            if s[i] == s[j] and (j-i < 2 or palindrome[i+1][j-1]):
                palindrome[i][j] = True
                minimum_cut[i] = min(minimum_cut[i], minimum_cut[j+1] + 1)

    return minimum_cut[0]-1

Reference Link:

1. 水中的鱼: [LeetCode] Palindrome Partitioning II, Solution: http://fisherlei.blogspot.com/2013/03/leetcode-palindrome-partitioning-ii.html