Friday, May 31, 2019

LeetCode [428] Serialize and Deserialize N-ary Tree

428. Serialize and Deserialize N-ary Tree
Hard

Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.

Design an algorithm to serialize and deserialize an N-ary tree. An N-ary tree is a rooted tree in which each node has no more than N children. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that an N-ary tree can be serialized to a string and this string can be deserialized to the original tree structure.

For example, you may serialize the following 3-ary tree

as [1 [3[5 6] 2 4]]. Note that this is just an example, you do not necessarily need to follow this format.

Or you can follow LeetCode's level order traversal serialization format, where each group of children is separated by the null value.

For example, the above tree may be serialized as [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14].

You do not necessarily need to follow the above suggested formats, there are many more different formats that work so please be creative and come up with different approaches yourself.

 

Constraints:

  • The height of the n-ary tree is less than or equal to 1000
  • The total number of nodes is between [0, 10^4]
  • Do not use class member/global/static variables to store states. Your encode and decode algorithms should be stateless.
 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
27
28
29
30
31
32
33
34
35
36
class Codec {
    void sh(Node* node, string& s){
        if(node){
            s += to_string(node->val) + " " + to_string(node->children.size()) + " ";
            for(auto c:node->children){
                sh(c, s);
            }
        }
    }

    Node* dh(stringstream& ss){
        ss.peek();
        if(ss.eof()) return NULL;
        int sz;
        Node* node = new Node();
        ss>>node->val>>sz;
        for(int i=0; i<sz; ++i){
            node->children.push_back(dh(ss));
        }
        return node;
    }
public:

    // Encodes a tree to a single string.
    string serialize(Node* root) {
        string s;
        sh(root, s);
        return s;
    }

    // Decodes your encoded data to tree.
    Node* deserialize(string data) {
        stringstream ss(data);
        return dh(ss);
    }
};
 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Codec {
    void sh(Node root, StringBuilder sb){
        if(root!=null){
            sb.append(root.val);
            sb.append(" ");
            sb.append(root.children.size());
            sb.append(" ");
            for(Node child : root.children){
                sh(child, sb);
            }
        }
    }
    // Encodes a tree to a single string.
    public String serialize(Node root) {
        StringBuilder sb = new StringBuilder();
        sh(root, sb);
        return sb.toString();
    }
    
    
    // Decodes your encoded data to tree.
    Node dh(StringBuilder sb){
        if(sb.length()==0) return null;
        int indexOfFirstSpace = sb.indexOf(" ", 0);
        int number = Integer.parseInt(sb.substring(0, indexOfFirstSpace));
        Node node = new Node(number, new ArrayList<>());

        int indexOfSecondSpace = sb.indexOf(" ", indexOfFirstSpace+1);
        if(indexOfSecondSpace==-1) indexOfSecondSpace = sb.length();
        int sz = Integer.parseInt(sb.substring(indexOfFirstSpace+1, indexOfSecondSpace));
        int newStart = indexOfSecondSpace!=sb.length() ? indexOfSecondSpace+1 : indexOfSecondSpace;

        sb.delete(0, newStart);
        for(int i=0; i<sz; ++i){
            node.children.add(dh(sb));
        }
        return node;
    }
    public Node deserialize(String data) {
        StringBuilder sb = new StringBuilder(data);
        return dh(sb);
    }
}

// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));

Thursday, May 30, 2019

LeetCode [591] Tag Validator

Given a string representing a code snippet, you need to implement a tag validator to parse the code and return whether it is valid. A code snippet is valid if all the following rules hold:
  1. The code must be wrapped in a valid closed tag. Otherwise, the code is invalid.
  2. closed tag (not necessarily valid) has exactly the following format : <TAG_NAME>TAG_CONTENT</TAG_NAME>. Among them, <TAG_NAME> is the start tag, and </TAG_NAME> is the end tag. The TAG_NAME in start and end tags should be the same. A closed tag is valid if and only if the TAG_NAME and TAG_CONTENT are valid.
  3. valid TAG_NAME only contain upper-case letters, and has length in range [1,9]. Otherwise, the TAG_NAME is invalid.
  4. valid TAG_CONTENT may contain other valid closed tagscdata and any characters (see note1) EXCEPT unmatched <, unmatched start and end tag, and unmatched or closed tags with invalid TAG_NAME. Otherwise, the TAG_CONTENT is invalid.
  5. A start tag is unmatched if no end tag exists with the same TAG_NAME, and vice versa. However, you also need to consider the issue of unbalanced when tags are nested.
  6. < is unmatched if you cannot find a subsequent >. And when you find a < or </, all the subsequent characters until the next > should be parsed as TAG_NAME (not necessarily valid).
  7. The cdata has the following format : <![CDATA[CDATA_CONTENT]]>. The range of CDATA_CONTENT is defined as the characters between <![CDATA[and the first subsequent ]]>.
  8. CDATA_CONTENT may contain any characters. The function of cdata is to forbid the validator to parse CDATA_CONTENT, so even it has some characters that can be parsed as tag (no matter valid or invalid), you should treat it as regular characters.
Valid Code Examples:
Input: "<DIV>This is the first line <![CDATA[<div>]]></DIV>"

Output: True

Explanation: 

The code is wrapped in a closed tag : <DIV> and </DIV>. 

The TAG_NAME is valid, the TAG_CONTENT consists of some characters and cdata. 

Although CDATA_CONTENT has unmatched start tag with invalid TAG_NAME, it should be considered as plain text, not parsed as tag.

So TAG_CONTENT is valid, and then the code is valid. Thus return true.


Input: "<DIV>>>  ![cdata[]] <![CDATA[<div>]>]]>]]>>]</DIV>"

Output: True

Explanation:

We first separate the code into : start_tag|tag_content|end_tag.

start_tag -> "<DIV>"

end_tag -> "</DIV>"

tag_content could also be separated into : text1|cdata|text2.

text1 -> ">>  ![cdata[]] "

cdata -> "<![CDATA[<div>]>]]>", where the CDATA_CONTENT is "<div>]>"

text2 -> "]]>>]"


The reason why start_tag is NOT "<DIV>>>" is because of the rule 6.
The reason why cdata is NOT "<![CDATA[<div>]>]]>]]>" is because of the rule 7.
Invalid Code Examples:
Input: "<A>  <B> </A>   </B>"
Output: False
Explanation: Unbalanced. If "<A>" is closed, then "<B>" must be unmatched, and vice versa.

Input: "<DIV>  div tag is not closed  <DIV>"
Output: False

Input: "<DIV>  unmatched <  </DIV>"
Output: False

Input: "<DIV> closed tags with invalid tag name  <b>123</b> </DIV>"
Output: False

Input: "<DIV> unmatched tags with invalid tag name  </1234567890> and <CDATA[[]]>  </DIV>"
Output: False

Input: "<DIV>  unmatched start tag <B>  and unmatched end tag </C>  </DIV>"
Output: False
Note:
  1. For simplicity, you could assume the input code (including the any characters mentioned above) only contain lettersdigits'<','>','/','!','[',']' and ' '.
 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class Solution
{
    bool isCap(char c)
    {
        return c >= 'A' && c <= 'Z';
    }

public:
    bool isValid(string code)
    {
        stack<string> tags;
        int i = 0, n = code.size();
        if(n<2 || code[0]!='<' || code.substr(0,2)=="<!") return false;
        
        while (i < n)
        {
            if (code[i] == '<')
            {
                //CDATA
                if (i + 8 < n && code.substr(i, 9)=="<![CDATA[")
                {
                    i += 9;
                    while(i<n && !(i+2<n && code.substr(i, 3)=="]]>")){
                        i++;
                    }
                    if(i+2<n && code.substr(i, 3)=="]]>") i+=3;
                    else return false;
                }
                else
                {//name tag
                    i++;
                    bool isStartTN = true;
                    if (i < n && code[i] == '/')
                    {
                        i++;
                        isStartTN = false;
                    }
                    string tagName;
                    while (i < n && code[i] != '>')
                    {
                        if (!isCap(code[i]))
                            return false;
                        tagName += code[i++];
                    }
                    if (tagName.size() < 1 || tagName.size() > 9)
                        return false;
                    if (isStartTN)
                    {
                        tags.push(tagName);
                    }
                    else
                    {
                        if (tags.empty() || tags.top() != tagName)
                            return false;
                        tags.pop();
                        if(tags.empty()) return i==n-1;
                    }
                    i++;
                }
            }else{
                i++;
            }
        }

        return tags.empty();
    }
};

LeetCode [542] 01 Matrix

Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell.
The distance between two adjacent cells is 1.

Example 1:
Input:
[[0,0,0],
 [0,1,0],
 [0,0,0]]

Output:
[[0,0,0],
 [0,1,0],
 [0,0,0]]
Example 2:
Input:
[[0,0,0],
 [0,1,0],
 [1,1,1]]

Output:
[[0,0,0],
 [0,1,0],
 [1,2,1]]

Note:
  1. The number of elements of the given matrix will not exceed 10,000.
  2. There are at least one 0 in the given matrix.
  3. The cells are adjacent in only four directions: up, down, left and right.
 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution
{
    vector<vector<int>> dir;

public:
    vector<vector<int>> updateMatrix(vector<vector<int>> &matrix)
    {
        dir.push_back(vector<int>{-1, 0});
        dir.push_back(vector<int>{1, 0});
        dir.push_back(vector<int>{0, -1});
        dir.push_back(vector<int>{0, 1});
        int m = matrix.size(), n = matrix[0].size();
        queue<pair<int, int>> que;
        for (int i = 0; i < m; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                if (matrix[i][j] == 0)
                    que.push(pair<int, int>(i, j));
                else
                    matrix[i][j] = INT_MAX;
            }
        }

        while (!que.empty())
        {
            int i = que.front().first, j = que.front().second;
            que.pop();
            for (auto d : dir)
            {
                int ii = i + d[0], jj = j + d[1];
                if (ii >= 0 && ii < m && jj >= 0 && jj < n && matrix[ii][jj] > matrix[i][j] + 1)
                {
                    matrix[ii][jj] = matrix[i][j] + 1;
                    que.push(pair<int, int>(ii, jj));
                }
            }
        }

        return matrix;
    }
};

LeetCode [780] Reaching Points

A move consists of taking a point (x, y) and transforming it to either (x, x+y) or (x+y, y).
Given a starting point (sx, sy) and a target point (tx, ty), return Trueif and only if a sequence of moves exists to transform the point (sx, sy)to (tx, ty). Otherwise, return False.
Examples:
Input: sx = 1, sy = 1, tx = 3, ty = 5
Output: True
Explanation:
One series of moves that transforms the starting point to the target is:
(1, 1) -> (1, 2)
(1, 2) -> (3, 2)
(3, 2) -> (3, 5)

Input: sx = 1, sy = 1, tx = 2, ty = 2
Output: False

Input: sx = 1, sy = 1, tx = 1, ty = 1
Output: True

Note:
  • sx, sy, tx, ty will all be integers in the range [1, 10^9].
 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:
    bool reachingPoints(int sx, int sy, int tx, int ty) {
        if (tx < sx || ty < sy) {
            return false;
        }
        if (tx == sx && ty == sy) {
            return true;
        }
        if (tx == sx) {
            return (ty - sy) % tx == 0;
        }
        if (ty == sy) {
            return (tx - sx) % ty == 0;
        }

        if (tx > ty) {
            return reachingPoints(sx, sy, tx % ty, ty);
        }
        return reachingPoints(sx, sy, tx, ty % tx);
    }
};

LeetCode [741] Cherry Pickup

741. Cherry Pickup
Hard

In a N x N grid representing a field of cherries, each cell is one of three possible integers.

 

  • 0 means the cell is empty, so you can pass through;
  • 1 means the cell contains a cherry, that you can pick up and pass through;
  • -1 means the cell contains a thorn that blocks your way.

 

Your task is to collect maximum number of cherries possible by following the rules below:

 

  • Starting at the position (0, 0) and reaching (N-1, N-1) by moving right or down through valid path cells (cells with value 0 or 1);
  • After reaching (N-1, N-1), returning to (0, 0) by moving left or up through valid path cells;
  • When passing through a path cell containing a cherry, you pick it up and the cell becomes an empty cell (0);
  • If there is no valid path between (0, 0) and (N-1, N-1), then no cherries can be collected.

 

 

Example 1:

Input: grid =
[[0, 1, -1],
 [1, 0, -1],
 [1, 1,  1]]
Output: 5
Explanation: 
The player started at (0, 0) and went down, down, right right to reach (2, 2).
4 cherries were picked up during this single trip, and the matrix becomes [[0,1,-1],[0,0,-1],[0,0,0]].
Then, the player went left, up, up, left to return home, picking up one more cherry.
The total number of cherries picked up is 5, and this is the maximum possible.

 

Note:

  • grid is an N by N 2D array, with 1 <= N <= 50.
  • Each grid[i][j] is an integer in the set {-1, 0, 1}.
  • It is guaranteed that grid[0][0] and grid[N-1][N-1] are not -1.
Explanations:
 Two person move from [0,0] to [n-1, n-1]. What's the max cherries they can pick.
- if the two person pass the same cell, they much pass it at the same time
- the length from [0,0] to position [i, j] is i+j;
- the length from [0,0] to [n-1, n-1] is 2n-2. this is also the max length;
- given a length K, dp[i][j] is the cherries picked up on the route [0,0]->[i,K-i] and [j, K-j]->[0,0]
- when K = 2n-2 the result is dp[n-1][n-1]. in this case, [i, K-i] = [n-1, n-1] = [j, K-j]. 
- dp_k[i][j] = max{dp_(k-1)[i-1][j-1], dp_(k-1)[i][j-1], dp_(k-1)[i-1][j], dp_(k-1)[i][j]} + grid[i][k-i] + grid[j][k-j]


 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
27
28
29
30
31
32
33
34
class Solution {
public:
    int cherryPickup(vector<vector<int>>& grid) {
        int n = grid.size();
        int K = 2*n-2;
        vector<vector<int>> dp(n, vector<int>(n, -1));
        dp[0][0] = grid[0][0]; // length k = 0
        for(int k=1; k<=K; ++k)
        {
            vector<vector<int>> tmp(n, vector<int>(n, -1));
            for(int i=0; i<=k && i<n; ++i)
            {
                if(k-i>=n) continue;
                if(grid[i][k-i]<0) continue;
                for(int j=0; j<=k && j<n; ++j)
                {
                    if(k-j>=n) continue;
                    if(grid[j][k-j]<0) continue;
                    int cherries = dp[i][j];//cherries picked up at k-1th iteration
                    if(i-1>=0) cherries = max(cherries, dp[i-1][j]);
                    if(j-1>=0) cherries = max(cherries, dp[i][j-1]);
                    if(i-1>=0 && j-1>=0) cherries = max(cherries, dp[i-1][j-1]);
                    
                    if(cherries<0) continue;//no way to current place
                    
                    tmp[i][j] = cherries + grid[i][k - i] + (i == j ? 0 : grid[j][k - j]);
                }
            }
            dp = tmp;
        }
        
        return max(dp[n-1][n-1], 0);
    }
};
 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
27
28
29
30
//Java
class Solution {
    public int cherryPickup(int[][] grid) {
        int N = grid.length;
        int[][] dp = new int[N][N];
        for(int i=0; i<N; ++i) Arrays.fill(dp[i], -1);
        int K = 2*N-2;
        dp[0][0] = grid[0][0];
        for(int k=1; k<=K; ++k){
            int[][] tmp = new int[N][N];
            for(int i=0; i<N; ++i) Arrays.fill(tmp[i], -1);
            for(int i=0; i<N && i<=k; ++i){//person A's position
                int coli = k-i;
                if(coli>=N || grid[i][coli]<0) continue;
                for(int j=0; j<N && j<=k; ++j){//person B's position
                    int colj = k-j;
                    if(colj>=N || grid[j][colj]<0) continue;
                    int cherries = dp[i][j];//cherries picked up at (k-1)th iteration
                    if(i-1>=0) cherries = Math.max(cherries, dp[i-1][j]);
                    if(j-1>=0) cherries = Math.max(cherries, dp[i][j-1]);
                    if(i-1>=0 && j-1>=0) cherries = Math.max(cherries, dp[i-1][j-1]);
                    if(cherries<0) continue;
                    tmp[i][j] = cherries + grid[i][k-i] + (i==j?0:grid[j][k-j]);
                }
            }
            dp = tmp;
        }
        return Math.max(dp[N-1][N-1], 0);
    }
}

Wednesday, May 29, 2019

LeetCode [427] Construct Quad Tree

We want to use quad trees to store an N x N boolean grid. Each cell in the grid can only be true or false. The root node represents the whole grid. For each node, it will be subdivided into four children nodes until the values in the region it represents are all the same.
Each node has another two boolean attributes : isLeaf and valisLeafis true if and only if the node is a leaf node. The val attribute for a leaf node contains the value of the region it represents.
Your task is to use a quad tree to represent a given grid. The following example may help you understand the problem better:
Given the 8 x 8 grid below, we want to construct the corresponding quad tree:
It can be divided according to the definition above:

The corresponding quad tree should be as following, where each node is represented as a (isLeaf, val) pair.
For the non-leaf nodes, val can be arbitrary, so it is represented as *.
Note:
  1. N is less than 1000 and guaranteened to be a power of 2.
  2. If you want to know more about the quad tree, you can refer to its wiki.
 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
// Definition for a QuadTree node.
class Node {
public:
    bool val;
    bool isLeaf;
    Node* topLeft;
    Node* topRight;
    Node* bottomLeft;
    Node* bottomRight;

    Node() {}

    Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) {
        val = _val;
        isLeaf = _isLeaf;
        topLeft = _topLeft;
        topRight = _topRight;
        bottomLeft = _bottomLeft;
        bottomRight = _bottomRight;
    }
};
*/
class Solution {
    int N;
public:
    Node* construct(vector<vector<int>>& grid) {
        N = grid.size();
        return helper(grid, 0, 0, N-1, N-1);
    }
    
    Node* helper(vector<vector<int>>& grid, int r1, int c1, int r2, int c2)
    {
        bool isLeaf = true;
        for(int i=r1; i<=r2; ++i)
        {
            for(int j=c1; j<=c2; ++j)
            {
                if(grid[i][j]!=grid[r1][c1]){isLeaf = false; break;}
            }
        }
        if(isLeaf){
            return new Node(grid[r1][c1]==1, true, NULL, NULL, NULL, NULL);
        }
        Node* tl = helper(grid, r1, c1, r1+(r2-r1)/2, c1+(c2-c1)/2);
        Node* tr = helper(grid, r1, c1+(c2-c1+1)/2, r1+(r2-r1)/2, c2);
        Node* bl = helper(grid, r1+(r2-r1+1)/2, c1, r2, c1+(c2-c1)/2);
        Node* br = helper(grid, r1+(r2-r1+1)/2, c1+(c2-c1+1)/2, r2, c2);
        return new Node(false, false, tl, tr, bl, br);
    }
};