Top100(中)
二叉树
int *res;
void inorder(struct TreeNode *root, int *returnSize) {
if (root == NULL) return;
// 左根右
inorder(root->left, returnSize);
res[(*returnSize)++] = root->val;
inorder(root->right, returnSize);
}
int *inorderTraversal(struct TreeNode *root, int *returnSize) {
res = (int *) malloc(sizeof(int) * 100);
*returnSize = 0;
inorder(root, returnSize);
return res;
}
int *inorderTraversal(struct TreeNode *root, int *returnSize) {
int *res = (int *) malloc(sizeof(int) * 100);
*returnSize = 0;
struct TreeNode *stack[100];
int top = 0;
while (top != 0 || root != NULL) {
// 左子树入栈
while (root != NULL) {
stack[top++] = root;
root = root->left;
}
root = stack[--top];
// 访问
res[(*returnSize)++] = root->val;
root = root->right;
}
return res;
}
int *res;
void inorderMorris(struct TreeNode *root, int *returnSize) {
if (root == NULL) return;
struct TreeNode *cur = root;
while (cur != NULL) {
if (cur->left != NULL) {
struct TreeNode *rightMost = cur->left;
while (rightMost->right != NULL && rightMost->right != cur) {
rightMost = rightMost->right;
}
if (rightMost->right == NULL) {
rightMost->right = cur;
cur = cur->left;
} else {
// 有左右孩子的节点第二次被经过,左子树都遍历完了,访问节点
res[(*returnSize)++] = cur->val;
rightMost->right = NULL;
cur = cur->right;
}
} else {
// 只有右孩子的节点只会被经过一次,直接访问
res[(*returnSize)++] = cur->val;
cur = cur->right;
}
}
}
int *inorderTraversal(struct TreeNode *root, int *returnSize) {
res = (int *) malloc(sizeof(int) * 100);
*returnSize = 0;
if (root == NULL) return res;
inorderMorris(root, returnSize);
return res;
}
// 递归
int maxDepth(struct TreeNode* root) {
if (root == NULL) return 0;
int left = maxDepth(root->left);
int right = maxDepth(root->right);
return (left > right ? left : right) + 1;
}
// 层序遍历
int maxDepth(struct TreeNode *root) {
if (root == NULL) return 0;
int depth = 0;
const int size = 5002;
// 循环队列
struct TreeNode *queue[size];
int front = 0, rear = 0;
queue[rear++] = root;
while (front != rear) {
int count = (rear - front + size) % size;
// 一层加一次
depth++;
while (count-- > 0) {
struct TreeNode *node = queue[(front++) % size];
if (node->left != NULL) queue[(rear++) % size] = node->left;
if (node->right != NULL) queue[(rear++) % size] = node->right;
}
}
return depth;
}
struct TreeNode *invertTree(struct TreeNode *root) {
if (root == NULL) return root;
struct TreeNode *left = invertTree(root->right);
struct TreeNode *right = invertTree(root->left);
root->left = left;
root->right = right;
return root;
}
// 递归
bool dfs(struct TreeNode *L, struct TreeNode *R) {
if (L == NULL && R == NULL) return true;
if (L == NULL || R == NULL || L->val != R->val) return false;
return dfs(L->left, R->right) && dfs(L->right, R->left);
}
bool isSymmetric(struct TreeNode *root) {
if (root == NULL) return true;
return dfs(root->left, root->right);
}
// 迭代
bool isSymmetric(struct TreeNode *root) {
if (root == NULL) return true;
if (root->left == NULL && root->right == NULL) return true;
if (root->left == NULL || root->right == NULL || root->left->val != root->right->val) return false;
const int size = 1001;
struct TreeNode *queue[size];
int front = 0, rear = 0;
// 左右孩子入队
queue[rear++] = root->left;
queue[rear++] = root->right;
while (rear != front) {
struct TreeNode *L = queue[(front++) % size];
struct TreeNode *R = queue[(front++) % size];
if (L == NULL && R == NULL) return true;
if ((L == NULL || R == NULL)
|| (L->val != R->val)
|| (L->left == NULL && R->right != NULL)
|| (L->right == NULL && R->left != NULL)
|| (L->right == NULL && R->left != NULL)
|| (L->left == NULL && R->right != NULL))
return false;
if (L->left != NULL) {
queue[(rear++) % size] = L->left;
queue[(rear++) % size] = R->right;
}
if (L->right != NULL) {
queue[(rear++) % size] = L->right;
queue[(rear++) % size] = R->left;
}
}
return true;
}
int res;
// 求树高的同时记录最远距离
int height(struct TreeNode *root) {
if (root == NULL)return 0;
int left = height(root->left);
int right = height(root->right);
if (left + right > res) res = left + right;
return (left > right ? left : right) + 1;
}
int diameterOfBinaryTree(struct TreeNode *root) {
res = 0;
height(root);
return res;
}
int **levelOrder(struct TreeNode *root, int *returnSize, int **returnColumnSizes) {
// 一层最多元素个数
const int size = 1002;
// 最多层数
const int leverMax = 2000;
// 返回的二维数组,第一维表示所在层,第二维表示该层的所有元素
int **res = (int **) malloc(sizeof(int *) * leverMax);
// 一维的维度(多少层)
*returnSize = 0;
// 每个二维的维度(每层多少元素)
*returnColumnSizes = (int *) malloc(sizeof(int) * leverMax);
if (root == NULL) return res;
// 循环队列
struct TreeNode *queue[size];
int lever = 0;
// 保存每层元素个数,下标就是所在层,从0开始
int *columnSize = (int *) calloc(leverMax, sizeof(int));
int front = 0, rear = 0;
queue[rear++] = root;
while (front != rear) {
// 当前层元素数
int count = (rear - front + size) % size;
res[lever] = (int *) malloc(sizeof(int) * count);
int temp = 0;
while (count-- > 0) {
root = queue[(front++) % size];
// 记录当前层的元素
res[lever][temp++] = root->val;
// 当前层元素总数加一
columnSize[lever]++;
if (root->left != NULL) queue[(rear++) % size] = root->left;
if (root->right != NULL) queue[(rear++) % size] = root->right;
}
// 加一层
lever++;
}
*returnSize = lever;
for (int i = 0; i < lever; ++i)
(*returnColumnSizes)[i] = columnSize[i];
return res;
}
// 递归生成
struct TreeNode *generate(int *nums, int left, int right) {
if (left > right) return NULL;
// 向下取整的中间元素
int mid = (right - left) / 2 + left;
struct TreeNode *node = (struct TreeNode *) malloc(sizeof(struct TreeNode));
node->val = nums[mid];
node->left = generate(nums, left, mid - 1);
node->right = generate(nums, mid + 1, right);
return node;
}
// 中序遍历
bool inorder(struct TreeNode *root) {
if (root == NULL) return true;
// 左
if (!inorder(root->left)) return false;
// 根
if (pre != NULL && pre->val >= root->val) return false;
pre = root;
// 右
return inorder(root->right);
}
bool isValidBST(struct TreeNode *root) {
pre = NULL;
return inorder(root);
}
// 判断子树是否在min到max的开区间内
bool dfs(struct TreeNode *root, long long min, long long max) {
if (root == NULL) return true;
if (root->val <= min || root->val >= max)return false;
return dfs(root->left, min, root->val) && dfs(root->right, root->val, max);
}
bool isValidBST(struct TreeNode *root) {
return dfs(root, 0x8000000000000000, 0x7fffffffffffffff);
}
int res;
int count;
// 右根左,倒着中序遍历
// 倒数第k个变成找正数第k个
void inorder(struct TreeNode *root) {
if (root == NULL || res != -1) return;
inorder(root->left);
count--;
if (count == 0) {
res = root->val;
return;
}
inorder(root->right);
}
int kthSmallest(struct TreeNode *root, int k) {
res = -1;
count = k;
inorder(root);
return res;
}
int *rightSideView(struct TreeNode *root, int *returnSize) {
*returnSize = 0;
if (root == NULL) return NULL;
int *res = (int *) malloc(sizeof(int) * 100);
const int size = 52;
struct TreeNode **queue = (struct TreeNode **) malloc(sizeof(struct TreeNode *) * size);
int front = 0, rear = 0;
queue[rear++] = root;
// 层序遍历找一层的最后一个节点
while (rear != front) {
int count = (rear - front + size) % size;
struct TreeNode *node;
while (count-- > 0) {
node = queue[(front++) % size];
if (node->left != NULL) queue[(rear++) % size] = node->left;
if (node->right != NULL) queue[(rear++) % size] = node->right;
}
res[(*returnSize)++] = node->val;
}
return res;
}
int *res;
int size;
void dfs(struct TreeNode *root, int depth, int *returnSize) {
if (root == NULL) return;
// 根
if (depth == size) {
// 如果是新的一层的第一个节点,就加入到结果中
// 由于是根右左顺序,新一层的第一个节点一定是该层最右边的节点
res[(*returnSize)++] = root->val;
size++;
}
// 右
dfs(root->right, depth + 1, returnSize);
// 左
dfs(root->left, depth + 1, returnSize);
}
int *rightSideView(struct TreeNode *root, int *returnSize) {
*returnSize = 0;
if (root == NULL) return NULL;
res = (int *) malloc(sizeof(int) * 100);
size = 0;
dfs(root, 0, returnSize);
return res;
}
// 保存左右子树到栈中,再修改左右指针
void flatten(struct TreeNode *root) {
if (root == NULL) return;
struct TreeNode *stack[2000];
int top = 0;
struct TreeNode *temp, *pre = NULL;
stack[top++] = root;
while (top != 0) {
root = stack[--top];
temp = root;
// 先压右,后压左
if (root->right != NULL) stack[top++] = root->right;
if (root->left != NULL) stack[top++] = root->left;
temp->left = NULL;
if (pre != NULL) pre->right = temp;
pre = temp;
}
}
// todo
// 神似morris
void flatten(struct TreeNode *root) {
while (root != NULL) {
if (root->left != NULL) {
struct TreeNode *rightMost = root->left;
while (rightMost->right != NULL)
rightMost = rightMost->right;
// 把右子树接到左子树的最右边的节点上
rightMost->right = root->right;
// 把追加过的左子树移到右子树的位置
// 下一步访问的其实还是左节点,保证了先序
root->right = root->left;
root->left = NULL;
}
root = root->right;
}
}
struct TreeNode *pre;
// 先序序列倒过来访问的递归写法(后序遍历递归写法的改写)
void dfs(struct TreeNode *root) {
if (root == NULL) return;
dfs(root->right);
dfs(root->left);
root->left = NULL;
root->right = pre;
pre = root;
}
void flatten(struct TreeNode *root) {
pre = NULL;
dfs(root);
}
// 先序序列倒过来访问的迭代写法(后序遍历迭代写法的改写)
void flatten(struct TreeNode *root) {
if (root == NULL) return;
struct TreeNode *stack[2000];
int top = 0;
struct TreeNode *pre = NULL;
while (top != 0 || root != NULL) {
while (root != NULL) {
stack[top++] = root;
root = root->right;
}
root = stack[--top];
if (root->left != NULL && pre != root->left) {
// 左子树不空且未被访问过
stack[top++] = root;
root = root->left;
} else {
// 左子树已经访问,可以处理当前节点
root->left = NULL;
root->right = pre;
pre = root;
root = NULL;
}
}
}
// 保存先序遍历的节点,再遍历一遍节点并同时修改
// 递归
struct TreeNode *generate(int *preorder, int start, int preorderSize, int *inorder, int left, int right) {
if (start > preorderSize || left > right) return NULL;
struct TreeNode *root = (struct TreeNode *) malloc(sizeof(struct TreeNode));
// start是前序遍历中当前正在处理的节点
root->val = preorder[start];
// todo 可以用散列快速定位
// 定位root在中序遍历中的位置,left到pos-1的元素用于构造左子树,pos+1到right的元素用于构造右子树
int pos = left;
for (int i = left; i <= right; ++i) {
if (inorder[i] == preorder[start]) {
pos = i;
break;
}
}
// 先序: {preorder[start]}
// {左子树(一共leftCount个元素)}
// {右子树,第一个元素为preorder[start+1+leftCount]}
// 中序: {left到pos-1(一共leftCount个元素),用于构造左子树}
// {preorder[start]也就是inorder[pos]}
// {pos+1到right用于构造右子树}
// 左子树元素个数
int leftCount = pos - left;
// 构造左子树,左子树第一个节点的值是preorder[start+1]
root->left = generate(preorder, start + 1, preorderSize, inorder, left, pos - 1);
// 构造右子树,右子树第一个节点的值是preorder[start+1+leftCount]
// 因为前序遍历中的start+1到start+leftCount一共leftCount个元素是用来构造左子树的
root->right = generate(preorder, start + 1 + leftCount, preorderSize, inorder, pos + 1, right);
return root;
}
struct TreeNode *buildTree(int *preorder, int preorderSize, int *inorder, int inorderSize) {
return generate(preorder, 0, preorderSize, inorder, 0, inorderSize - 1);
}
// todo 看不懂
int pre;
int in;
struct TreeNode *generate(int *preorder, int preorderSize, int *inorder, int inorderSize, int stop) {
if (pre == preorderSize) return NULL;
if (inorder[in] == stop) {
in++;
return NULL;
}
int rootVal = preorder[pre++];
struct TreeNode *root = (struct TreeNode *) malloc(sizeof(struct TreeNode));
root->val = rootVal;
root->left = generate(preorder, preorderSize, inorder, inorderSize, rootVal);
root->right = generate(preorder, preorderSize, inorder, inorderSize, stop);
return root;
}
struct TreeNode *buildTree(int *preorder, int preorderSize, int *inorder, int inorderSize) {
pre = 0;
in = 0;
return generate(preorder, preorderSize, inorder, inorderSize, 0x7fffffff);
}
// todo 迭代
struct TreeNode *buildTree(int *preorder, int preorderSize, int *inorder, int inorderSize) {
if (preorderSize == 0) return NULL;
struct TreeNode **stack = (struct TreeNode **) malloc(sizeof(struct TreeNode *) * 3000);
int top = 0;
int pre = 0;
int in = 0;
// 先序遍历的第一个值作为根节点
struct TreeNode *curRoot = (struct TreeNode *) malloc(sizeof(struct TreeNode));
curRoot->val = preorder[pre++];
curRoot->left = NULL;
curRoot->right = NULL;
stack[top++] = curRoot;
// 作为最终根节点返回
struct TreeNode *root = curRoot;
// 遍历前序遍历的数组
while (pre < preorderSize) {
// 出现了当前节点的值和中序遍历数组的值相等,寻找是谁的右子树
if (curRoot->val == inorder[in]) {
// 每次进行出栈,实现倒着遍历
while (top != 0 && stack[top - 1]->val == inorder[in]) {
curRoot = stack[--top];
in++;
}
// 设为当前的右孩子
struct TreeNode *node = (struct TreeNode *) malloc(sizeof(struct TreeNode));
node->val = preorder[pre++];
node->left = NULL;
node->right = NULL;
curRoot->right = node;
curRoot = curRoot->right;
stack[top++] = curRoot;
} else {
// 否则 作为左子树
struct TreeNode *node = (struct TreeNode *) malloc(sizeof(struct TreeNode));
node->val = preorder[pre++];
node->left = NULL;
node->right = NULL;
curRoot->left = node;
curRoot = curRoot->left;
stack[top++] = curRoot;
}
}
return root;
}
// 返回从root开始往下的路径中和为targetSum的情况总数
int dfsCount(struct TreeNode *root, int targetSum, long long tempSum) {
if (root == NULL) return 0;
int tempRes = 0;
tempSum += root->val;
if (tempSum == targetSum) tempRes++;
tempRes += dfsCount(root->left, targetSum, tempSum);
tempRes += dfsCount(root->right, targetSum, tempSum);
return tempRes;
}
// 累加从每个节点出发的情况总数
int dfs(struct TreeNode *root, long long targetSum) {
if (root == NULL) return 0;
return dfsCount(root, targetSum, 0) + dfs(root->left, targetSum) + dfs(root->right, targetSum);
}
// 暴力递归
int pathSum(struct TreeNode *root, int targetSum) {
return dfs(root, targetSum);
}
// java版暴力递归
class Solution {
int dfsCount(TreeNode root, int targetSum, long tempSum) {
if (root == null) return 0;
int tempRes = 0;
tempSum += root.val;
if (tempSum == targetSum) tempRes++;
tempRes += dfsCount(root.left, targetSum, tempSum);
tempRes += dfsCount(root.right, targetSum, tempSum);
return tempRes;
}
int dfs(TreeNode root, int targetSum) {
if (root == null) return 0;
return dfsCount(root, targetSum, 0) + dfs(root.left, targetSum) + dfs(root.right, targetSum);
}
public int pathSum(TreeNode root, int targetSum) {
return dfs(root, targetSum);
}
}
// todo *树的前缀和+回溯
class Solution {
// 保存前缀树,key为前缀和,value为前缀和出现的次数
Map<Long, Integer> hashMap = new HashMap<Long, Integer>();
public int pathSum(TreeNode root, int targetSum) {
// 前缀树为0的个数至少是一个
hashMap.put(0L, 1);
return dfs(root, 0, targetSum);
}
public int dfs(TreeNode root, long prefixSum, int targetSum) {
if (root == null) return 0;
// 计算前缀和
prefixSum += root.val;
// 若是存在前缀和为prefixSum - target的节点,则该节点到当前节点的路径就是符合题意的
int cur = hashMap.getOrDefault(prefixSum - targetSum, 0);
// 保存前缀和
hashMap.put(prefixSum, hashMap.getOrDefault(prefixSum, 0) + 1);
// 计算左右子树符合题意的个数
int left = dfs(root.left, prefixSum, targetSum);
int right = dfs(root.right, prefixSum, targetSum);
// 从map中去掉当前节点的前缀和,使得兄弟结点无法使用当前结点的前缀和
hashMap.put(prefixSum, hashMap.get(prefixSum) - 1);
return cur + left + right;
}
}
// 前提:节点的值唯一,p、q都在二叉树中
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q){
if(root == NULL)
// 如果树为空,直接返回null
return NULL;
if(root == p || root == q)
// 如果p和q中有等于root的,那么它们的最近公共祖先即为root(一个节点也可以是它自己的祖先)
return root;
// 递归遍历左子树,只要在左子树中找到了p或q,则先找到谁就返回谁
struct TreeNode *left = lowestCommonAncestor(root->left, p, q);
// 递归遍历右子树,只要在右子树中找到了p或q,则先找到谁就返回谁
struct TreeNode *right = lowestCommonAncestor(root->right, p, q);
if(left == NULL)
// 如果在左子树中p和q都找不到,则 p和 q一定都在右子树中,右子树中先遍历到的那个就是最近公共祖先(一个节点也可以是它自己的祖先)
return right;
else if(right == NULL)
// 否则,如果left不为空,在左子树中有找到节点(p或q),这时候要再判断一下右子树中的情况。如果在右子树中,p和q都找不到,则p和q一定都在左子树中,左子树中先遍历到的那个就是最近公共祖先(一个节点也可以是它自己的祖先)
return left;
else
//否则,当left和right均不为空时,说明p、q节点分别在 root异侧, 最近公共祖先即为 root
return root;
}
// 方法二:记录跟节点到p、q的路径。从p、q往上找到第一个公共的节点
class Solution {
public:
int res = INT_MIN;
// 返回向父节点能提供的最长单侧路径和(只能来自左子树或者右子树一边)
int dfs(TreeNode *root) {
if (root == nullptr) return 0;
int left = dfs(root->left);
int right = dfs(root->right);
// 不向父节点提供时,路径会经过当前的根节点,最大路径和会包括两侧能提供的最长单侧路径和
res = max(res, left + right + root->val);
// 返回较大的单侧路径和,较大的还小于0的话就返回0,表示不向父节点提供
return max(max(left, right) + root->val, 0);
}
int maxPathSum(TreeNode *root) {
dfs(root);
return res;
}
};
图
struct Coordinate {
int x;
int y;
};
int res;
// 暂存字符为1坐标
struct Coordinate *stack;
// 栈顶指针
int top;
// 访问标记数组,0表示尚未访问,1表示访问过。可以省略,直接在原来的grid上标记
int **visited;
// 方向
int directions[4][2] = {{-1, 0},
{1, 0},
{0, -1},
{0, 1}};
// 迭代写法
void dfs(char **grid, int rowSize, int columnSize, int x, int y) {
// 标记访问
visited[x][y] = 1;
if (grid[x][y] == '0') return;
// 否则就是字符1,把坐标(x, y)入栈
stack[top].x = x;
stack[top].y = y;
top++;
while (top > 0) {
int tempX = stack[top - 1].x;
int tempY = stack[top - 1].y;
// 表示node坐标四周是否还有未被访问过的1
int flag = false;
// 按上下左右的顺序找
for (int i = 0; i < 4; ++i) {
int newX = tempX + directions[i][0];
int newY = tempY + directions[i][1];
// 新坐标未越界,且尚未访问过
if ((newX >= 0 && newX < rowSize && newY >= 0 && newY < columnSize)
&& visited[newX][newY] == 0) {
// 标记访问
visited[newX][newY] = 1;
// 是1就入栈
if (grid[newX][newY] == '1') {
flag = true;
stack[top].x = newX;
stack[top].y = newY;
top++;
}
}
}
// 都被访问过了就把当前坐标出栈,回溯上个坐标
if (!flag) top--;
}
// 当前岛屿的处理完,边界要么是字符0要么是越界
res++;
}
int numIslands(char **grid, int gridSize, int *gridColSize) {
res = 0;
stack = (struct Coordinate *) malloc(sizeof(struct Coordinate) * gridSize * (*gridColSize));
top = 0;
visited = (int **) malloc(sizeof(int *) * gridSize);
for (int i = 0; i < gridSize; ++i)
visited[i] = (int *) calloc(*gridColSize, sizeof(int));
for (int i = 0; i < gridSize; ++i)
for (int j = 0; j < *gridColSize; ++j)
// 从没访问过的坐标开始遍历
if (visited[i][j] == 0)
dfs(grid, gridSize, *gridColSize, i, j);
return res;
}
// 方向
int directions[4][2] = {{-1, 0},
{1, 0},
{0, -1},
{0, 1}};
// 判断坐标是否越界
bool isCoordinateLegal(int rowSize, int columnSize, int x, int y) {
return x >= 0 && x < rowSize && y >= 0 && y < columnSize;
}
// 判断是否访问过,0表示海洋,1表示陆地,2表示访问过
bool isVisited(char **grid, int x, int y) {
return grid[x][y] == '2';
}
void markVisited(char **grid, int x, int y) {
grid[x][y] = '2';
}
void dfs(char **grid, int rowSize, int columnSize, int x, int y) {
// 标记访问
markVisited(grid, x, y);
// 按上下左右的顺序找
for (int i = 0; i < 4; ++i) {
int newX = x + directions[i][0];
int newY = y + directions[i][1];
// 新坐标未越界,且尚未访问过
if (isCoordinateLegal(rowSize, columnSize, newX, newY) && !isVisited(grid, newX, newY)) {
if (grid[newX][newY] == '1')
dfs(grid, rowSize, columnSize, newX, newY);
}
}
}
int numIslands(char **grid, int gridSize, int *gridColSize) {
int res = 0;
for (int i = 0; i < gridSize; ++i) {
for (int j = 0; j < *gridColSize; ++j) {
// 从没访问过的且字符是1的坐标开始遍历
if (!isVisited(grid, i, j)) {
if (grid[i][j] == '1') {
res++;
dfs(grid, gridSize, *gridColSize, i, j);
}
markVisited(grid, i, j);
}
}
}
return res;
}
// BFS
// 并查集
struct Coordinate {
int x;
int y;
};
int directions[4][2] = {{-1, 0},
{1, 0},
{0, -1},
{0, 1}};
int rowSize;
int columnSize;
int sizeOfQueue;
int front;
int rear;
int freshNum;
// 烂橘子左边队列
struct Coordinate *queue;
bool isCoordinateLegal(int x, int y) {
return x >= 0 && x < rowSize && y >= 0 && y < columnSize;
}
// 感染四周的新鲜橘子,并将其入队
void infect(int **grid, int x, int y) {
for (int i = 0; i < 4; ++i) {
int newX = x + directions[i][0];
int newY = y + directions[i][1];
if (isCoordinateLegal(newX, newY) && grid[newX][newY] == 1) {
// 被感染的新鲜橘子入队
grid[newX][newY] = 2;
queue[rear].x = newX;
queue[rear].y = newY;
rear = (rear + 1) % sizeOfQueue;
// 少了个新鲜橘子
freshNum--;
}
}
}
int orangesRotting(int **grid, int gridSize, int *gridColSize) {
rowSize = gridSize;
columnSize = *gridColSize;
sizeOfQueue = rowSize * columnSize + 1;
queue = (struct Coordinate *) malloc(sizeof(struct Coordinate) * sizeOfQueue);
front = 0;
rear = 0;
freshNum = 0;
for (int i = 0; i < rowSize; ++i) {
for (int j = 0; j < columnSize; ++j) {
if (grid[i][j] == 2) {
// 把烂橘子入队
queue[rear].x = i;
queue[rear].y = j;
rear = (rear + 1) % sizeOfQueue;
} else if (grid[i][j] == 1) {
// 记录新鲜橘子数
freshNum++;
}
}
}
// 感染轮数
int res = 0;
while (front != rear) {
int tempRear = rear;
int count = (rear - front + sizeOfQueue) % sizeOfQueue;
while (count-- > 0) {
// 出队
int tempX = queue[front].x;
int tempY = queue[front].y;
front = (front + 1) % sizeOfQueue;
// 感染四周的新鲜橘子,并将其入队
infect(grid, tempX, tempY);
}
// 有新的烂橘子入队,表明感染了一轮
if (rear != tempRear) res++;
}
// 无法感染时,检查是否还有新鲜橘子
return freshNum == 0 ? res : -1;
}
// BFS:kahn算法找入度为0的顶点
// prerequisites[i][0]为弧头节点,prerequisites[i][1]为弧尾节点
bool canFinish(int numCourses, int **prerequisites, int prerequisitesSize, int *prerequisitesColSize) {
// 记录各个顶点的入度
int *inDegrees = (int *) calloc(numCourses, sizeof(int));
// 记录入度为0的顶点
int stack[numCourses];
int top = 0;
// 遍历每条弧,记录入度
for (int i = 0; i < prerequisitesSize; ++i)
inDegrees[prerequisites[i][0]]++;
// 遍历每个顶点,记录入度为0的顶点
for (int i = 0; i < numCourses; ++i)
if (inDegrees[i] == 0)
stack[top++] = i;
// 剩余未删除的弧的个数
int leftEdgeCount = prerequisitesSize;
while (top != 0) {
int k = stack[--top];
// 将所有以k为弧尾节点的弧断开
for (int i = 0; i < prerequisitesSize; ++i) {
if (prerequisites[i][1] == k) {
// 删除弧
leftEdgeCount--;
// 弧头顶点入度减一
inDegrees[prerequisites[i][0]]--;
// 若弧头节点的入度减小成0,则入栈
if (inDegrees[prerequisites[i][0]] == 0)
stack[top++] = prerequisites[i][0];
}
}
}
return leftEdgeCount == 0;
}
struct EdgeNode {
int vertex;
struct EdgeNode *next;
};
struct VertexNode {
int vertex;
struct EdgeNode *dummyHead;
};
struct Graph {
struct VertexNode *adjList;
int vertexNum;
int edgeNum;
};
struct Graph *createGraph(int numCourses, int **prerequisites, int prerequisitesSize) {
struct Graph *graph = (struct Graph *) malloc(sizeof(struct Graph));
graph->vertexNum = numCourses;
graph->edgeNum = prerequisitesSize;
graph->adjList = (struct VertexNode *) malloc(sizeof(struct VertexNode) * numCourses);
for (int i = 0; i < numCourses; ++i) {
graph->adjList[i].dummyHead = (struct EdgeNode *) malloc(sizeof(struct EdgeNode));
graph->adjList[i].vertex = i;
graph->adjList[i].dummyHead->next = NULL;
}
// 建立邻接表
for (int i = 0; i < prerequisitesSize; ++i) {
struct EdgeNode *node = (struct EdgeNode *) malloc(sizeof(struct EdgeNode));
node->vertex = prerequisites[i][0];
struct EdgeNode *dummyHead = graph->adjList[prerequisites[i][1]].dummyHead;
// 头插法
node->next = dummyHead->next;
dummyHead->next = node;
}
return graph;
}
// 访问标记数组,0表示未访问,1表示正在访问,2表示访问结束
int *visited;
struct Graph *graph;
bool hasCircle;
void dfs(int **prerequisites, int vertex) {
if (hasCircle) return;
// 正在访问当前节点
visited[vertex] = 1;
struct EdgeNode *cur = graph->adjList[vertex].dummyHead->next;
while (cur != NULL) {
if (visited[cur->vertex] == 1) {
// 同一个递归中访问到正在访问的顶点,表示出现环
hasCircle = true;
return;
}
if (visited[cur->vertex] == 0)
// 尚未访问就进行访问,访问完毕的已经退出他自己的递归了,不需要处理
dfs(prerequisites, cur->vertex);
cur = cur->next;
}
// 当前节点访问完毕
visited[vertex] = 2;
// 如果需要输出拓扑序列的话,可以在此处将节点压入栈中,最后输出栈
}
// DFS:逆拓扑排序,找出度为0的顶点
bool canFinish(int numCourses, int **prerequisites, int prerequisitesSize, int *prerequisitesColSize) {
visited = (int *) calloc(numCourses, sizeof(int));
graph = createGraph(numCourses, prerequisites, prerequisitesSize);
hasCircle = false;
for (int i = 0; i < numCourses; ++i)
if (visited[i] == 0)
dfs(prerequisites, i);
return !hasCircle;
}
// 结构体定义中不能直接赋值
typedef struct TrieNode {
bool isEnd;
// 指针数组
struct TrieNode *children[26];
} Trie;
Trie *trieCreate() {
Trie *root = (Trie *) malloc(sizeof(Trie));
root->isEnd = false;
memset(root->children, 0, sizeof(root->children));
return root;
}
void trieInsert(Trie *obj, char *word) {
Trie *cur = obj;
int len = strlen(word);
for (int i = 0; i < len; ++i) {
char ch = word[i];
if (cur->children[ch - 'a'] == NULL) {
Trie *node = (Trie *) malloc(sizeof(Trie));
node->isEnd = false;
memset(node->children, 0, sizeof(node->children));
// 给cur增加一个孩子节点
cur->children[ch - 'a'] = node;
}
// 移到对应孩子节点
cur = cur->children[ch - 'a'];
}
cur->isEnd = true;
}
bool trieSearch(Trie *obj, char *word) {
Trie *cur = obj;
int len = strlen(word);
for (int i = 0; i < len; ++i) {
char ch = word[i];
// 没有往下的路径了
if (cur->children[ch - 'a'] == NULL) return false;
// 移到对应孩子节点
cur = cur->children[ch - 'a'];
}
return cur->isEnd;
}
bool trieStartsWith(Trie *obj, char *prefix) {
Trie *cur = obj;
int len = strlen(prefix);
for (int i = 0; i < len; ++i) {
char ch = prefix[i];
// 没有往下的路径了
if (cur->children[ch - 'a'] == NULL) return false;
// 移到对应孩子节点
cur = cur->children[ch - 'a'];
}
return true;
}
void trieFree(Trie *obj) {
free(obj);
obj = NULL;
}
回溯
int **res;
int *hashMap;
int *rtSize;
// temp中0到curIndex已经放入数据,现在往curIndex处放入所有可能
void generate(int *nums, int numsSize, int *temp, int curIndex) {
// temp已经放满,把当前排列添加到结果中
if (curIndex == numsSize) {
for (int i = 0; i < numsSize; ++i) {
res[(*rtSize)][i] = temp[i];
}
(*rtSize)++;
return;
}
for (int i = 0; i < numsSize; ++i) {
// nums[i]还没放入,就放入到curIndex位置
if (hashMap[nums[i] + 10] == 0) {
temp[curIndex] = nums[i];
// 标记nums[i]已经放入
hashMap[nums[i] + 10] = 1;
// 递归处理子问题,尝试curIndex+1处所有的放入可能
generate(nums, numsSize, temp, curIndex + 1);
// 取消标记,再尝试在curIndex处放入其他还没使用过的数据
hashMap[nums[i] + 10] = 0;
}
}
}
// 按字典序输出
int **permute(int *nums, int numsSize, int *returnSize, int **returnColumnSizes) {
// 最多的组合数
const int maxSize = 720;
*returnSize = 0;
res = (int **) malloc(sizeof(int *) * maxSize);
*returnColumnSizes = (int *) malloc(sizeof(int) * maxSize);
for (int i = 0; i < 720; ++i) {
res[i] = (int *) malloc(sizeof(int) * numsSize);
(*returnColumnSizes)[i] = numsSize;
}
rtSize = returnSize;
// 标记数据是否已经使用过(即放入temp数组)
hashMap = (int *) calloc(21, sizeof(int));
// 暂存当前的排列
int *temp = (int *) malloc(sizeof(int) * numsSize);
generate(nums, numsSize, temp, 0);
return res;
}
int **res;
int *rtSize;
void swap(int *array, int left, int right) {
if (left == right) return;
int temp = array[left];
array[left] = array[right];
array[right] = temp;
}
// temp中0到curIndex已经放入数据,现在往curIndex处放入所有可能
void generate(int *nums, int numsSize, int *temp, int curIndex) {
// temp已经放满,把当前排列添加到结果中
if (curIndex == numsSize) {
for (int i = 0; i < numsSize; ++i) {
res[(*rtSize)][i] = temp[i];
}
(*rtSize)++;
return;
}
// nums[left]开始到末尾都是尚未使用过的元素,从中挑出一个使用,并且在nums中和nums[left]交换位置
// 这样以来nums从开头到nums[left]就是已经使用过的元素
int left = curIndex;
for (int right = left; right < numsSize; ++right) {
temp[curIndex] = nums[right];
// 标记nums[i]已经放入
swap(nums, left, right);
// 递归处理子问题,尝试curIndex+1处所有的放入可能
generate(nums, numsSize, temp, curIndex + 1);
// 取消标记,再尝试在curIndex处放入其他还没使用过的数据
swap(nums, left, right);
}
}
// 不按字典序输出,不使用hashMap标记元素是否使用过
int **permute(int *nums, int numsSize, int *returnSize, int **returnColumnSizes) {
// 最多的组合数
const int maxSize = 720;
*returnSize = 0;
res = (int **) malloc(sizeof(int *) * maxSize);
*returnColumnSizes = (int *) malloc(sizeof(int) * maxSize);
for (int i = 0; i < 720; ++i) {
res[i] = (int *) malloc(sizeof(int) * numsSize);
(*returnColumnSizes)[i] = numsSize;
}
rtSize = returnSize;
// 暂存当前的排列
int *temp = (int *) malloc(sizeof(int) * numsSize);
generate(nums, numsSize, temp, 0);
return res;
}
// 以 curIndex 作为标记,nums[0, curIndex)是已经排好的,也就是使用过的元素
class Solution {
public:
vector<vector<int>> res;
void backtrack(vector<int> &nums, int curIndex) {
if (curIndex == nums.size()) {
res.emplace_back(nums);
return;
}
// nums[0, curIndex)是已经排好的,从 nums[curIndex, nums.size()-1]中选一个 nums[i] 放到 nums[curIndex]
for (int i = curIndex; i < nums.size(); ++i) {
// nums[i] 放到 nums[curIndex]
swap(nums[i], nums[curIndex]);
// 继续递归填下一个数
backtrack(nums, curIndex + 1);
// 撤销操作
swap(nums[i], nums[curIndex]);
}
}
// 不按字典序输出
vector<vector<int>> permute(vector<int> &nums) {
backtrack(nums, 0);
return res;
}
};
// 把 nums 数组当作标记数组
class Solution {
public:
vector<vector<int>> res;
vector<int> output;
// output 中 0 到 curIndex 已经放入数据,现在往 curIndex 处放入所有可能
void backtrack(vector<int> &nums, int curIndex) {
// output 已经放满,把当前排列添加到结果中
if (curIndex == nums.size()) {
res.emplace_back(output);
return;
}
for (int i = 0; i < nums.size(); ++i) {
// 已经被使用过的就跳过
if (nums[i] == INT_MIN) continue;
int temp = nums[i];
// 标记
nums[i] = INT_MIN;
output.emplace_back(temp);
// 继续递归填下一个数
backtrack(nums, curIndex + 1);
// 撤销操作
output.pop_back();
nums[i] = temp;
}
}
// 不按字典序输出
vector<vector<int>> permute(vector<int> &nums) {
backtrack(nums, 0);
return res;
}
};
int **res;
int *rtSize;
int **rtColumnSize;
void generate(int *nums, int numsSize, int *temp, int len, int curIndex, int nextStart) {
if (curIndex == len) {
// 将长度为len的子集加入结果
res[*rtSize] = (int *) malloc(sizeof(int) * len);
(*rtColumnSize)[*rtSize] = len;
for (int i = 0; i < len; ++i)
res[*rtSize][i] = temp[i];
(*rtSize)++;
return;
}
// 当前位置选nums[i],那么后面位置选的元素是从nums[i+1]开始选择的,避免选重复了
// nextStart之前的已经被考虑过了
for (int i = nextStart; i < numsSize; ++i) {
// 从curIndex到结尾挑一个放在curIndex
temp[curIndex] = nums[i];
// 在curIndex已经放入nums[i]的条件下,考虑curIndex+1放入i后面的元素中的哪一个
generate(nums, numsSize, temp, len, curIndex + 1, i + 1);
}
}
int **subsets(int *nums, int numsSize, int *returnSize, int **returnColumnSizes) {
const int maxSize = 1024;
res = (int **) malloc(sizeof(int *) * maxSize);
rtSize = returnSize;
*rtSize = 0;
rtColumnSize = returnColumnSizes;
*rtColumnSize = (int *) malloc(sizeof(int) * maxSize);
int *temp = (int *) malloc(sizeof(int) * numsSize);
res[0] = NULL;
(*rtColumnSize)[0] = 0;
(*rtSize)++;
// 生成的长度逐渐加一
for (int len = 1; len <= numsSize; ++len)
generate(nums, numsSize, temp, len, 0, 0);
return res;
}
// todo 01序列表示对应位置的元素是否选中
int **subsets(int *nums, int numsSize, int *returnSize, int **returnColumnSizes) {
int **res = (int **) malloc(sizeof(int *) * (1 << numsSize));
*returnColumnSizes = (int *) malloc(sizeof(int) * (1 << numsSize));
*returnSize = 1 << numsSize;
int temp[numsSize];
// mask中1的个数代表了子集中元素个数
for (int mask = 0; mask < (1 << numsSize); ++mask) {
// 记录子集中元素个数
int len = 0;
for (int i = 0; i < numsSize; ++i) {
// 根据mask中1的位置判断nums[i]是否被选中
// mask & (1 << i) != 0 说明被选中了
if (mask & (1 << i)) {
temp[len++] = nums[i];
}
}
int *tempRes = (int *) malloc(sizeof(int) * len);
memcpy(tempRes, temp, sizeof(int) * len);
(*returnColumnSizes)[mask] = len;
res[mask] = tempRes;
}
return res;
}
int **res;
int *rtSize;
int **rtColumnSize;
void generate(int *nums, int numsSize, int *temp, int len, int cur) {
// cur==numsSize为true时,表示temp中已经在长度为len的情况下,已经尝试放过所有的元素
if (cur == numsSize) {
int *tempRes = (int *) malloc(sizeof(int) * len);
memcpy(tempRes, temp, sizeof(int) * len);
(*rtColumnSize)[*rtSize] = len;
res[*rtSize] = tempRes;
(*rtSize)++;
return;
}
// 1.在temp[len]处放nums[cur],然后考虑在temp[len+1]处放nums数组中从cur+1到结尾中的哪个元素
temp[len] = nums[cur];
generate(nums, numsSize, temp, len + 1, cur + 1);
// 2.不在temp[len]处放nums[cur],而是考虑在temp[len]处放nums数组中从cur+1到结尾中的哪个元素
generate(nums, numsSize, temp, len, cur + 1);
}
int **subsets(int *nums, int numsSize, int *returnSize, int **returnColumnSizes) {
res = (int **) malloc(sizeof(int *) * (1 << numsSize));
rtSize = returnSize;
*rtSize = 0;
rtColumnSize = returnColumnSizes;
*rtColumnSize = (int *) malloc(sizeof(int) * (1 << numsSize));
int *temp = (int *) malloc(sizeof(int) * numsSize);
generate(nums, numsSize, temp, 0, 0);
return res;
}
char **res;
int *rtSize;
char *temp;
char phoneMap[10][5] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
int digitsLen;
void generate(char *digits, int curIndex) {
// digits已经处理完,curIndex表示正在处理digits中下标为curIndex的数字
if (curIndex == digitsLen) {
temp[curIndex] = '\0';
char *tempRes = (char *) malloc(sizeof(char) * (curIndex + 1));
memcpy(tempRes, temp, sizeof(char) * (curIndex + 1));
res[*rtSize] = tempRes;
(*rtSize)++;
return;
}
char *phoneStr = phoneMap[digits[curIndex] - '0'];
for (int i = 0; i < strlen(phoneStr); ++i) {
// temp中curIndex处放入phoneStr中的一个字符
temp[curIndex] = phoneStr[i];
// 在放入phoneStr[i]的情况下,递归处理子问题在curIndex+1处放什么字符
generate(digits, curIndex + 1);
}
}
char **letterCombinations(char *digits, int *returnSize) {
*returnSize = 0;
digitsLen = strlen(digits);
if (digits == NULL || digitsLen == 0) return NULL;
rtSize = returnSize;
res = (char **) malloc(sizeof(char *) * 256);
temp = (char *) malloc(sizeof(char) * 5);
generate(digits, 0);
return res;
}
int *rtSize;
int **rtColumnSize;
int targetSum;
int **res;
int *temp;
void generate(int *candidates, int candidateSize, int start, int curIndex, int tempSum) {
if (tempSum == targetSum) {
int *tempRes = (int *) malloc(sizeof(int) * curIndex);
memcpy(tempRes, temp, sizeof(int) * curIndex);
res[*rtSize] = tempRes;
(*rtColumnSize)[*rtSize] = curIndex;
(*rtSize)++;
return;
}
// 如果curIndex放的时candidates[i],那么curIndex+1处不能取下标i之前的元素,防止重复
// 但curIndex+1处可以继续取candidates[i]
// 从start开始取,防止重复
for (int i = start; i < candidateSize; ++i) {
// 超过目标和就舍弃
if (tempSum + candidates[i] > targetSum) continue;
// 1.在curIndex放candidates[i]
tempSum += candidates[i];
temp[curIndex] = candidates[i];
// 递归处理子问题:在curIndex+1处放入什么元素
generate(candidates, candidateSize, i, curIndex + 1, tempSum);
// 2.回溯,取消在curIndex放candidates[i],尝试放入其他元素
tempSum -= candidates[i];
}
}
int **combinationSum(int *candidates, int candidatesSize, int target, int *returnSize, int **returnColumnSizes) {
*returnSize = 0;
rtSize = returnSize;
*returnColumnSizes = (int *) malloc(sizeof(int) * 150);
rtColumnSize = returnColumnSizes;
res = (int **) malloc(sizeof(int *) * 150);
temp = (int *) malloc(sizeof(int) * 20);
targetSum = target;
generate(candidates, candidatesSize, 0, 0, 0);
return res;
}
char **res;
int *rtSize;
char *temp;
void generate(int n, int curIndex, int leftBracketNum, int rightBracketNum) {
// 左右括号都用完
if (leftBracketNum == 0 && rightBracketNum == 0) {
temp[curIndex] = '\0';
char *tempRes = (char *) malloc(sizeof(char) * ((n << 1) + 1));
memcpy(tempRes, temp, sizeof(char) * ((n << 1) + 1));
res[(*rtSize)++] = tempRes;
return;
}
// 放入(的条件:剩余(的数量大于0
if (leftBracketNum > 0) {
// 1.curIndex处放(
temp[curIndex] = '(';
// 处理子问题curIndex+1处放什么
generate(n, curIndex + 1, leftBracketNum - 1, rightBracketNum);
}
// 放入)的条件:剩余(的数量小于剩余)的数量
if (leftBracketNum < rightBracketNum) {
// 2.curIndex处放)
temp[curIndex] = ')';
// 处理子问题curIndex+1处放什么
generate(n, curIndex + 1, leftBracketNum, rightBracketNum - 1);
}
}
char **generateParenthesis(int n, int *returnSize) {
*returnSize = 0;
rtSize = returnSize;
res = (char **) malloc(sizeof(char *) * (1 << (n << 1)));
temp = (char *) malloc(sizeof(char) * ((n << 1) + 1));
generate(n, 0, n, n);
return res;
}
// todo bfs
bool res;
int len;
int rowSize;
int columnSize;
void recursive(char **board, char *word, int curIndex, int curRow, int curColumn) {
// 已经找到就不找了
if (res) return;
// 找到了
if (curIndex == len) {
res = true;
return;
}
// 坐标越界、board[curRow][curColumn]已经和之前的某一位匹配过了、或者和当前位不匹配都直接返回
if ((curRow < 0 || curRow >= rowSize || curColumn < 0 || curColumn >= columnSize)
|| (board[curRow][curColumn] == '0')
|| (board[curRow][curColumn] != word[curIndex]))
return;
// 匹配的情况下,置为0,标记已经匹配过
char tempChar = board[curRow][curColumn];
board[curRow][curColumn] = '0';
// 再找下一个和word[curIndex+1]匹配的
// 1.上
recursive(board, word, curIndex + 1, curRow - 1, curColumn);
// 2.下
recursive(board, word, curIndex + 1, curRow + 1, curColumn);
// 3.左
recursive(board, word, curIndex + 1, curRow, curColumn - 1);
// 4.右
recursive(board, word, curIndex + 1, curRow, curColumn + 1);
// 取消标记,恢复原始状态
board[curRow][curColumn] = tempChar;
}
bool exist(char **board, int boardSize, int *boardColSize, char *word) {
res = false;
len = strlen(word);
rowSize = boardSize;
columnSize = *boardColSize;
for (int i = 0; i < rowSize; ++i)
for (int j = 0; j < columnSize; ++j)
// 从每个位置作为起点开始
recursive(board, word, 0, i, j);
return res;
}
class Solution {
public:
vector<vector<string>> res;
vector<string> output;
int len;
// 判断回文
bool judge(string &str, int left, int right) {
while (left < right) {
if (str[left] != str[right]) return false;
left++;
right--;
}
return true;
}
// curIndex 左边是已经分割好的字符串
void backtrack(string s, int curIndex) {
if (curIndex == len) {
res.emplace_back(output);
return;
}
for (int right = curIndex; right < len; ++right) {
// [curIndex, right] 构不成回文,就跳过
if (!judge(s, curIndex, right)) continue;
// 如果能构成回文,就临时加入 output
output.emplace_back(s.substr(curIndex, right - curIndex + 1));
// 然后递归处理后面的序列
backtrack(s, right + 1);
// 回溯
output.pop_back();
}
}
vector<vector<string>> partition(string s) {
len = s.length();
backtrack(s, 0);
return res;
}
};
class Solution {
public:
vector<vector<string>> res;
// 分别标记列和两个方向的斜线上是否已经存在皇后
unordered_set<int> columns;
unordered_set<int> diagonals1;
unordered_set<int> diagonals2;
vector<vector<string>> solveNQueens(int n) {
// 记录每一行的皇后所在的列
vector<int> queens(n, -1);
backtrack(queens, n, 0);
return res;
}
void backtrack(vector<int> &queens, int n, int row) {
if (row == n) {
vector<string> board = generateBoard(queens, n);
res.push_back(board);
} else {
for (int i = 0; i < n; i++) {
// 当前列已有皇后
if (columns.find(i) != columns.end()) continue;
// 主斜线已有
int diagonal1 = row - i;
if (diagonals1.find(diagonal1) != diagonals1.end()) continue;
// 副斜线已有
int diagonal2 = row + i;
if (diagonals2.find(diagonal2) != diagonals2.end()) continue;
// 把 row 行的皇后放在 i 列
queens[row] = i;
// 标记列和两个方向的斜线上已经存在皇后
columns.insert(i);
diagonals1.insert(diagonal1);
diagonals2.insert(diagonal2);
// 递归处理下一行
backtrack(queens, n, row + 1);
// 取消标记
queens[row] = -1;
columns.erase(i);
diagonals1.erase(diagonal1);
diagonals2.erase(diagonal2);
}
}
}
vector<string> generateBoard(vector<int> &queens, int n) {
vector<string> board;
for (int i = 0; i < n; i++) {
string row = string(n, '.');
row[queens[i]] = 'Q';
board.push_back(row);
}
return board;
}
};
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
vector<vector<string>> res;
// 记录皇后放的位置,queens[i] 二进制位为 1 的地方才是放皇后的位置
// 也可以直接记录具体列号,这样生成结果时快些
vector<int> queens;
int limit;
vector<vector<string>> solveNQueens(int n) {
// 把低 n 位变成 1
limit = (1 << n) - 1;
// -1 的位置表示没有皇后
queens.resize(n, -1);
backtrack(n, 0, 0, 0, 0);
return res;
}
void backtrack(int n, int row, int columns, int diagonals1, int diagonals2) {
if (columns == limit) {
// 生成结果
res.emplace_back(generateBoard(n));
return;
}
// 0 的位置能放,1 的位置不能放
int ban = columns | diagonals1 | diagonals2;
// candidate 为 1 的地方都是可以放皇后的
int candidate = limit & (~ban);
// 尝试每个位置
while (candidate != 0) {
// 最右侧的 1
int place = candidate & (-candidate);
queens[row] = place;
// 累计上当前皇后的影响,(diagonals1 | place) >> 1 的意思是当前 place 位置放皇后的情况下,主斜线对下一行的影响
backtrack(n, row + 1, columns | place, (diagonals1 | place) >> 1, (diagonals2 | place) << 1);
// 删掉最右侧的 1
candidate ^= place;
}
}
vector<string> generateBoard(int n) {
vector<string> board;
for (int i = 0; i < n; i++) {
string str;
for (int j = 0; j < n; ++j) {
if ((queens[i] & (1 << j)) != 0) {
str += 'Q';
} else {
str += '.';
}
}
board.emplace_back(str);
}
return board;
}
};
二分查找
// 左边界(大于等于target的第一个位置)
int searchInsert(int *nums, int numsSize, int target) {
int left = 0, right = numsSize - 1;
int mid;
while (left <= right) {
mid = ((right - left) >> 1) + left;
if (nums[mid] >= target)
// 往左
right = mid - 1;
else
// 往右
left = mid + 1;
}
// 结束时,left=right+1
// right右边全都大于等于target,left左边全都小于target
return left;
}
int rowSize;
int columnSize;
// 当成一维数组进行二分查找
bool binarySearch(int **matrix, int target, int left, int right) {
if (left > right) return false;
int mid;
while (left <= right) {
mid = left + ((right - left) >> 1);
// 计算具体坐标
int row = mid / columnSize;
int column = mid % columnSize;
int cur = matrix[row][column];
if (cur == target) {
return true;
} else if (cur > target) {
// 往左
right = mid - 1;
} else {
// 往右
left = mid + 1;
}
}
return false;
}
bool searchMatrix(int **matrix, int matrixSize, int *matrixColSize, int target) {
rowSize = matrixSize;
columnSize = *matrixColSize;
return binarySearch(matrix, target, 0, rowSize * columnSize - 1);
}
bool searchMatrix(int **matrix, int matrixSize, int *matrixColSize, int target) {
int row = 0, column = *matrixColSize - 1;
// 从右上角往左或往下
while (row < matrixSize && column >= 0) {
int cur = matrix[row][column];
if (cur == target) {
return true;
} else if (cur < target) {
// 往下找更大的
row++;
} else {
// 往左找更小的
column--;
}
}
return false;
}
// 左边界
int binarySearch1(int *array, int size, int target) {
int left = 0, right = size - 1;
int mid;
while (left <= right) {
mid = ((right - left) >> 1) + left;
if (array[mid] >= target)
right = mid - 1;
else
left = mid + 1;
}
return left;
}
// 右边界
int binarySearch2(int *array, int size, int target) {
int left = 0, right = size - 1;
int mid;
while (left <= right) {
mid = ((right - left) >> 1) + left;
if (array[mid] <= target)
left = mid + 1;
else
right = mid - 1;
}
return right;
}
int *searchRange(int *nums, int numsSize, int target, int *returnSize) {
int *res = (int *) malloc(sizeof(int) * 2);
*returnSize = 2;
int left = binarySearch1(nums, numsSize, target);
int right = binarySearch2(nums, numsSize, target);
if (left >= numsSize || nums[left] != target) {
res[0] = -1;
res[1] = -1;
} else {
res[0] = left;
res[1] = right;
}
return res;
}
// 递归
int binarySearchNums(int *nums, int target, int left, int right) {
if (left > right) return -1;
int mid = left + ((right - left) >> 1);
if (nums[mid] == target) return mid;
if (nums[mid] >= nums[left]) {
// [left, mid-1]是有序的,并且target在范围内
if ((left <= mid - 1) && nums[left] <= target && nums[mid - 1] >= target)
return binarySearchNums(nums, target, left, mid - 1);
else
return binarySearchNums(nums, target, mid + 1, right);
} else {
// [mid+1, right]是有序的,并且target在范围内
if ((mid + 1 <= right) && nums[mid + 1] <= target && nums[right] >= target)
return binarySearchNums(nums, target, mid + 1, right);
else
return binarySearchNums(nums, target, left, mid - 1);
}
}
int search(int *nums, int numsSize, int target) {
return binarySearchNums(nums, target, 0, numsSize - 1);
}
// 迭代
int binarySearchNums(int *nums, int target, int left, int right) {
if (left > right) return -1;
int mid;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (nums[mid] == target) return mid;
if (nums[mid] >= nums[left]) {
// [left, mid-1]是有序的,并且target在范围内
if ((left <= mid - 1) && nums[left] <= target && nums[mid - 1] >= target)
right = mid - 1;
else
left = mid + 1;
} else {
// [mid+1, right]是有序的,并且target在范围内
if ((mid + 1 <= right) && nums[mid + 1] <= target && nums[right] >= target)
left = mid + 1;
else
right = mid - 1;
}
}
return -1;
}
int search(int *nums, int numsSize, int target) {
return binarySearchNums(nums, target, 0, numsSize - 1);
}
// 循环右移的nums
int findMin(int *nums, int numsSize) {
int left = 0, right = numsSize - 1;
int min = nums[0];
int mid;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (nums[mid] < min) min = nums[mid];
if (nums[mid] >= nums[left]) {
// [left, mid-1]是顺序区间
if (nums[left] < min) min = nums[left];
// 在右侧区间找
left = mid + 1;
} else {
// [mid+1, right]是顺序区间
if ((mid + 1 <= right) && nums[mid + 1] < min) min = nums[mid + 1];
// 在左侧区间找
right = mid - 1;
}
}
return min;
}
// todo
// 循环右移的nums
int findMin(int *nums, int numsSize) {
int left = 0;
int right = numsSize - 1;
int mid;
// 规律:最小值下标x,[0,x)值都大于等于末尾元素nums[x],[x,numsSize-1]都小于等于末尾元素nums[x]
while (left < right) {
mid = left + ((right - left) >> 1);
if (nums[mid] > nums[right]) {
// [left, mid]都大于nums[right],都排除,在右侧区间[mid+1, right]中找
left = mid + 1;
} else if (nums[mid] < nums[right]) {
// nums[mid]是[mid,right]上最小的,忽略(mid,right]上的,在[left, mid]中找
right = mid;
}
}
// 循环结束时,left等于right,且left左边全都大于nums[left],nums[right]又大于等于其右边的
// 所以最小值就是nums[left]
return nums[left];
}
// todo
// 循环右移的nums
int findMin(int *nums, int numsSize) {
int left = 0;
int right = numsSize - 1;
int mid;
// 规律:最小值下标x,[0,x)值都大于等于末尾元素nums[x],[x,numsSize-1]都小于等于末尾元素nums[x]
while (left < right) {
mid = left + ((right - left) >> 1);
if (nums[mid] > nums[right]) {
// [left, mid]都大于nums[right],都排除,在右侧区间[mid+1, right]中找
left = mid + 1;
} else if (nums[mid] < nums[right]) {
// nums[mid]是[mid,right]上最小的,忽略(mid,right]上的,在[left, mid]中找
right = mid;
} else {
// 忽略末尾,新的末尾nums[right-1]也符合规律
right--;
}
}
return nums[left];
}
bool judgeMin(int *nums, int numsSize, int index) {
// 同时比左右两个元素小的就是最小值
if (nums[index] < nums[(index - 1 + numsSize) % numsSize]
&& nums[index] < nums[(index + 1) % numsSize])
return true;
return false;
}
// 对每个最小值可能出现的地方进行判断
int findMin(int *nums, int numsSize) {
int left = 0;
int right = numsSize - 1;
int mid;
while (left < right) {
mid = left + ((right - left) >> 1);
// left可能等于mid,所以要加上等号,表示一个元素nums[left]也有序
if (nums[left] <= nums[mid]) {
// [left, mid]有序
if (judgeMin(nums, numsSize, left)) return nums[left];
left = mid + 1;
} else if (nums[left] > nums[mid]) {
// [mid, right]有序
if (judgeMin(nums, numsSize, mid)) return nums[mid];
right = mid;
}
}
return nums[left];
}
class Solution {
public:
int getKth(vector<int> &ary1, int start1, int end1, vector<int> &ary2, int start2, int end2, int k) {
// 记录两个数组的长度
int len1 = end1 - start1 + 1;
int len2 = end2 - start2 + 1;
// 其中一个数组空了,返回另一个数组中第 k 个小的
if (len1 == 0) return ary2[start2 + k - 1];
if (len2 == 0) return ary1[start1 + k - 1];
// 返回最小的
if (k == 1) return min(ary1[start1], ary2[start2]);
// 找第 k/2 小的元素所在的下标,如果数组个数比 k/2 还小,就找末尾元素
int i = start1 + min(len1, k / 2) - 1;
int j = start2 + min(len2, k / 2) - 1;
if (ary1[i] < ary2[j]) {
// 排除 ary1[start1]~ary1[i] 位置的所有元素,一共 excluded 个数,这些都不可能是第 k 小的
int excluded = i - start1 + 1;
// 继续在剩余的数组元素中找第 k - excluded 小的
return getKth(ary1, i + 1, end1, ary2, start2, end2, k - excluded);
} else {
// 排除 ary2[start2]~ary2[j] 位置的所有元素
int excluded = j - start2 + 1;
return getKth(ary1, start1, end1, ary2, j + 1, end2, k - excluded);
}
}
// 递增序列A和B,从A和B中找第k小的数字,A[1]~A[k/2],B[1]~B[k/2],一共才k个数,
// 在A[k/2] < B[k/2]的情况下,A[k/2]最多是第k-1小的,在找第k小的数字时就可以将A[1]~A[k/2]排除
double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
int m = nums1.size();
int n = nums2.size();
// 靠左的中位数是第 (m + n + 1) / 2 小的数
int left = (m + n + 1) / 2;
// 靠右的中位数是第 (m + n + 2) / 2 小的数
int right = (m + n + 2) / 2;
// 将偶数和奇数的情况合并,如果是奇数,会求两次同样的 k 。
return (getKth(nums1, 0, m - 1, nums2, 0, n - 1, left) + getKth(nums1, 0, m - 1, nums2, 0, n - 1, right)) * 0.5;
}
};
class Solution {
public:
// todo
double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
int m = nums1.size();
int n = nums2.size();
// 保证 m <= n
if (m > n) return findMedianSortedArrays(nums2, nums1);
int iMin = 0, iMax = m;
while (iMin <= iMax) {
int i = (iMin + iMax) / 2;
int j = (m + n + 1) / 2 - i;
if (j != 0 && i != m && nums2[j - 1] > nums1[i]) {
// i 需要增大
iMin = i + 1;
} else if (i != 0 && j != n && nums1[i - 1] > nums2[j]) {
// i 需要减小
iMax = i - 1;
} else {
// 达到要求,并且将边界条件列出来单独考虑
int maxLeft = 0;
if (i == 0)
maxLeft = nums2[j - 1];
else if (j == 0)
maxLeft = nums1[i - 1];
else
maxLeft = max(nums1[i - 1], nums2[j - 1]);
// 奇数的话不需要考虑右半部分
if ((m + n) % 2 == 1)
return maxLeft;
int minRight;
if (i == m)
minRight = nums2[j];
else if (j == n)
minRight = nums1[i];
else
minRight = min(nums2[j], nums1[i]);
// 如果是偶数的话返回结果
return (maxLeft + minRight) / 2.0;
}
}
return 0.0;
}
};