2020/8/16
JZ19 顺时针打印矩阵
题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
思路:我们可以把打印一圈分为四步:第一步从左到右打印一行,第二步从上到下打印一列,第三步从右到左打印一行,第四步从下到上打印一列。每一步我们根据起始坐标和终止坐标用一个循环就能打印出一行或者一列。不过值得注意的是最后一圈有可能退化成只有一行、只有一列,甚至只有一个数字,因此打印这样的一圈就不再需要四步。因此 我们要分析打印时每一步的前提条件。第一步总是需要的,因为打印一圈至少有一步。如果只有一行,那么就不用第二步了。也即是需要第二步的前提条件是终止行号大于起始行号。需要第三步打印的前提条件是圈内至少有两行两列,也就是说除了要求终止行号大于起始行号之外,还要求终止列号大于起始列号。同理,需要打印第四步的前提条件是至少有三行两列,因此要求终止行号比起始行号至少大2,同时终止列号大于起始列号。
【代码】
package com.cc.jianzhi;
/*
顺时针打印矩阵
*/
import java.util.ArrayList;
public class PrintMatrix {
public static void main(String[] args) {
int [][] matrix={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
PrintMatrix pm=new PrintMatrix();
System.out.println(pm.printMatrix(matrix));
}
public ArrayList<Integer> printMatrix(int[][] matrix) {
ArrayList<Integer> reList = new ArrayList<>();
if (matrix == null) {
return reList;
}
int tR = 0;
int tC = 0;
int dR = matrix.length - 1;
int dC = matrix[0].length - 1;
while (tR <= dR && tC <= dC) {
printMatrix(matrix, tR++, tC++, dR--, dC--, reList);
}
return reList;
}
public void printMatrix(int[][] matrix, int tR, int tC, int dR, int dC, ArrayList<Integer> reList) {
// 只有一行
if (tR == dR) {
for (int i = tC; i <= dC; i++) {
reList.add(matrix[tR][i]);
}
}
// 只有一列
else if (tC == dC) {
for (int i = tR; i <= dR; i++) {
reList.add(matrix[i][tC]);
}
} else {
int curR = tR;
int curC = tC;
// 从左到右
while (curC != dC) {
reList.add(matrix[tR][curC]);
curC++;
}
// 从上到下
while (curR != dR) {
reList.add(matrix[curR][dC]);
curR++;
}
// 从右到左
while (curC != tC) {
reList.add(matrix[dR][curC]);
curC--;
}
// 从下到上
while (curR != tR) {
reList.add(matrix[curR][tC]);
curR--;
}
}
}
}
JZ20 包含min函数的栈
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
思路:定义两个栈stack,压栈时,先将元素node压入stack1,然后判断stack2的情况:stack2为空或者栈顶元素大于node,则将node压入stack2中;stack2栈不为空且栈顶元素小于node,则重复压入栈顶元素。获取最小元素时,从stack2中获取栈顶元素即可。
package com.cc.jianzhi;
import java.util.Stack;
public class MinInStack {
public static void main(String[] args) {
MinInStack m=new MinInStack();
m.push(1);
m.push(3);
m.push(9);
m.push(6);
System.out.println(m.min());
}
private Stack<Integer> stack1 = new Stack<>();
private Stack<Integer> stack2 = new Stack<>();
/**
* 压栈
* @param node 待压入的元素
*/
public void push(int node) {
stack1.push(node);
if (stack2.isEmpty() || stack2.peek() >= node) {
stack2.push(node);
} else {
stack2.push(stack2.peek());
}
}
public void pop() {
stack1.pop();
stack2.pop();
}
public int top() {
return stack2.peek();
}
/**
* O(1)获取栈中最小值
* @return 最小值
*/
public int min() {
return stack2.peek();
}
}
JZ21栈的压入、弹出序列
题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
思路:判断下一个要弹出的元素:
如果刚好是栈顶元素,直接弹出。
如果不在栈顶,则把压栈序列中还没有入栈的数字压入栈,直接待弹出的数字压入栈顶。
如果所有数字都压入栈顶后依然没有后找到下一个弹出的数字,则不可能是弹出序列。
【代码】
package com.cc.jianzhi;
import java.util.Stack;
public class IsPopOrder {
public static void main(String[] args) {
int[] pushA={1,2,3,4,5};
int[] popA={4,5,3,2,1};
IsPopOrder p=new IsPopOrder();
System.out.println(p.IsPopOrder(pushA,popA));
}
/**
* 判断是否是弹出序列
* @param pushA 压栈序列
* @param popA 弹栈序列
* @return 是否是弹出序列
*/
public boolean IsPopOrder(int[] pushA,int[] popA) {
if (pushA == null || popA == null || pushA.length != popA.length) {
return false;
}
Stack<Integer> stack = new Stack<>();
int i = 0;
int n = pushA.length;
boolean flag = false;
for (int val : popA) {
while (stack.isEmpty() || stack.peek() != val) {
if (i >= n) {
flag = true;
break;
}
stack.push(pushA[i++]);
}
if (flag) {
break;
}
stack.pop();
}
return stack.isEmpty();
}
}