实现栈排序
要求: 一个栈中元素为整型,实现一个方法将该栈从顶到底按照从大到小的顺序排列
只能申请一个栈和有限的变量
import java.util.Stack;
public class SortStackByStack {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>();
stack.push(4);
stack.push(1);
stack.push(8);
stack.push(7);
stack.push(5);
stack.push(9);
stack.push(2);
stack.push(6);
sort(stack);
while(!stack.empty()) {
System.out.println(stack.pop());
}
}
public static void sort(Stack<Integer> stack) {
if(stack.empty()) {
return;
}
Stack<Integer> tempStack = new Stack<Integer>();
while(!stack.empty()) {
int temp = stack.pop();
while(!tempStack.empty() && tempStack.peek() < temp) {
stack.push(tempStack.pop());
}
tempStack.push(temp);
}
while(!tempStack.empty()) {
stack.push(tempStack.pop());
}
}
}
生成窗口最大值数组
要求:
给出一个整形数组,例如arr = {5,4,3,5,6,7,6},窗口大小为w=3,窗口每次向右移动一位,输出每个窗口中最大值组成的数组。
例如:
* [5,4,3,]5,6,7,6 窗口最大值为5
* 5,[4,3,5,]6,7,6 窗口最大值为5
* 5,4,[3,5,6,]7,6 窗口最大值为6
* 5,4,3,[5,6,7,]6 窗口最大值为7
* 5,4,3,5,[6,7,6] 窗口最大值为7
*
* 则输出的数组为{5,5,6,7,7};
*
* 思路:本题如果依次遍历然后比较,只能做出时间复杂度为O(W*N)的解法
* 可以利用双端队列,做出时间复杂度为O(N)的解法,关键在于当遍历的数大于队列里的数时,
* 可以将队列里的数依次弹出(此时里面的小数已经无用),做出一个从大到小排列的队列,
* 再判断队头最大值是否在窗口中即可。
* 所有的遍历数据最多进队列一次,出队列一次,比较次数最多也只是N的常数倍,可以做到时间复杂度为O(n)
public class WindowMaxArr {
public static void main(String[] args) {
int[] arr = {5,4,3,5,6,7,6};
int[] result = getWindowMaxArr(arr, 3);
System.out.println(Arrays.toString(result));
}
public static int[] getWindowMaxArr(int[] arr,int w) {
if(arr == null || arr.length < w || w < 1) {
return null;
}
int[] result = new int[arr.length + 1 - w];
int index = 0;
LinkedList<Integer> queue = new LinkedList<Integer>();
for(int i = 0;i < arr.length;i++) {
/* 自写劣质版
if(queue.isEmpty()) {
}else if(arr[queue.getLast()] > arr[i]){
}else if(arr[queue.getLast()] <= arr[i]) {
while(!queue.isEmpty() && arr[queue.getLast()] <= arr[i] ) {
queue.pollLast();
}
}
queue.add(i);
if(i >= w - 1) {
while(queue.getFirst() < i + 1 - w ) {
queue.pollFirst();
}
result[index++] = arr[queue.getFirst()];
}
*/
//简洁正宗版
while(!queue.isEmpty() && arr[queue.getLast()] <= arr[i]) {
queue.pollLast();
}
queue.add(i);
if(queue.getFirst() == i - w) {
queue.pollFirst();
}
if(i >= w - 1) {
result[index++] = arr[queue.getFirst()];
}
}
return result;
}
}
单调栈结构
要求:给定一个不含有重复值的数组arr, 找到每一个i位置左边和右边离i位置最近且值比arr[i]小的值索引 返回所有位置信息。
* 例如:arr={3,4,1,5,6,2,7}
* 返回值为:
* {{-1,2},{0,2},{-1,-1},{2,5},{3,5},{2,-1},{5,-1}}
* 进阶问题:数组arr可能存在重复值
*
public class NearLess {
public static void main(String[] args) {
int[] arr = { 3,4,1,5,6,2,7};
int[][] result = rightWay01(arr);
int[][] result2 = rightWay02(arr);
int[][] result3 = rightWay03(arr);
for (int[] is : result) {
System.out.print(Arrays.toString(is) + " ");
}
System.out.println();
for (int[] is : result2) {
System.out.print(Arrays.toString(is) + " ");
}
System.out.println();
for (int[] is : result3) {
System.out.print(Arrays.toString(is) + " ");
}
}
// 1.时间复杂度为O(n²)
public static int[][] rightWay01(int[] arr){
int[][] result = new int[arr.length][2];
for(int i = 0;i < arr.length;i++) {
int j = i - 1;
int k = i + 1;
//向前遍历
for(;j >= 0;j--) {
if(arr[j] < arr[i]) {
break;
}
}
result[i][0] = j;
//向后遍历
for(;k < arr.length;k++) {
if(arr[k] < arr[i]) {
break;
}
}
if(k == arr.length) {
result[i][1] = -1;
}else {
result[i][1] = k;
}
}
return result;
}
//2.不含重复值,时间复杂度为O(n)
//思路:遍历数组内元素,利用栈存储,并将栈设计成单调形式
//若求元素左右小于该元素的值索引,则从栈底到栈顶为递增;
//若求元素左右大于该元素的值索引,则从栈底到栈顶为递减。
//在此题中,遍历时若该元素入栈时不构成单调递增,
//则弹出栈中数据,直至元素压入栈后为单调;
//压入栈的元素左边最近小值则为此时的栈顶,
//弹出栈的元素右边最近小值则为此时遍历的元素索引。
public static int[][] rightWay02(int[] arr){
if(arr == null || arr.length == 0) {
return null;
}
int[][] result = new int[arr.length][2];
Stack<Integer> stack = new Stack<>();
for(int i = 0;i < arr.length;i++) {
while(!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
result[stack.pop()][1] = i;
}
if(stack.isEmpty()) {
result[i][0] = -1;
}else {
result[i][0] = stack.peek();
}
stack.push(i);
}
while(!stack.isEmpty()) {
result[stack.pop()][1] = -1;
}
return result;
}
//3.进阶问题:数组arr可能存在重复值,时间复杂度为O(n)
public static int[][] rightWay03(int[] arr){
if(arr == null || arr.length == 0) {
return null;
}
int[][] result = new int[arr.length][2];
Stack<Integer> stack = new Stack<>();
for(int i = 0;i < arr.length;i++) {
while(!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
result[stack.pop()][1] = i;
}
//有重复值时,需多加一个判断
if(stack.isEmpty()) {
result[i][0] = -1;
}else if(arr[i] == arr[stack.peek()]){
result[i][0] = result[stack.peek()][0];
}else {
result[i][0] = stack.peek();
}
stack.push(i);
}
while(!stack.isEmpty()) {
result[stack.pop()][1] = -1;
}
return result;
}
}
求最大子矩阵的大小
给定一个整型矩阵map,其中的值只有0和1两种,求其中全是1的所有矩形区域中,最大的矩形区域为1的数量。
例如:
1,1,1,0
其中最大的矩形区域有3个1,所以返回3。
再如:
1,0,1,1
1,1,1,1
1,1,1,0
其中,最大的矩形区域有6个1,所以返回6。
public class MaxRecSize {
public static void main(String[] args) {
int[] arr = {3,4,5,4,3,6};
int maxAreaByHeight = getMaxAreaByHeight(arr);
System.out.println(maxAreaByHeight);
int[][] arr2 = {{1,0,1,1},{1,1,1,1},{1,1,1,0}};
int maxRecSize = maxRecSize(arr2);
System.out.println(maxRecSize);
}
/*
* 给定一个整型矩阵map,其中的值只有0和1两种,求其中全是1的所有矩形区域中,最大的矩形区域为1的数量。
* 例如:
* 1,1,1,0
* 其中最大的矩形区域有3个1,所以返回3。
* 再如:
* 1,0,1,1
* 1,1,1,1
* 1,1,1,0
* 其中,最大的矩形区域有6个1,所以返回6。
*
* 思路:矩阵的行数为N,以每一行切割,然后统计以当前行作为底的情况下,
* 每个位置往上的连续1的数量。
* 那么可以将1的数量转化成最大矩形的面积,每一行切割,
* 如何依次遍历比较更新最大值。
* 考察每一个矩阵向左右扩展后形成的最大矩阵,可以使用单调栈,
* 转化成求当前i位置左右最近小值的索引,此时的索引相减即为矩形的底,
* i索引的值即为高。
*/
public static int maxRecSize(int[][] arr) {
int[] height = new int[arr[0].length];
int max = 0;
for(int i = 0;i < arr.length;i++) {
for(int j = 0;j < arr[0].length;j++) {
if(i == 0) {
height[j] = arr[i][j];
}else {
height[j] = arr[i][j] == 0 ? 0 : height[j] + 1;
}
}
max = Math.max(max, getMaxAreaByHeight(height));
}
return max;
}
public static int getMaxAreaByHeight(int[] height) {
if(height == null || height.length == 0) {
return 0;
}
int[][] range = new int[height.length][2];
Stack<Integer> stack = new Stack<Integer>();
int max = 0;
for(int i = 0;i < height.length;i++) {
while(!stack.isEmpty() && height[i] < height[stack.peek()]) {
range[stack.pop()][1] = i;
}
if(!stack.isEmpty() && height[stack.peek()] == height[i]) {
range[i][0] = range[stack.peek()][0];
}else if(stack.isEmpty()){
range[i][0] = -1;
}else {
range[i][0] = stack.peek();
}
stack.push(i);
}
while(!stack.isEmpty()) {
range[stack.pop()][1] = height.length;
}
for(int i = 0;i < height.length;i++) {
max = Math.max(max, height[i]*(range[i][1]-range[i][0] - 1));
}
return max;
}
}