2015年8月25日星期二

Lintcode: Jump Game


Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
Have you met this question in a real interview? 
Yes
Example
A = [2,3,1,1,4], return true.
A = [3,2,1,0,4], return false.
Note
This problem have two method which is Greedy and Dynamic Programming.
The time complexity of Greedy method is O(n).
The time complexity of Dynamic Programming method is O(n^2).
We manually set the small data set to allow you pass the test in both ways. This is just to let you learn how to use this problem in dynamic programming ways. If you finish it in dynamic programming ways, you can try greedy method to make it accept again.
Tags Expand 

Algorithm reference: http://yucoding.blogspot.com/2013/01/leetcode-question-28-jump-game.html
Note: when use vector as parameters of a function, it is passed by value, not by address.

DP:
use a hashmap hash[] to record an bool array to remember whether each position be arrived
for each element located at a of A from left to right:
      if hash[a] is true, set positions within A[a] is  true;
      if not, break the loop
Check whether the last element is true.

Time: O(n^2)
Space: O(n)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
    /**
     * @param A: A list of integers
     * @return: The boolean answer
     */
    bool canJump(vector<int> A) {
        // write you code here
        if(A.size() == 0) return false;
        vector<bool> record(A.size(), false);
        record[0] = true;
        for(int i = 0; i < A.size(); i++){
            if(record[i]){
                for(int j = 0; j < A[i]; j++){
                    record[i + j + 1] = true;
                }
            }
            else break;
        }
        return record[A.size() - 1];
    }
};

Greedy:
From the DP, we can easily see that there is a boundary in record array, all positions before that boundary is true, after that is false. So we just need to record the boundary ---- the max position that all elements before current elements can arrive.

Time: O(n)
Space: O(1)

sudo codes:
int mIdx = 0;
For ith element of array A
        if(i > mIdx) return false;
        else mIdx = max(i + A[i], mIdx);
return (A.size() - 1 <= mIdx)? true: false;


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Solution {
public:
    /**
     * @param A: A list of integers
     * @return: The boolean answer
     */
    bool canJump(vector<int> A) {
        // write you code here
        if(A.size() == 0) return false;
        int mIdx = 0;
        for(int i = 0; i < A.size(); i++){
            if(i > mIdx) break;
            mIdx = max(i + A[i], mIdx);
        }
        return A.size() - 1 <= mIdx ? true: false;
    }
};


Lintcode second:
O(n) dp solution:
dp[i] -- farthest index the ith index can jump to
if(i <= dp[i - 1]) dp[i] = max(dp[i - 1], i + A[i])


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
    /**
     * @param A: A list of integers
     * @return: The boolean answer
     */
    bool canJump(vector<int> A) {
        // write you code here
        if(A.size() <= 1) return true;
        vector<int> dp(A.size());
        dp[0] = A[0];
        for(int i = 1; i < A.size(); i++){
            if(dp[i - 1] >= i) dp[i] = max(dp[i - 1], i + A[i]);
            else return false;
        }
        if(dp[A.size() - 1] >= A.size() - 1) return true;
        return false;
    }
};

2015年8月21日星期五

Lintcode: Delete Digits

Given string A representative a positive integer which has N digits, remove any k digits of the number, the remaining digits are arranged according to the original order to become a new positive integer.
Find the smallest integer after remove k digits.
N <= 240 and k <= N,
Have you met this question in a real interview?
Yes
Example
Given an integer A = "178542", k = 4
return a string "12"
Tags Expand 


Related Problems Expand 

Initial thoughts(wrong):

Compare the effects of each digit in A. So we need to sort the digits. The effect can be measured the number after removing the corresponding digit from A.
However, this solution is wrong. Because each time we delete one digit, the effect of each digit removal has already changed. If we update the effect array each time we delete one digit, Time complexity will become O(knlogn).
Terrible solution...
Below is the wrong solution and wrong test result:


class Solution {
public:
    /**
     *@param A: A positive integer which has N digits, A is a string.
     *@param k: Remove k digits.
     *@return: A string
    */
    static bool comp(pair<int, string> p1, pair<int, string> p2){
        return p1.second < p2.second;
    }
     
    string DeleteDigits(string A, int k) {
        // wirte your code here
        vector< pair<int, string> > digVal;
        for(int i = 0; i < A.size(); i++){
            string str = A;
            str.erase(i, 1);
            pair<int, string> p = make_pair(i, str);
            digVal.push_back(p);
        }
        sort(digVal.begin(), digVal.end(), comp);
        for(int i = 0; i < k; i++){
            A.replace(digVal[i].first, 1, "t");
        }
        for(int i = 0; i < A.size(); i++){
            if(A[i] == 't') A.erase(i--, 1);
        }
        return A;
    }
};

Input
178542, 4
Output
17
Expected
12

Second try: Greedy
Now we know each time we delete one digit, we have to research the next element we should delete.
To make the result as small as possible, the deletion has to start from the left side.
When we delete one digit, it will be replaced by the digit behind it. So if we want the number to be smaller, we need delete the first digit that is larger than the digit behind itself. If we cannot find one, just delete the last digit.
Time: O(kn)
space: O(1)
e.g.  178542      delete 8 ==>  17542  delete 7  ==> 1542 delete 5 ==> 142 delete 4 ==> 12


class Solution {
public:
    /**
     *@param A: A positive integer which has N digits, A is a string.
     *@param k: Remove k digits.
     *@return: A string
     */
    string DeleteDigits(string A, int k) {
        // wirte your code here
        for(int i = 0; i < k; i++){
            for(int j = 0; j < A.size(); j++){
                if(j == A.size() -1 || A[j] > A[j + 1]){
                A.erase(j, 1);
                break;
                }
            }
        }
        while(A.front() == '0'){
            A.erase(0,1);
        }
        return A;
    }
};

Optimized Greedy -- two pointers:
In the above codes, each loop starts comparison from 0. Actually it's not necessary. Numbers already compared don't need to be compared again. We can use j to record it.
Worst time: O(2n) ----e.g. input (123451, 6)
Space: O(1)

class Solution {
public:
    /**
     *@param A: A positive integer which has N digits, A is a string.
     *@param k: Remove k digits.
     *@return: A string
     */
    string DeleteDigits(string A, int k) {
        // wirte your code here
        int j = 0;
        for(int i = 0; i < k; i++){
            for(; j < A.size(); j++){
                if(j == A.size() -1 || A[j] > A[j + 1]){
                    A.erase(j,1);
                    j--;
                    if(j == -1) j = 0; //in case j= 0, then j-- be -1
                    break;
                }
            }
        }
        while(A.front() == '0'){
            A.erase(0,1);
        }
        return A;
    }
};
Optimized Greedy -- stack:
Use a stack to remember those numbers which have been compared.
Worst time: O(2n) -- e.g. input (123451, 6)
Space: O(n)
http://www.cnblogs.com/easonliu/p/4507657.html
STL--string.substr()
STL--string.erase()

The thoughts are a little different;
Before storing each digit from left to right, it will check whether the top element in stack is larger than current digit:
 if larger, keep poping until there is one element in the stack is small or equal to the current digit or the stack is empty, then push current digit,
 if not, just push current element.
The method above makes sure all elements stored in stack are sorted from small to large, by poping all large elements before pushing new element.
However, this method means we only do element removal when new element is small than top element in stack. Which means the removal times may be smaller than k.
For sorted digits from small to big,  we just need to delete the last element to get the smallest number.

Deal with exceptions: How to push 0:
Two cases:
when the new coming element is 0, then all elements in stack will be cleared except count == k
If 0 is the first element in stack, we don't need this 0
If count already equals to k and stack is not empty, we need this 0
So we need 0 when stack is not empty, don't need 0 when stack is empty.
Logical relationship above is (A[i] != '0' || !str.empty()) in Line 17

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
    /**
     *@param A: A positive integer which has N digits, A is a string.
     *@param k: Remove k digits.
     *@return: A string
     */
    string DeleteDigits(string A, int k) {
        string str;
        int count = 0;
        for(int i = 0; i < A.size(); i++){
             while(!str.empty() && str.back() > A[i] && count < k){
                 str.pop_back();
                 count++;
             }
             //if 0 appear, all elements in stack will be cleared except c=k
             if(A[i] != '0' || !str.empty()) str.push_back(A[i]);
        }
        //in case, when all numbers in stack are already from low to high
        //just delete from the end
        if(count < k) str.erase(str.end() - (k - count), str.end());
        return str;
    }
};


Try DP and DFS solution: even though they are not good one

http://blog.csdn.net/wankunde/article/details/43792369



2015年8月20日星期四

Lintcode: Largest Number

Given a list of non negative integers, arrange them such that they form the largest number.
Have you met this question in a real interview? 
Yes
Example
Given [1, 20, 23, 4, 8], the largest formed number is 8423201.
Note
The result may be very large, so you need to return a string instead of an integer.
Tags Expand 




STL: sort 
String compare

Codes reference: http://leetcodesolution.blogspot.com/2015/01/leetcode-largest-number.html

Thought:
At first, I think of creating 10 sets to store numbers begin with 0 to 9. However, problem is how to sort numbers begin with the same number. We have to judge those numbers by their bit like
35, 351, 34, 33, 3, 32, 323
A simple way is to compare str1+ str2 & str2 + str1. String is able to compare according to ASICII order. Since the digits of two strings are same, the string comparison can be used to directly compare the integer expressed from string.

Time: O(nlogn)   -- quicksort
Space: O(1)

class Solution {
public:
    /**
     *@param num: A list of non negative integers
     *@return: A string
     */
    static bool mycomp(int a, int b){  //don't forget static
       return to_string(a) + to_string(b) < to_string(b) + to_string(a);
    } 
     
    string largestNumber(vector<int> &num) {
        // write your code here
        sort(num.begin(), num.end(), mycomp);
        if(num[num.size() - 1] == 0) return "0";
        string res;
        for(int i = num.size() - 1; i >= 0; i--){
            res += to_string(num[i]);
        }
        return res;
    }
};


Lintcode second:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
    /**
     *@param num: A list of non negative integers
     *@return: A string
     */
     static bool cmp(int a, int b){
         return to_string(a) + to_string(b) > to_string(b) + to_string(a);
     }
    string largestNumber(vector<int> &num) {
        // write your code here
        sort(num.begin(), num.end(), cmp);
        //in case the largest number is zero and then the highest digit of result will be zero
        if(num[0] == 0) return "0";
        string res;
        for(int i = 0; i < num.size(); i++){
            res += to_string(num[i]);
        }
        return res;
    }
};

Lintcode: 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 costscost[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.
Have you met this question in a real interview? 
Yes
Example
Given 4 gas stations with gas[i]=[1,1,3,1], and the cost[i]=[2,2,1,1]. The starting gas station's index is 2.
Note
The solution is guaranteed to be unique.
Challenge
O(n) time and O(1) extra space
Tags Expand 

Initial violent solution:
Use one loop to let the car start off at each station, and use another loop to test whether this car is able to travel around the circle.
Time: O(n^2)
Space: O(1)
class Solution {
public:
    /**
     * @param gas: a vector of integers
     * @param cost: a vector of integers
     * @return: an integer 
     */
    int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
        // write your code here
        int N = gas.size();
        for(int i = 0; i < N; i++){
            int mygas = 0;
            for(int j = i; j < i + N; j++){
                int cur = j % N;
                mygas += gas[cur];
                if(mygas >= cost[cur]) mygas = mygas - cost[cur];
                else break;
                if(j == i + N - 1) return i;
            }
        }
        return -1;
    }
};

Greedy Solution:

1)The key is that if gas sum(0 ~ i) is less than cost[i], then we just need to let car start off after i.

My initial greedy solution thought:
I understand the key point above.
Refer to other solutions online, they just iterate the loop once, even don't prove that when car start off at the last gas station, whether it is able to drive one circle. Because they all have an assumption that

2)if sum(gas[i] - cost[i]) >= 0, there must be an solution.
But why?...
Here is a great proof.
http://bookshadow.com/weblog/2015/08/06/leetcode-gas-station/
In version 1, I just use property 1) so I evaluate the existence when car start at any element,
Time: O(2n)
Space: O(1)
In version 2, I use both 1) and 2>. we know that if sum gas >= sum cost, there must be a solution. So we just need to get the last station where car cannot proceed.
Time: O(n)
Space: O(1)

Version 1:
class Solution {
public:
    /**
     * @param gas: a vector of integers
     * @param cost: a vector of integers
     * @return: an integer 
     */
    int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
        // write your code here
        int N = gas.size();
        for(int i = 0; i < N; i++){
            int mygas = 0;
            int count = 0;
            while(true){
                count++;
                int cur = i % N;
                mygas += gas[cur];
                if(mygas >= cost[cur]) {
                    mygas = mygas - cost[cur];
                    i++;
                }else{
                    //i++;
                    break;
                }
                if(count == N) return i%N;
            }
        }
        return -1;
    }
};

Version 2:


class Solution {
public:
    /**
     * @param gas: a vector of integers
     * @param cost: a vector of integers
     * @return: an integer 
     */
    int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
        // write your code here
        int sum = 0;
        int tempsum = 0;
        int j = -1;
        for(int i = 0; i < gas.size(); i++){
            sum = sum + gas[i] - cost[i];
            tempsum = tempsum + gas[i] - cost[i];
            if(tempsum < 0){
                j = i;
                tempsum = 0;
            }
        }
        if(sum < 0) return -1;
        return j + 1;
    }
};


DP solution: not a good one, try later
O(n^2)

Reference:
动态规划求解最大字段和及其变种问题



Lintcode second:

O(n^2) solution:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
    /**
     * @param gas: a vector of integers
     * @param cost: a vector of integers
     * @return: an integer 
     */
     //3:30
    int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
        // write your code here
        int sum_gas = 0; 
        int sum_cost = 0;
        for(int i = 0; i < gas.size(); i++){
            int sum_gas = 0; 
            int sum_cost = 0;
            for(int j = i; j < i + gas.size();j++){
                j = j % gas.size();
                sum_gas += gas[j];
                sum_cost += cost[j];
                if(sum_gas < sum_cost) break;
                if(j == (i + gas.size() - 1) % gas.size()) return i;
            }
        }
        return -1;
    }
};









Lintcode: Majority Number

Given an array of integers, the majority number is the number that occursmore than half of the size of the array. Find it.
Have you met this question in a real interview?
Yes
Example
Given [1, 1, 1, 1, 2, 2, 2], return 1
Challenge
O(n) time and O(1) extra space
Tags Expand 


Greedy method:(Moore voting algorithm)

Just keep recording one element and times appeared, and iterate the array. If current element equals to the recorded one, count plus 1; If not, count -1 until count == 0, then change the recorded element to current one.
The key is that the majority element occurs more than half times. Even in worst case, the recorded time will be at least one.

Time; O(n)
Space: O(1)

class Solution {
public:
    /**
     * @param nums: A list of integers
     * @return: The majority number
     */
    int majorityNumber(vector<int> nums) {
        // write your code here
        int major = -1;
        int count = 0;
        for(int i = 0; i < nums.size(); i++){
            if(!count) {
                major = nums[i];
                count++;
            }
            else if(major == nums[i]){
              count++;
              if(count > nums.size() / 2) return major; //just optimization, not necessary
            }
            else {
                count--;
            }
        }
        return major;
    }
};




2015年8月19日星期三

Lintcode: Single Number


Given 2*n + 1 numbers, every numbers occurs twice except one, find it.
Have you met this question in a real interview? 
Yes
Example
Given [1,2,2,1,3,4,3], return 4
Challenge
One-pass, constant extra space.
Tags Expand 

http://fisherlei.blogspot.com/2013/11/leetcode-single-number-solution.html
This problem requires Time: O(n) and Space O(1).
So both "sort then find" and "hashmap" don't work.

The key is to use ^(xor) bitwise operation: if same number xor twice, the initial number will not change(x ^ x = 0). Because 0 ^ x = x, so we set initial number 0.
0 ^ 0 = 0; 0 ^ 0 =0; 0^ 0 = 0;
0 ^ 1 = 1; 1 ^ 1 = 0; 0 ^ 1 = 1;

class Solution {
public:
 /**
  * @param A: Array of integers.
  * return: The single number.
  */
    int singleNumber(vector<int> &A) {
        // write your code here
        int res = 0;
        for(int i = 0; i < A.size(); i++){
            res = res ^ A[i];
        }
        return res;
    }
};

Lint code: Binary Representation

Given a (decimal - e.g. 3.72) number that is passed in as a string, return the binary representation that is passed in as a string. If the fractional part of the number can not be represented accurately in binary with at most 32 characters, return ERROR.
Have you met this question in a real interview? 
Yes
Example
For n = "3.72", return "ERROR".
For n = "3.5", return "11.1".
Tags Expand 

My solution:
First, extract the left part and right part into two int; O(n) -- n is the length of input string
Second, turn the left part to binary string by divide 2;
              O(logleft) -- less than O(32) -- left is the left part int
              turn the right part to binary string by multiply 2
              worst case O(32)
Finally, combine left and right string.

Worst case Time: O(n) + 2*O(32)
Worst case Space: O(64 chars) = O(1)

Many bugs apper:
1) When there real part is 0 or decimal part is 0
2) At first I use double to indicate the decimal part. But then it cannot figure out whether 0.5 * 2 == 1 after the initial value multiply two several times. Embarrased. In the end, I use int to indicate decimal
Here, note to use long type to indicate decimal values and limit.

Finally accepted, TAT


class Solution {
public:
    /**
     *@param n: Given a decimal number that is passed in as a string
     *@return: A string
     */
    string binaryRepresentation(string n) {
        // wirte your code here
        int left = 0;
        int i = 0;
        while(n[i] != '.'){
            left = left * 10 + n[i] -'0';
            i++;
        }
        string leftstr;
        while(left){
            leftstr = to_string(left % 2) + leftstr;
            left = left / 2;
        }
        
        long right = 0;
        int j = i + 1;
        while(j < n.size()){   
            right = right * 10 + n[j] - '0';
            j++;
        }
        long limit = pow(10, j - i -1);
        string rightstr;
 while(right){
  if(rightstr.size() > 32) return "ERROR";
  if(right * 2 >= limit){
   rightstr += '1';
   right = right * 2 - limit;
  }
  else {
   rightstr += '0';
   right *= 2;
  }
 }
        if(leftstr.empty()) leftstr = "0";
        if(rightstr.empty()) return leftstr;
        return leftstr + '.' + rightstr;
    }
};