Thursday, August 30, 2018

403. Frog Jump

403Frog Jump
A frog is crossing a river. The river is divided into x units and at each unit there may or may not exist a stone. The frog can jump on a stone, but it must not jump into the water.
Given a list of stones' positions (in units) in sorted ascending order, determine if the frog is able to cross the river by landing on the last stone. Initially, the frog is on the first stone and assume the first jump must be 1 unit.
If the frog's last jump was k units, then its next jump must be either k - 1, k, or k + 1 units. Note that the frog can only jump in the forward direction.
Note:
  • The number of stones is ≥ 2 and is < 1,100.
  • Each stone's position will be a non-negative integer < 231.
  • The first stone's position is always 0.
Example 1:
[0,1,3,5,6,8,12,17]

There are a total of 8 stones.
The first stone at the 0th unit, second stone at the 1st unit,
third stone at the 3rd unit, and so on...
The last stone at the 17th unit.

Return true. The frog can jump to the last stone by jumping 
1 unit to the 2nd stone, then 2 units to the 3rd stone, then 
2 units to the 4th stone, then 3 units to the 6th stone, 
4 units to the 7th stone, and 5 units to the 8th stone.
Example 2:
[0,1,2,3,4,8,9,11]

Return false. There is no way to jump to the last stone as 
the gap between the 5th and 6th stone is too large.
--------------------------------
Solution #1, brute force. Time limit exceeded
O(3^n)
class Solution {
    public boolean canCross(int[] stones) {
        Map<Integer, Integer> map = getMap(stones);
        return rec(map, stones, 1, 1);
    }
    
    private boolean rec(Map<Integer, Integer> map, int[] stones, int stone, int k) {
        if (k == 0 || !map.containsKey(stone)) return false;
        if (map.get(stone) == stones.length - 1) return true;
        
        return rec(map, stones, stone + k - 1, k - 1)
            || rec(map, stones, stone + k, k)
            || rec(map, stones, stone + k + 1, k + 1);
    }
    
    private Map<Integer, Integer> getMap(int[] stones) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < stones.length; i++) {
            map.put(stones[i], i);
        }
        
        return map;
    }
}

Solution #2, DP - Memoization
O(n^2 * m), m为计算key的复杂度,ToDo: java这块转换代码的实现和复杂度得深入了解下
如果用一些hashing算法的话,应该可以把m压缩到O(1), 这样总体保持O(n^2)
或者(ToDo),用一个n * n的2d array,n为stone的数量。因为步数k肯定会是小于总的stone的数量
class Solution {
    public boolean canCross(int[] stones) {
        Map<Integer, Integer> map = getMap(stones);
        Map<String, Boolean> dp = new HashMap<>();
        return rec(map, stones, 1, 1, dp);
    }
    
    private boolean rec(Map<Integer, Integer> map, int[] stones, int stone, int k, Map<String, Boolean> dp) {
        if (k == 0 || !map.containsKey(stone)) return false;
        if (map.get(stone) == stones.length - 1) return true;
        
        String key = Integer.toString(stone) + "#" + Integer.toString(k);
        if (dp.containsKey(key)) {
            return dp.get(key);
        }
        
        boolean flag = rec(map, stones, stone + k - 1, k - 1, dp)
            || rec(map, stones, stone + k, k, dp)
            || rec(map, stones, stone + k + 1, k + 1, dp);
        
        dp.put(key,flag);
        return flag;
    }
    
    private Map<Integer, Integer> getMap(int[] stones) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < stones.length; i++) {
            map.put(stones[i], i);
        }
        
        return map;
    }
}
Solution #3, iterative DP. 用#2的思路,但是第2维存的是Set,因为要保证唯一性
Map里存的是(stone -> 到达当前stone上一步所用的step). 画一个2维矩阵图能帮助理解,这里就懒得发上来了。
class Solution {
    public boolean canCross(int[] stones) {
        Map<Integer, Set<Integer>> map = getMap(stones);
        
        if (!map.containsKey(1)) return false;
        map.get(1).add(1);
        for (int i = 1; i < stones.length - 1; i++) {
            
            int stone = stones[i];
            for (Integer step : map.get(stone)) {
                if (step - 1 > 0 && map.containsKey(stone + step - 1)) {
                    map.get(stone + step - 1).add(step - 1);
                }
                if (map.containsKey(stone + step)) {
                    map.get(stone + step).add(step);
                }
                if (map.containsKey(stone + step + 1)) {
                    map.get(stone + step + 1).add(step + 1);
                }
            }
        }
        
        return !map.get(stones[stones.length - 1]).isEmpty();
    }
    
    private Map<Integer, Set<Integer>> getMap(int[] stones) {
        Map<Integer, Set<Integer>> map = new HashMap<>();
        for (int stone : stones) {
            map.put(stone, new HashSet<>());
        }
        
        return map;
    }
}

Wednesday, August 29, 2018

381. Insert Delete GetRandom O(1) - Duplicates allowed

381Insert Delete GetRandom O(1) - Duplicates allowed
Design a data structure that supports all following operations in average O(1) time.
Note: Duplicate elements are allowed.
  1. insert(val): Inserts an item val to the collection.
  2. remove(val): Removes an item val from the collection if present.
  3. getRandom: Returns a random element from current collection of elements. The probability of each element being returned is linearly related to the number of same value the collection contains.
Example:
// Init an empty collection.
RandomizedCollection collection = new RandomizedCollection();

// Inserts 1 to the collection. Returns true as the collection did not contain 1.
collection.insert(1);

// Inserts another 1 to the collection. Returns false as the collection contained 1. Collection now contains [1,1].
collection.insert(1);

// Inserts 2 to the collection, returns true. Collection now contains [1,1,2].
collection.insert(2);

// getRandom should return 1 with the probability 2/3, and returns 2 with the probability 1/3.
collection.getRandom();

// Removes 1 from the collection, returns true. Collection now contains [1,2].
collection.remove(1);

// getRandom should return 1 and 2 both equally likely.
collection.getRandom();
--------------------------
class RandomizedCollection {
    
    private static Random random = new Random();
    private Map<Integer, Set<Integer>> map;
    private List<Integer> list;
    private int index;

    /** Initialize your data structure here. */
    public RandomizedCollection() {
        index = 0;
        list = new ArrayList<>();
        map = new HashMap<>();
    }
    
    /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
    public boolean insert(int val) {
        boolean rt = false;
        if (!map.containsKey(val)) {
            map.put(val, new HashSet<Integer>());
            rt = true;
        }
        map.get(val).add(index);
        
        if (index == list.size()) {
            list.add(val);
        }else {
            list.set(index, val);
        }
        
        index++;
        
        return rt;
    }
    
    /** Removes a value from the collection. Returns true if the collection contained the specified element. */
    public boolean remove(int val) {
        if (!map.containsKey(val) || map.get(val).isEmpty()) return false;
        
        int pos = map.get(val).iterator().next();
        map.get(val).remove(pos);
        int endValue = list.get(index - 1);
        map.get(endValue).add(pos);
        map.get(endValue).remove(index - 1);
        list.set(pos, endValue);
        index--;
            
        return true;
    }
    
    /** Get a random element from the collection. */
    public int getRandom() {
        return list.get(random.nextInt(index));
    }
}

/**
 * Your RandomizedCollection object will be instantiated and called as such:
 * RandomizedCollection obj = new RandomizedCollection();
 * boolean param_1 = obj.insert(val);
 * boolean param_2 = obj.remove(val);
 * int param_3 = obj.getRandom();
 */

491. Increasing Subsequences

491Increasing Subsequences
Given an integer array, your task is to find all the different possible increasing subsequences of the given array, and the length of an increasing subsequence should be at least 2 .
Example:
Input: [4, 6, 7, 7]
Output: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
Note:
  1. The length of the given array will not exceed 15.
  2. The range of integer in the given array is [-100,100].
  3. The given array may contain duplicates, and two equal integers should also be considered as a special case of increasing sequence.
------------------
类似combination,也可以用back tracking来做
class Solution {
    public List<List<Integer>> findSubsequences(int[] nums) {
        Set<List<Integer>> rt = new HashSet<>();
        helper(rt, nums, 0, new ArrayList<>());
        
        List<List<Integer>> r = new ArrayList<>();
        r.addAll(rt);
        return r;
    }
    
    private void helper(Set<List<Integer>> rt, int[] nums, int i, List<Integer> cur) {
        if (i == nums.length) {
            if (cur.size() > 1) rt.add(cur);
            return;
        }
        
        if (cur.isEmpty() || nums[i] >= cur.get(cur.size() - 1)) {
            List<Integer> list = new ArrayList<>(cur);
            list.add(nums[i]);
            helper(rt, nums, i + 1, list);    
        }
        
        helper(rt, nums, i + 1, cur);
    }
}

Tuesday, August 28, 2018

281. Zigzag Iterator

281Zigzag Iterator
Given two 1d vectors, implement an iterator to return their elements alternately.
Example:
Input:
v1 = [1,2]
v2 = [3,4,5,6] 

Output: [1,3,2,4,5,6]

Explanation: By calling next repeatedly until hasNext returns false, 
             the order of elements returned by next should be: [1,3,2,4,5,6].
Follow up: What if you are given k 1d vectors? How well can your code be extended to such cases?
Clarification for the follow up question:
The "Zigzag" order is not clearly defined and is ambiguous for k > 2 cases. If "Zigzag" does not look right to you, replace "Zigzag" with "Cyclic". For example:
Input:
[1,2,3]
[4,5,6,7]
[8,9]

Output: [1,4,8,2,5,9,3,6,7].

-----------------------
Solution #1, 通用方法
public class ZigzagIterator {

    private boolean v1True = true;
    private List<Integer> v1;
    private List<Integer> v2;
    private int i1;
    private int i2;
    
    public ZigzagIterator(List<Integer> v1, List<Integer> v2) {
        this.v1 = v1;
        this.v2 = v2;
        i1 = 0;
        i2 = 0;
    }

    public int next() {
        int rt;
        if (v1True) {
            if (i1 < v1.size()) {
                rt = v1.get(i1);
                i1++;
                v1True = false;
            }else {
                rt = v2.get(i2);
                i2++;
            }
        } else {
            if (i2 < v2.size()) {
                rt = v2.get(i2);
                i2++;
                v1True = true;
            }else {
                rt = v1.get(i1);
                i1++;
            }
        }
        
        return rt;
    }

    public boolean hasNext() {
        return i1 < v1.size() || i2 < v2.size();
    }
}

/**
 * Your ZigzagIterator object will be instantiated and called as such:
 * ZigzagIterator i = new ZigzagIterator(v1, v2);
 * while (i.hasNext()) v[f()] = i.next();
 */

Solution #2, Java Iterator
public class ZigzagIterator {

    private Queue<Iterator> que;
    private List<Integer> v1;
    private List<Integer> v2;
    
    public ZigzagIterator(List<Integer> v1, List<Integer> v2) {
        que = new LinkedList<Iterator>();
        this.v1 = v1;
        this.v2 = v2;
        if (!v1.isEmpty()) que.add(v1.iterator());
        if (!v2.isEmpty()) que.add(v2.iterator());
    }

    public int next() {
        
        Iterator i = que.poll();
        int next = (Integer)i.next();
        
        if (i.hasNext()) que.add(i);
        
        return next;
    }

    public boolean hasNext() {
        return !que.isEmpty();
    }
}

/**
 * Your ZigzagIterator object will be instantiated and called as such:
 * ZigzagIterator i = new ZigzagIterator(v1, v2);
 * while (i.hasNext()) v[f()] = i.next();
 */

468. Validate IP Address

468Validate IP Address
Write a function to check whether an input string is a valid IPv4 address or IPv6 address or neither.
IPv4 addresses are canonically represented in dot-decimal notation, which consists of four decimal numbers, each ranging from 0 to 255, separated by dots ("."), e.g.,172.16.254.1;
Besides, leading zeros in the IPv4 is invalid. For example, the address 172.16.254.01 is invalid.
IPv6 addresses are represented as eight groups of four hexadecimal digits, each group representing 16 bits. The groups are separated by colons (":"). For example, the address 2001:0db8:85a3:0000:0000:8a2e:0370:7334 is a valid one. Also, we could omit some leading zeros among four hexadecimal digits and some low-case characters in the address to upper-case ones, so 2001:db8:85a3:0:0:8A2E:0370:7334 is also a valid IPv6 address(Omit leading zeros and using upper cases).
However, we don't replace a consecutive group of zero value with a single empty group using two consecutive colons (::) to pursue simplicity. For example, 2001:0db8:85a3::8A2E:0370:7334 is an invalid IPv6 address.
Besides, extra leading zeros in the IPv6 is also invalid. For example, the address 02001:0db8:85a3:0000:0000:8a2e:0370:7334 is invalid.
Note: You may assume there is no extra space or special characters in the input string.
Example 1:
Input: "172.16.254.1"

Output: "IPv4"

Explanation: This is a valid IPv4 address, return "IPv4".
Example 2:
Input: "2001:0db8:85a3:0:0:8A2E:0370:7334"

Output: "IPv6"

Explanation: This is a valid IPv6 address, return "IPv6".
Example 3:
Input: "256.256.256.256"

Output: "Neither"

Explanation: This is neither a IPv4 address nor a IPv6 address.
----------------------------
Solution #1
注意一下边边角角
'.' 在最前或最后, “.1.1.1.1.”
“1.1..1”
class Solution {
    public String validIPAddress(String IP) {
        if (IP == null || IP.length() == 0) return "Neither";
        if (isValidIPv4(IP)) return "IPv4";
        if (isValidIPv6(IP)) return "IPv6";
        return "Neither";
    }
    
    private boolean isValidIPv6(String ip) {
        if (ip.charAt(0) == ':' || ip.charAt(ip.length() - 1) == ':') return false;

        String[] s = ip.split(":");
        if (s.length != 8) return false;
        
        for (String num : s) {
            if (num.length() > 4 || num.length() == 0) return false;
            for (int i = 0; i < num.length(); i++) {
                char c = num.charAt(i);
                if ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || Character.isDigit(c)) continue;
                else return false;
            }
        }
        
        return true;
    }
    
    private boolean isValidIPv4(String ip) {
        if (ip.charAt(0) == '.' || ip.charAt(ip.length() - 1) == '.') return false;
        String[] s = ip.split("\\.");
        
        if (s.length != 4) return false;
        
        for (String num : s) {
            if (num.length() > 3 || (num.length() > 1 && num.charAt(0) == '0') || num.length() == 0) return false;
            
            for (int i = 0; i < num.length(); i++) {
                char c = num.charAt(i);
                if (!Character.isDigit(c)) return false;
            }
            int i = Integer.parseInt(num);
            if (i > 255) return false;
        }
        
        return true;
    }
}

Solution #2, Regex
class Solution {
    public String validIPAddress(String IP) {
        if(IP.matches("(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])")) return "IPv4";
        if(IP.matches("(([0-9a-fA-F]{1,4}):){7}([0-9a-fA-F]{1,4})"))return "IPv6";
        return "Neither";
    }
}

Sunday, August 26, 2018

426.Convert Binary Search Tree to Sorted Doubly Linked List

 426Convert Binary Search Tree to Sorted Doubly Linked List
Convert a BST to a sorted circular doubly-linked list in-place. Think of the left and right pointers as synonymous to the previous and next pointers in a doubly-linked list.
Let's take the following BST as an example, it may help you understand the problem better:


We want to transform this BST into a circular doubly linked list. Each node in a doubly linked list has a predecessor and successor. For a circular doubly linked list, the predecessor of the first element is the last element, and the successor of the last element is the first element.
The figure below shows the circular doubly linked list for the BST above. The "head" symbol means the node it points to is the smallest element of the linked list.


Specifically, we want to do the transformation in place. After the transformation, the left pointer of the tree node should point to its predecessor, and the right pointer should point to its successor. We should return the pointer to the first element of the linked list.
The figure below shows the transformed BST. The solid line indicates the successor relationship, while the dashed line means the predecessor relationship.

--------------------
Pre-order traversal
/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;

    public Node() {}

    public Node(int _val,Node _left,Node _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/
class Solution {
    private Node pre = null;
    private Node head = null;
    
    public Node treeToDoublyList(Node root) {
        if (root == null) return null;
        
        inorder(root);
        head.left = pre;
        pre.right = head;
        return head;
    }
    
    private void inorder(Node root) {
        if (root == null) {
            return;
        }
        
        inorder(root.left);        
        if (pre == null) {
            head = root;
        }else {
            pre.right = root;
            root.left = pre;    
        }
        
        pre = root;
        
        inorder(root.right);        
    }
}

Saturday, August 25, 2018

415, 34, Add Strings, Find First and Last Position of Element in Sorted Array

415Add Strings
Given two non-negative integers num1 and num2 represented as string, return the sum of num1 and num2.
Note:
  1. The length of both num1 and num2 is < 5100.
  2. Both num1 and num2 contains only digits 0-9.
  3. Both num1 and num2 does not contain any leading zero.
  4. You must not use any built-in BigInteger library or convert the inputs to integer directly.
------------------
class Solution {
    public String addStrings(String num1, String num2) {
        int carry = 0;
        StringBuilder sb = new StringBuilder();
        
        for (int i = 0; i < num1.length() || i < num2.length(); i++) {
            int n1 = 0, n2 = 0;
            if (i < num1.length()) n1 = num1.charAt(num1.length() - 1 - i) - '0';
            if (i < num2.length()) n2 = num2.charAt(num2.length() - 1 - i) - '0';
            sb.append((n1 + n2 + carry) % 10);
            carry = (n1 + n2 + carry) / 10;
        }
        
        if (carry > 0) sb.append(carry);
        
        return sb.reverse().toString();
    }
}


34Find First and Last Position of Element in Sorted Array
Given an array of integers nums sorted in ascending order, 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].
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
----------------------------
用2分找开头跟结尾
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] rt = new int[2];
        
        rt[0] = findStart(nums, 0, nums.length - 1, target);
        if (rt[0] == -1) {
            rt[1] = -1;
        }else {
            rt[1] = findEnd(nums, rt[0], nums.length - 1, target);
        }
        
        return rt;
    }
    
    private int findStart(int[] nums, int left, int right, int target) {
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] == target) {
                if (mid == 0 || (mid > 0 && nums[mid - 1] != nums[mid])) {
                    return mid;      
                }
                
                right = mid - 1;
            } else if (nums[mid] < target) left = mid + 1;
            else right = mid - 1;
        }
        
        return -1;
    }
    
    private int findEnd(int[] nums, int left, int right, int target) {
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] == target) {
                if (mid == nums.length - 1 || (mid < nums.length - 1 && nums[mid + 1] != nums[mid])) {
                    return mid;
                }
                
                left = mid + 1;
            }else if (nums[mid] < target) left = mid + 1;
            else right = mid - 1;
        }
        
        return -1;
    }
}

Friday, August 24, 2018

346. Moving Average from Data Stream

346Moving Average from Data Stream
Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window.
Example:
MovingAverage m = new MovingAverage(3);
m.next(1) = 1
m.next(10) = (1 + 10) / 2
m.next(3) = (1 + 10 + 3) / 3
m.next(5) = (10 + 3 + 5) / 3
----------------------
class MovingAverage {
    
    private int[] buffer;
    private int pointer;
    private int sum;
    private int size;
    private int sofar;
    /** Initialize your data structure here. */
    public MovingAverage(int size) {
        this.size = size;
        buffer = new int[size];
        pointer = 0;
        sum = 0;
        sofar = 0;
    }
    
    public double next(int val) {
        sum -= buffer[pointer];
        sum += val;
        buffer[pointer] = val;
        pointer++;
        pointer %= size;
        
        if (sofar < size) sofar++;
        
        return (double)sum / sofar;
    }
}

/**
 * Your MovingAverage object will be instantiated and called as such:
 * MovingAverage obj = new MovingAverage(size);
 * double param_1 = obj.next(val);
 */

348. Design Tic-Tac-Toe

348Design Tic-Tac-Toe
Design a Tic-tac-toe game that is played between two players on a n x n grid.
You may assume the following rules:
  1. A move is guaranteed to be valid and is placed on an empty block.
  2. Once a winning condition is reached, no more moves is allowed.
  3. A player who succeeds in placing n of their marks in a horizontal, vertical, or diagonal row wins the game.
Example:
Given n = 3, assume that player 1 is "X" and player 2 is "O" in the board.

TicTacToe toe = new TicTacToe(3);

toe.move(0, 0, 1); -> Returns 0 (no one wins)
|X| | |
| | | |    // Player 1 makes a move at (0, 0).
| | | |

toe.move(0, 2, 2); -> Returns 0 (no one wins)
|X| |O|
| | | |    // Player 2 makes a move at (0, 2).
| | | |

toe.move(2, 2, 1); -> Returns 0 (no one wins)
|X| |O|
| | | |    // Player 1 makes a move at (2, 2).
| | |X|

toe.move(1, 1, 2); -> Returns 0 (no one wins)
|X| |O|
| |O| |    // Player 2 makes a move at (1, 1).
| | |X|

toe.move(2, 0, 1); -> Returns 0 (no one wins)
|X| |O|
| |O| |    // Player 1 makes a move at (2, 0).
|X| |X|

toe.move(1, 0, 2); -> Returns 0 (no one wins)
|X| |O|
|O|O| |    // Player 2 makes a move at (1, 0).
|X| |X|

toe.move(2, 1, 1); -> Returns 1 (player 1 wins)
|X| |O|
|O|O| |    // Player 1 makes a move at (2, 1).
|X|X|X|
Follow up:
Could you do better than O(n2) per move() operation?
-------------------
Solution #1
开一个2d array
class TicTacToe {

    private int[][] grid;
    private int n;
    /** Initialize your data structure here. */
    public TicTacToe(int n) {
        this.n = n;
        grid = new int[n][n];
    }
    
    /** Player {player} makes a move at ({row}, {col}).
        @param row The row of the board.
        @param col The column of the board.
        @param player The player, can be either 1 or 2.
        @return The current winning condition, can be either:
                0: No one wins.
                1: Player 1 wins.
                2: Player 2 wins. */
    public int move(int row, int col, int player) {
        grid[row][col] = player;
        
        int win = player;
        for (int i = 0; i < n; i++) {
            if (grid[row][i] != player) {
                win = 0;
                break;
            }
        }
        
        if (win == player) return player;
        win = player;
        
        for (int i = 0; i < n; i++) {
            if (grid[i][col] != player) {
                win = 0;
                break;
            }
        }
        
        if (win == player) return player;
        
        if (row == col) {
            win = player;
            for (int i = 0; i < n; i++) {
                if (grid[i][i] != player) {
                    win = 0;
                    break;
                }
            }
            if (win == player) return player;
        }
        
        
        if (row + col == n - 1) {
            win = player;
            for (int i = 0; i < n; i++) {
                if (grid[i][n - 1 - i] != player) {
                    win = 0;
                    break;
                }
            }
            if (win == player) return player;
        }
        
        return 0;
    }    
}

/**
 * Your TicTacToe object will be instantiated and called as such:
 * TicTacToe obj = new TicTacToe(n);
 * int param_1 = obj.move(row,col,player);
 */

Solution #2,对1的优化
用2个array分别记录每一行和列,2个值来记录对角线
class TicTacToe {
    
    private int[] rows;
    private int[] cols;
    private int diag;
    private int antiDiag;
    private int n;
    /** Initialize your data structure here. */
    public TicTacToe(int n) {
        this.n = n;
        rows = new int[n];
        cols = new int[n];
        diag = 0;
        antiDiag = 0;
    }
    
    /** Player {player} makes a move at ({row}, {col}).
        @param row The row of the board.
        @param col The column of the board.
        @param player The player, can be either 1 or 2.
        @return The current winning condition, can be either:
                0: No one wins.
                1: Player 1 wins.
                2: Player 2 wins. */
    public int move(int row, int col, int player) {
        int mv = player == 1? 1 : -1;
        rows[row] += mv;
        cols[col] += mv;
        
        if (row == col) diag += mv;
        if (row + col == n - 1) antiDiag += mv;
        
        if (Math.abs(rows[row]) == n 
            || Math.abs(cols[col]) == n
            || Math.abs(diag) == n
            || Math.abs(antiDiag) == n) {
            
            return player;
        }
        
        return 0;
    }
}

/**
 * Your TicTacToe object will be instantiated and called as such:
 * TicTacToe obj = new TicTacToe(n);
 * int param_1 = obj.move(row,col,player);
 */

Thursday, August 23, 2018

269. Alien Dictionary

269Alien Dictionary
There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you. You receive a list of non-empty words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language.
Example 1:
Input:
[
  "wrt",
  "wrf",
  "er",
  "ett",
  "rftt"
]

Output: "wertf"
Example 2:
Input:
[
  "z",
  "x"
]

Output: "zx"
Example 3:
Input:
[
  "z",
  "x",
  "z"
] 

Output: "" 

Explanation: The order is invalid, so return "".
Note:
  1. You may assume all letters are in lowercase.
  2. You may assume that if a is a prefix of b, then a must appear before b in the given dictionary.
  3. If the order is invalid, return an empty string.
  4. There may be multiple valid order of letters, return any one of them is fine.
-------------------------
典型的Topological sort

注意以下个例:
1. 有环
2. ["z", "z"]
3. ["wz", "w"]

class Solution {
    
    private boolean circle = false;
    
    public String alienOrder(String[] words) {
        Map<Character, Set<Character>> map = getGraph(words);
        Map<Character, Integer> visited = new HashMap<>();
        
        StringBuilder rt = new StringBuilder();
        for (Character c : map.keySet()) {
            dfs(map, c, visited, rt);    
        }
        
        if (circle) return "";
        return rt.reverse().toString();
    }
    
    private void dfs(Map<Character, Set<Character>> map, char cur,  Map<Character, Integer> visited, StringBuilder sb) {

        if (visited.containsKey(cur) && visited.get(cur) == 1) {
            circle = true;
            return;
        }
        if (visited.containsKey(cur) && visited.get(cur) == -1) return;
        
        visited.put(cur, 1);
        for (Character c : map.get(cur)) {
            dfs(map, c, visited, sb);
        }    

        visited.put(cur, -1);
        sb.append(cur);
    }
    
    private Map<Character, Set<Character>> getGraph(String[] words) {
        Map<Character, Set<Character>> map = new HashMap<>();
        
        for (String w : words) {
            for (int i = 0; i < w.length(); i++) {
                map.put(w.charAt(i), new HashSet<>());
            }    
        }
        
        for (int i = 1; i < words.length; i++) {
            for (int j = 0; j < words[i].length() && j < words[i - 1].length(); j++) {
                char c1 = words[i - 1].charAt(j);
                char c2 = words[i].charAt(j);
                
                if (c1 == c2) continue;
                map.get(c1).add(c2);        
                break;
            }   
        }
        
        return map;
    }
}

ToDo
1.把上面的代码精简以下。
2.用BFS再写一遍

Tuesday, August 21, 2018

772. Basic Calculator III

772Basic Calculator III
Implement a basic calculator to evaluate a simple expression string.
The expression string may contain open ( and closing parentheses ), the plus + or minus sign -non-negative integers and empty spaces .
The expression string contains only non-negative integers, +-*/ operators , open ( and closing parentheses ) and empty spaces . The integer division should truncate toward zero.
You may assume that the given expression is always valid. All intermediate results will be in the range of [-2147483648, 2147483647].
Some examples:
"1 + 1" = 2
" 6-4 / 2 " = 4
"2*(5+5*2)/3+(6/2+8)" = 21
"(2+6* 3+5- (3*14/7+2)*5)+3"=-12

Note: Do not use the eval built-in library function.

------------------
当处理到括号的时候用递归

1. I,II和III的通解都可以是:把加减号和值,乘除号和值分别预存起来。
2. 遇到数字计算乘除的值
3.遇到加减号说明乘除已经定下,计算加减号的值

ref:http://shibaili.blogspot.com/2018/08/772-basic-calculator-iii.html

ToDo: 把I,II用类似方法再写一次

class Solution {
    public int calculate(String s) {
        int op1 = 1, op2 = 1;
        int val1 = 0, val2 = 1;
        
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (Character.isDigit(c)) {
                int num = c - '0';
                while (i + 1 < s.length() && Character.isDigit(s.charAt(i + 1))) {
                    num = num * 10 + (s.charAt(i + 1) - '0');
                    i++;
                }
                
                val2 = op2 == 1 ? val2 * num : val2 / num;
            }else if (c == '(') {
                int cur = i;
                int count = 0;
                while (i < s.length()) {
                    char ch = s.charAt(i);
                    if (ch == '(') count++;
                    if (ch == ')') count--;
                    if (count == 0) break;
                    i++;
                }
                
                int num = calculate(s.substring(cur + 1,i));
                val2 = op2 == 1 ? val2 * num : val2 / num;
                
            }else if (c == '+' || c == '-') {
                val1 = val1 + op1 * val2;
                op1 = c == '+' ? 1 : -1;
                op2 = 1;
                val2 = 1;
            }else if (c == '*' || c == '/') {
                op2 = c == '*' ? 1 : -1;
            }
        }
        
        return val1 + op1 * val2;
    }
}

Sunday, August 19, 2018

336. Palindrome Pairs

336. Palindrome Pairs
Hard
Given a list of unique words, find all pairs of distinct indices (i, j) in the given list, so that the concatenation of the two words, i.e. words[i] + words[j] is a palindrome.
Example 1:
Input: ["abcd","dcba","lls","s","sssll"]
Output: [[0,1],[1,0],[3,2],[2,4]] 
Explanation: The palindromes are ["dcbaabcd","abcddcba","slls","llssssll"]
Example 2:
Input: ["bat","tab","cat"]
Output: [[0,1],[1,0]] 
Explanation: The palindromes are ["battab","tabbat"]

------------------------
对每一个string,把它拼成palindrome所需要的另一半都计算出来,然后在给定的范围内查找。

O(n * k^2), n为string的格式,k为string的平均长度。k^2的消耗在isPalindrome
class Solution {
    public List<List<Integer>> palindromePairs(String[] words) {
        Map<String, Integer> map = getMap(words);
        List<List<Integer>> rt = new ArrayList<>();
        
        for (int start = 0; start < words.length; start++) {
            String word = words[start];
            for (int i = 0; i <= word.length(); i++) {
                String st1 = word.substring(0,i);
                String st2 = word.substring(i);
                
                if (isPalindrome(st1)) {
                    String target = new StringBuilder(st2).reverse().toString();
                    if (map.containsKey(target) && map.get(target) != start) {
                        List<Integer> l = new ArrayList<>();
                        l.add(map.get(target));    
                        l.add(start);
                        rt.add(l);
                    }
                }
                
                if (isPalindrome(st2) && !st2.isEmpty()) {
                    String target = new StringBuilder(st1).reverse().toString();
                    if (map.containsKey(target) && map.get(target) != start) {
                        List<Integer> l = new ArrayList<>();
                        l.add(start);
                        l.add(map.get(target));    
                        rt.add(l);
                    }
                }
            }
        }
        
        return rt;
    }
    
    private boolean isPalindrome(String s) {
        int left = 0, right = s.length() - 1;
        while (left < right) {
            if (s.charAt(left) != s.charAt(right)) return false;
            left++;
            right--;
        }
        
        return true;
    }
    
    
    private Map<String, Integer> getMap(String[] words) {
        Map<String, Integer> map = new HashMap<>();
        
        for (int i = 0; i < words.length; i++) {
            map.put(words[i], i);
        }
        
        return map;
    }
}

Friday, August 17, 2018

791. Custom Sort String

791Custom Sort String
S and T are strings composed of lowercase letters. In S, no letter occurs more than once.
S was sorted in some custom order previously. We want to permute the characters of T so that they match the order that S was sorted. More specifically, if x occurs before y in S, then x should occur before y in the returned string.
Return any permutation of T (as a string) that satisfies this property.
Example :
Input: 
S = "cba"
T = "abcd"
Output: "cbad"
Explanation: 
"a", "b", "c" appear in S, so the order of "a", "b", "c" should be "c", "b", and "a". 
Since "d" does not appear in S, it can be at any position in T. "dcba", "cdba", "cbda" are also valid outputs.

Note:
  • S has length at most 26, and no character is repeated in S.
  • T has length at most 200.
  • S and T consist of lowercase letters only.
---------------------
第一个循环:把在T且在S的插入
第二个循环:把在T但不在S的插入
class Solution {
    public String customSortString(String S, String T) {
        Map<Character, Integer> map = getMap(T);
        StringBuilder sb = new StringBuilder();
        
        for (int i = 0; i < S.length(); i++) {
            char c = S.charAt(i);
            int count = map.getOrDefault(c, 0);
            for (int j = 0; j < count; j++) {
                sb.append(c);
            }
            map.put(c, 0);
        }
        
        for (int i = 0; i < T.length(); i++) {
            char c = T.charAt(i);
            if (map.containsKey(c) && map.get(c) > 0) {
                for (int j = 0; j < map.get(c); j++) {
                    sb.append(c);
                }
                map.put(c, 0);
            }
        }
        
        return sb.toString();
    }
    
    private Map<Character, Integer> getMap(String s) {
        Map<Character, Integer> map = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            map.put(c, map.getOrDefault(c, 0) + 1);
        }
        
        return map;
    }
}