LeetCode 348, 285
LeetCode 348 Design Tic-Tac-Toe
方法:数组
时间复杂度:每次move是O(1)
空间复杂度:O(n)
想法:是一个比较基本的操作,因为题目里面说赢的条件是某一行全是某个人的,或者某一列全是某个人的,或者主对角线或副对角线全是某一个人的,因此最暴力的做法是每次move操作遍历一遍整个棋盘,每次是O(n^2)。但是这样肯定是太慢的。我们对于每次move操作,实际上不需要知道player1和player2具体之前都放在了棋盘的哪里,我们只需要知道,现在要放的这个位置,它所在的行、列、主副对角线(如果在对角线上)是不是全都属于某一个玩家。一种想法是利用数组,如果是player1进行操作,那就对相对应的行列数组,和对角线的变量+1,如果是player2进行的操作,就-1。比方说对于第一行,我们用row[0]代表,player1每放一个棋子在第一行,它就+1,那么如果说row[0]在某个时刻变成了n,那就说明全是第一行全是player1的棋子。反之如果变成了-n,就说明全是player2下的棋子。
代码:
class TicTacToe {
private int[] rows, cols;
private int diag, revDiag, N;
/** Initialize your data structure here. */
public TicTacToe(int n) {
this.rows = new int[n];
this.cols = new int[n];
this.diag = 0;
this.revDiag = 0;
this.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) {
int add = player == 1 ? 1 : -1;
rows[row] += add;
if (rows[row] == N) {
return 1;
}
if (rows[row] == -N) {
return 2;
}
cols[col] += add;
if (cols[col] == N) {
return 1;
}
if (cols[col] == -N) {
return 2;
}
if (row == col) {
diag += add;
if (diag == N) {
return 1;
}
if (diag == -N) {
return 2;
}
}
if (row + col == N - 1) {
revDiag += add;
if (revDiag == N) {
return 1;
}
if (revDiag == -N) {
return 2;
}
}
return 0;
}
}
LeetCode 285 Inorder Successor in BST
方法1:dfs中序遍历
时间复杂度:O(n)
空间复杂度:O(n)
想法:最基本的做法,就是把它当成一般的二叉树来做,对于一个二叉树的节点,找它的后继节点。那么就开全局变量prev和cur,当遍历到p节点时,设上prev,然后在它的下一个节点设上cur。最后return cur。这样做的话严格会把所有节点扫一遍,而且因为递归出口是判断节点是不是null,因此我也没想出来能不能用boolean型dfs或者怎么用boolean型dfs。
代码:
class Solution {
private TreeNode prev = null, cur = null;
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
if (root == null || p == null) {
return null;
}
dfs(root, p);
return cur;
}
private void dfs(TreeNode root, TreeNode p) {
if (root == null) {
return;
}
dfs(root.left, p);
if (prev != null && cur == null) {
cur = root;
}
else if (root == p) {
prev = root;
}
dfs(root.right, p);
}
}
方法2:迭代型中序遍历
时间复杂度:O(n)
空间复杂度:O(n)
想法:还是把它当成普通的二叉树来做,不过这是利用栈来做中序遍历的做法。与上面的方法比起来,这个做法只要找到了node之后就会break出来,不一定会严格扫描所有的节点。但不管怎么样时间复杂度还是O(n)。
代码:
class Solution {
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
Stack<TreeNode> stack = new Stack<>();
while (root != null) {
stack.push(root);
root = root.left;
}
boolean found = false;
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
if (found) {
return node;
}
if (node == p) {
found = true;
}
if (node.right != null) {
node = node.right;
while (node != null) {
stack.push(node);
node = node.left;
}
}
}
return null;
}
}
方法3:递归、BST性质
时间复杂度:O(h)
空间复杂度:O(h)
想法:使用二叉树的性质来做优化,而不是一味地将它当成普通的二叉树来处理。如果说root.val <= p.val,说明p要么就是root,要么在root的右子树,那么p的后继节点肯定是在root的右子树,因此返回inorderSuccessor(root.right, p);。反之,如果root的值比p的值大,那么p肯定是在root的左子树,p的后继要么是root,要么在root的左子树里面,因此我们先查看一下inorderSuccessor(root.left, p);返回什么,如果说在root的左子树里面能够找到p的后继,也就是说这里的返回值不是null,那就返回它,否则说明左子树里面也没找到。不在右子树、然后左子树也没找到,那就只能是root本身。
代码:
class Solution {
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
if (root == null || p == null) {
return null;
}
if (root.val <= p.val) {
return inorderSuccessor(root.right, p);
}
TreeNode l = inorderSuccessor(root.left, p);
return l == null ? root : l;
}
}
方法4:迭代、BST性质
时间复杂度:O(h)
空间复杂度:O(h)
想法:方法3的迭代写法,在第一个while里面,如果root.val > p.val,就把successor设为root,然后root去左子树;否则的话只让root去右子树。这样做了之后,root在某一刻或许会指向p节点,这个时候,假设说root.right == null,没有右子树,那么当前的successor就是要返回的结果。不然的话,因为我们的root和successor是从上到下这么过来的,这个时刻的successor不是最终结果,因为root的后继,应该是root的右子树里面最靠左的那一个。因此再开一个while一直找到那个节点为止。
代码:
class Solution {
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
if (root == null || p == null) {
return null;
}
TreeNode successor = null;
while (root != null && root != p) {
if (root.val > p.val) {
successor = root;
root = root.left;
}
else {
root = root.right;
}
}
if (root.right == null) {
return successor;
}
root = root.right;
while (root != null) {
successor = root;
root = root.left;
}
return successor;
}
}