问题1
给定一个无序矩阵,其中只有1和0两种值, 求只含有1 的最大的子矩阵大小, 矩阵的大小用其中的元素个数来表示
解题思路:
-
矩阵压缩, 计算出以每一行为底的直方图
举例说明: 矩阵为
0 1 1 0 1
1 1 0 1 1
以第一行为底的直方图为: 0 1 1 0 1
以第二行为底的直方图为: 1 2 0 1 2 (当前底的数值为0,则直方图值为0) -
针对1中的直方图, 进行入栈操作(入栈的为height 的index),举例:当前直方图表示为 height[6]=[3,5,4]
step1: 当前栈为空, 0 入栈 ()step2: 当前栈顶元素为height[0] =3, 小于5, 1入栈
step3: 当前栈顶元素为height[1]=5, 大于4,
a.结算当前栈顶index对应的元素:
currentIndex=1 的rightIndex=2, leftIndex=1, 总长度为 (rightIndex - leftIndex-1); 矩阵大小为:
(rightIndex - leftIndex-1) * height[currentIndex] = 5,
b. 当前栈顶元素出栈step4: 2 入栈
step5: height 的index都已入栈,此时需要结算栈中的每一个元素并出栈。
/****
* 题目3:给定一个无序矩阵,其中只有1和0两种值, 求只含有1 的最大的子矩阵大小, 矩阵的大小用其中的元素个数来表示
* <p>
* 1. 矩阵压缩, 计算出以每一行为底的直方图:
* 举例: 矩阵为 0 1 1 0 1
* 1 1 0 1 1
* 以第一行为底的直方图为: 0 1 1 0 1
* 以第二行为底的直方图为: 1 2 0 1 2 (当前底的数值为0,则直方图值为0)
* 2. 对1中生成的直方图,采用入栈,出栈的方法来计算最大的矩阵大小。
* 3.
*/
public static int getMaxLengthOfMatrix(int[][] map) {
if (null == map || map.length == 0 || map[0].length == 0) {
return 0;
}
int maxLength = 0;
int[] height = new int[map[0].length];
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
height[j] = map[i][j] == 0 ? 0 : height[j] + 1;
}
//计算好了以第i 行为底的直方图,开始对直方图入栈, 出栈。
int currentLength = getMaxRecFromBottom(height);
maxLength = Math.max(currentLength, maxLength);
}
return maxLength;
}
public static int getMaxRecFromBottom(int[] height) {
if (height == null || height.length == 0) {
return 0;
}
int maxLength = 0;
Stack<Integer> stack = new Stack<Integer>();
for (int index = 0; index < height.length; index++) {
while (!stack.isEmpty() && height[index] <= stack.peek()) {
int currentIndex = stack.pop();
int leftIndex = stack.isEmpty() ? -1 : stack.peek();
int rightIndex = index;
int currentLength = (rightIndex - leftIndex - 1) * height[currentIndex];
maxLength = Math.max(maxLength, currentLength);
}
stack.push(index);
}
//在执行完height 后 栈里面如果还有元素也需要一个个pop出来计算高度
while(!stack.isEmpty()){
int currentIndex = stack.pop();
int leftIndex = stack.isEmpty() ? -1 : stack.peek();
int rightIndex = height.length; // 注意此时 的rightIndex = height.length
int curretArea = (rightIndex - leftIndex - 1) * height[currentIndex];
maxLength = Math.max(maxLength, curretArea);
}
return maxLength;
}
问题2: O(log N * log N) 的时间复杂度, 计算完全二叉树中的节点个数
public static int nodeNums(Node head) {
if (head == null) {
return 0;
}
return bs(head, 1, mostLeftLevel(head, 1));
}
/***
* @param node
* @param l 表示当前遍历的层数;
* 1.先计算出二叉树的高度h, 记录传入的遍历的当前层数l
* 2. 然后计算右节点的左子树的高度,看是否等于h,不等
* 2.1 如果等于h, 则表示左节点的是一颗满二叉树,可以计算高度,h-l,
* 当前节点数为 1 << (h-l) - 1, 再加上一个节点,为 1 << (h-l) -1 +1.
* 2.2 如果不等于h, 则右子树的层数是 h-l -1 , 且是满二叉树, 可以计算节点数 1 << (h - l - 1), 递归 左子树
*
* @param h
* @return
*/
public static int bs(Node node, int l, int h) {
if (l == h) {
return 1;
}
if (mostLeftLevel(node.rightNode, l + 1) == h) {
return (1 << (h - l)) + bs(node.rightNode, l + 1, h);
} else {
return (1 << (h - l - 1)) + bs(node.leftNode, l + 1, h);
}
}
//获取树的深度
public static int mostLeftLevel(Node headNode, int level) {
while (headNode != null) {
level++;
headNode = headNode.leftNode;
}
return level - 1;
}