226翻转二叉树
翻转二叉树是一个经典的问题,目标是将二叉树的左右子树互换。可以通过递归或迭代两种方法来实现。
1. 递归解法
递归翻转二叉树的思路是从根节点开始,将每个节点的左右子节点互换。然后对左右子节点进行相同的操作,直到遍历完整棵树。
Java 代码实现(递归法)
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) {
this.val = val;
}
}
public class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return null;
}
// 递归翻转左右子树
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);
// 交换左右子树
root.left = right;
root.right = left;
return root;
}
// 示例用法
public static void main(String[] args) {
// 构建一个示例二叉树
TreeNode root = new TreeNode(4);
root.left = new TreeNode(2);
root.right = new TreeNode(7);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(3);
root.right.left = new TreeNode(6);
root.right.right = new TreeNode(9);
Solution solution = new Solution();
TreeNode invertedRoot = solution.invertTree(root);
// 输出翻转后的二叉树结构
System.out.println(invertedRoot.val); // 应输出 4
System.out.println(invertedRoot.left.val); // 应输出 7
System.out.println(invertedRoot.right.val); // 应输出 2
}
}
2. 迭代解法(使用队列)
可以使用广度优先遍历,借助队列来实现迭代翻转。具体步骤是从根节点开始,依次将左右子节点交换,并将非空的子节点加入队列,继续处理直到队列为空。
Java 代码实现(迭代法)
import java.util.LinkedList;
import java.util.Queue;
public class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return null;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode current = queue.poll();
// 交换当前节点的左右子节点
TreeNode temp = current.left;
current.left = current.right;
current.right = temp;
// 将非空子节点加入队列
if (current.left != null) {
queue.offer(current.left);
}
if (current.right != null) {
queue.offer(current.right);
}
}
return root;
}
}
复杂度分析
- 时间复杂度:
O(N),其中N是二叉树的节点数。每个节点都会被访问一次。 - 空间复杂度:
O(N),递归调用栈或迭代时的队列最多存储N个节点。
221.最大正方形
我们定义一个二维数组 dp,其中 dp[i][j] 表示以位置 (i, j) 为右下角的最大正方形的边长。我们用动态规划来填充这个数组。
状态转移方程
如果当前位置的矩阵值为 1,则 dp[i][j] 可以通过其左方、上方和左上方的 dp 值推导出来:
plaintext
复制代码
dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
dp[i-1][j]表示当前元素上方的最大正方形边长。dp[i][j-1]表示当前元素左方的最大正方形边长。dp[i-1][j-1]表示当前元素左上方的最大正方形边长。
如果 matrix[i][j] 为 0,则 dp[i][j] = 0。
初始化
- 边界情况下,第一行和第一列的位置只需要考虑是否为
1,所以dp[i][j]会直接等于matrix[i][j](0或1)。
示例
假设矩阵如下:
plaintext
复制代码
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
计算 dp 值的过程如下:
- 遍历每个元素。
- 根据状态转移方程填充
dp,并更新最大边长。
class Solution {
public int maximalSquare(char[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return 0;
}
int rows = matrix.length;
int cols = matrix[0].length;
int[][] dp = new int[rows][cols];
int maxSide = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (matrix[i][j] == '1') {
if (i == 0 || j == 0) {
dp[i][j] = 1;
} else {
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
}
maxSide = Math.max(maxSide, dp[i][j]);
}
}
}
return maxSide * maxSide; // 返回最大正方形的面积
}
}
215.数组中的第K个最大元素
当然,除了快速选择算法之外,还有其他几种方法可以找到数组中第 k 个最大的元素。以下是一些常见的替代方案:
1. 使用堆(Heap)
可以使用一个最小堆来维护当前 k 个最大的元素。堆的大小固定为 k,当遍历整个数组时,如果当前元素大于堆顶元素,就将堆顶元素替换为当前元素。最终,堆顶元素就是第 k 个最大的元素。
时间复杂度:O(n log k)
以下是实现的代码示例:
import java.util.PriorityQueue;
public class KthLargestElement {
public static int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> minHeap = new PriorityQueue<>(k);
for (int num : nums) {
minHeap.offer(num);
if (minHeap.size() > k) {
minHeap.poll();
}
}
return minHeap.peek();
}
public static void main(String[] args) {
int[] nums = {3, 2, 1, 5, 6, 4};
int k = 2;
System.out.println("第 " + k + " 个最大的元素是: " + findKthLargest(nums, k));
}
}
2. 排序
另一种简单的方法是将数组排序,然后直接访问第 k 个元素。这种方法的时间复杂度为 O(n log n),因为排序的复杂度通常是 O(n log n)。
以下是实现的代码示例:
import java.util.Arrays;
public class KthLargestElement {
public static int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length - k]; // 返回第 k 个最大的元素
}
public static void main(String[] args) {
int[] nums = {3, 2, 1, 5, 6, 4};
int k = 2;
System.out.println("第 " + k + " 个最大的元素是: " + findKthLargest(nums, k));
}
}
3. 计数排序
如果数组中的元素范围有限(例如,都是非负整数),可以使用计数排序的方法。这种方法的时间复杂度为 O(n + m),其中 m 是元素的范围。
选择最佳方法
- 快速选择:适合大多数情况下,特别是当需要 O(n) 的时间复杂度。
- 最小堆:适合在 k 较小的情况下,且能维持动态的流数据。
- 排序:适合对数组进行完整的排序时。
- 计数排序:适合元素范围有限且是整数时。
选择哪种方法取决于具体的场景和输入数据特性。
3万+

被折叠的 条评论
为什么被折叠?



