Tuesday, September 15, 2015

3Sum | Leetcode

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

Note:
  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • The solution set must not contain duplicate triplets.
    For example, given array S = {-1 0 1 2 -1 -4},

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

Solution: Sort the input array. Iterate through the array. For each element i, find the 2Sum of elements i+1 to the end of the array such that nums[i] + nums[j] + nums[k] == 0, or -nums[i] = nums[j] + nums[k]. For each 2Sum, start from the two ends of the subarray. If the current number is too small, make it bigger by advancing from the left end. If too big, make it smaller by advancing from the right end. Check for duplicate solutions by skipping duplicate numbers.
public class Solution {

    public List<List<Integer>> threeSum(int[] nums) {
        // If we need to preserve input, just clone into new array.
        Arrays.sort(nums);
        
        List<List<Integer>> answer = new ArrayList<>();

        for (int i = 0; i < nums.length - 2; i++) {
            int n = nums[i];
            
            // Avoid duplicate solutions.
            if (i > 0 && n == nums[i - 1]) continue;
            
            int start = i + 1;
            int end = nums.length - 1;
            
            while (start < end) {
                int first = nums[start];
                int last = nums[end];
                
                if (first + last == -n) {
                    answer.add(Arrays.asList(n, first, last));
                    start++;
                    end--;
                    
                    // Avoid duplicate solutions.
                    while (start < end && nums[end] == last) end--;
                    while (start < end && nums[start] == first) start++;
                } else if (first + last < -n) {
                    // Current sum is too small, so make it bigger.
                    start++;
                } else {
                    // Current sum is too big, so make it smaller.
                    end--;
                }
            }
        }
        
        return answer;
    }
}

Monday, September 14, 2015

Longest Common Prefix | Leetcode

Write a function to find the longest common prefix string amongst an array of strings.

---

Solution: Use a double for-loop. The outer loop is from the first character to the last character of each string. The inner loop is for each string in the array. Whenever we find an end of any string, or find any string having a different character, stop looping and return the anwer.
public class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs.length == 0) return "";
        
        StringBuilder sb = new StringBuilder();

        OUTER:
        for (int i = 0;; i++) {
            if (i >= strs[0].length()) break;
            char c = strs[0].charAt(i);
            
            for (int j = 1; j < strs.length; j++) {
                if (i >= strs[j].length()) break OUTER;
                if (strs[j].charAt(i) != c) break OUTER;
            }
            
            sb.append((char) c);
        }
        
        return sb.toString();
    }
}

Roman to Integer | Leetcode

Given a roman numeral, convert it to an integer.
 
Input is guaranteed to be within the range from 1 to 3999.

---

Solution: The integer value can be derived by greedily going through the string from left to right and then recognizing its current immediate substring on the left.
public class Solution {
    private String s;
    private int i = 0;
    private int n = 0;
    
    public int romanToInt(String s) {
        this.s = s;
        fromRoman("M", 1000);
        fromRoman("CM", 900);
        fromRoman("D", 500);
        fromRoman("CD", 400);
        fromRoman("C", 100);
        fromRoman("XC", 90);
        fromRoman("L", 50);
        fromRoman("XL", 40);
        fromRoman("X", 10);
        fromRoman("IX", 9);
        fromRoman("V", 5);
        fromRoman("IV", 4);
        fromRoman("I", 1);
        return n;
    }
    
    private int fromRoman(String roman, int value) {
        while (s.indexOf(roman, i) == i) {
            n += value;
            i += roman.length();
        }
        return n;
    }
}

Sunday, September 13, 2015

Integer to Roman | Leetcode

Given an integer, convert it to a roman numeral.

Input is guaranteed to be within the range from 1 to 3999.

---

Solution: The system of roman numerals is a basic greedy algorithm. Take the next largest numeral whenever you can. Then move on to the next lower numeral.
public class Solution {
    public String intToRoman(int num) {
        StringBuilder sb = new StringBuilder();
        num = toRoman(sb, "M", num, 1000);
        num = toRoman(sb, "CM", num, 900);
        num = toRoman(sb, "D", num, 500);
        num = toRoman(sb, "CD", num, 400);
        num = toRoman(sb, "C", num, 100);
        num = toRoman(sb, "XC", num, 90);
        num = toRoman(sb, "L", num, 50);
        num = toRoman(sb, "XL", num, 40);
        num = toRoman(sb, "X", num, 10);
        num = toRoman(sb, "IX", num, 9);
        num = toRoman(sb, "V", num, 5);
        num = toRoman(sb, "IV", num, 4);
        num = toRoman(sb, "I", num, 1);
        return sb.toString();
    }
    
    private int toRoman(StringBuilder sb, String roman, int num, int value) {
        while (num >= value) {
            sb.append(roman);
            num -= value;
        }
        return num;
    }
}

Container With Most Water | Leetcode

Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.

Note: You may not slant the container.

---

Solution: Start from both ends of the container. Keep track of the maximum area. If the left end is shorter than the right end, move the left end by one step right. Else move the right end by one step left. When you are done, return the maximum area that we have seen so far.
public class Solution {
    public int maxArea(int[] height) {
        int max = 0;
        int left = 0;
        int right = height.length - 1;
        
        while (left < right) {
            int area = (right - left) * Math.min(height[left], height[right]);
            max = Math.max(max, area);

            if (height[left] < height[right]) {
                left++;
            } else {
                right--;
            }
        }
        
        return max;
    }
}

Thursday, September 10, 2015

Palindrome Number | Leetcode

Determine whether an integer is a palindrome. Do this without extra space.


Some hints:

Could negative integers be palindromes? (ie, -1)

If you are thinking of converting the integer to string, note the restriction of using extra space.

You could also try reversing an integer. However, if you have solved the problem "Reverse Integer", you know that the reversed integer might overflow. How would you handle such case?

There is a more generic way of solving this problem.

---

Solution: Find largest power-10 divisor "pow10" for x (such that 1 <= (x / pow10) <= 9). Using pow10, we can extract the leftmost digit of x. Loop by comparing the leftmost digit and rightmost digit of x until we have no more digits left to compare.
public class Solution {
    public boolean isPalindrome(int x) {
        if (x < 0) return false; // based on question definition
        if (x <= 9) return true; // single digit, no need to check
        
        // Find number of digits.
        int pow10 = 1;
        for (int i = x / 10; i > 0; i /= 10) {
            pow10 *= 10;
        }

        // Loop until there is at most one digit left.
        while (pow10 > 1) {
            int right = x % 10;
            int left = x / pow10;
            if (right != left) return false;
            
            x %= pow10;   // remove left digit
            x /= 10;      // remove right digit
            pow10 /= 100; // we just removed 2 digits
        }
        
        return true;
    }
}

String to Integer (atoi) | Leetcode

Implement atoi to convert a string to an integer.

Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.

Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.

Update (2015-02-10):

The signature of the C++ function had been updated. If you still see your function signature accepts a const char * argument, please click the reload button to reset your code definition.


Requirements for atoi:

The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.

The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.

If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.

If no valid conversion could be performed, a zero value is returned. If the correct value is out of the range of representable values, INT_MAX (2147483647) or INT_MIN (-2147483648) is returned.

---

Solution: The code below has comments that explain how it works.
public class Solution {
    public int myAtoi(String str) {
        if (str == null || str.isEmpty()) return 0;

        // Remove whitespaces.        
        int i = 0;
        while (Character.isWhitespace(str.charAt(i))) {
            i++;
        }
        
        if (i == str.length()) return 0;
        
        // Check negative.
        boolean isNeg = false;
        char c = str.charAt(i);
        if (c == '+') {
            i++;
        } else if (c == '-') {
            i++;
            isNeg = true;
        }
        
        if (i == str.length()) return 0;
        
        // Extract number.
        int n = 0;
        for (int numDigits = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            
            // Stop at any non-digit.
            if (ch < '0' || ch > '9') break;
            
            // Operate in negative because abs(MIN_INT) > abs(MAX_INT).
            n = (n * 10) - (ch - '0');
            
            // Check integer overflow.
            // Using (n > 0) without numDigits might not always work.
            if (++numDigits > 10 || n > 0) {
                return isNeg ? Integer.MIN_VALUE : Integer.MAX_VALUE;
            }
        }
        
        // Check integer at boundary.
        if (!isNeg && n == Integer.MIN_VALUE) {
            return Integer.MAX_VALUE;
        }
        
        return isNeg ? n : -n;
    }
}