一、用数组结构实现大小固定的队列和栈
1、数组实现栈
package FaceQuestion;
/**
* 使用固定长度的数组实现一个栈结构
*/
public class ArrayStack {
Integer[] arr;
Integer index;
public ArrayStack(int arraySize){
if (arraySize<0){
throw new IllegalArgumentException("数组初始化错误");
}
arr=new Integer[arraySize];
index=0;
}
/**
* 返回栈顶元素但不弹出
* @return
*/
public Integer peek(){
if (index==0){
return null;
}
return arr[index-1];
}
/**
* 弹出栈顶元素
* @return
*/
public Integer pop(){
if (index==0){
throw new ArrayIndexOutOfBoundsException("栈越界!!!");
}
return arr[--index];
}
/**
* 压栈
* @param obj
*/
public void push(int obj){
if (index==arr.length){
throw new ArrayIndexOutOfBoundsException("栈越界!!!");
}
arr[index++]=obj;
}
}
2.数组实现队列
package FaceQuestion;
/**
* 定长数组实现栈
* 设置标志位,start和end
* 从end中插入,start处弹出
* 同时使用size判断数组越界问题,size记录的是数组中元素个数
* 每插入一个元素,size++,元素放在end处,并使用nextIndex判断end位置,如果到数组边界,那么就置为0
* 每弹出一个元素,size--,弹出start处元素,并使用nextIndex判断start位置,如果到数组边界,那么置为0;
*/
public class ArrayQueue {
private Integer[] arr;
private Integer size;
private Integer start;
private Integer end;
/**
* 初始化定长数组
* @param initSize
*/
public ArrayQueue(int initSize){
if (initSize<0){
throw new IllegalArgumentException("数组初始化失败");
}
arr=new Integer[initSize];
size=0;
start=0;
end=0;
}
public Integer peek(){
if (size==0){
return null;
}
return arr[start];
}
public void push(int obj){
if (size==arr.length){
throw new ArrayIndexOutOfBoundsException("越界");
}
size++;
arr[end]=obj;
end=nextIndex(arr.length,end);
}
public Integer poll(){
if (size==0){
throw new ArrayIndexOutOfBoundsException("越界");
}
size--;
int tmp=start;
start=nextIndex(arr.length,start);
return arr[tmp];
}
/**
* 获取start和end的移动的下一个位置,如果到了边界,那么就置为0
* @param length
* @param index
* @return
*/
private Integer nextIndex(int length, Integer index) {
return index==length-1?0:index+1;
}
}
二、实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作
package FaceQuestion;
import java.util.Stack;
/**
* 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。
* 思路:使用两个栈来实现,一个正常存储元素,一个只存储小元素(每次入栈都比较一下,比栈顶元素小就压入)
*/
public class GetMinStack {
private Stack<Integer> stackData;
private Stack<Integer> stackMin;
private GetMinStack(){
this.stackData=new Stack<>();
this.stackMin=new Stack<>();
}
private void push(int newNum){
if (this.stackMin.isEmpty()){
this.stackMin.push(newNum);
}else if (newNum<=this.getMin()){
this.stackMin.push(newNum);
}
this.stackData.push(newNum);
}
public int pop() {
if (this.stackData.isEmpty()) {
throw new RuntimeException("Your stack is empty.");
}
int value = this.stackData.pop();
if (value == this.getMin()) {
this.stackMin.pop();
}
return value;
}
private int getMin() {
if (this.stackMin.isEmpty()){
throw new RuntimeException("栈溢出");
}
return this.stackMin.peek();
}
}
三、使用队列实现一个栈
package FaceQuestion;
import java.util.LinkedList;
import java.util.Queue;
/**
* 使用队列完成栈结构
* 使用两个队列不断的倒进倒出来实现
* 创建两个队列1,2
* 入队时正常入其中一个队,弹出时,将队尾元素保留,前面元素压入到另一个队列中
*/
public class TwoQueueStack {
private Queue<Integer> queue;
private Queue<Integer> help;
public TwoQueueStack(){
queue=new LinkedList<>();
help=new LinkedList<>();
}
public void push(int pushInt){
queue.add(pushInt);
}
public int peek(){
if (queue.isEmpty()){
throw new RuntimeException("栈为空");
}
while (queue.size()!=1){
help.add(queue.poll());
}
int res=queue.poll();
help.add(res);
swap();
return res ;
}
public int poll(){
if (queue.isEmpty()){
throw new RuntimeException("栈为空");
}
while (queue.size()>1){
help.add(queue.poll());
}
int res=queue.poll();
swap();
return res;
}
//交换一下help和queue的引用
private void swap(){
Queue<Integer> tmp=queue;
queue=help;
help=tmp;
}
}
四、使用栈实现一个队列
package FaceQuestion;
import java.util.Stack;
/**
* 使用两个栈实现一个队列
* 创建好两个栈,一个用于压入给定的元素,当需要弹出元素时,
* 需要压入栈的元素全部压入到
* 弹出栈中,由弹出栈弹出元素
*/
public class TwoStackQueue {
private Stack<Integer> stackPush;//专门用于压入元素的栈
private Stack<Integer> stackPop;//专门用于弹出的栈
public TwoStackQueue(){
stackPop=new Stack<>();
stackPush=new Stack<>();
}
public void push(Integer newValue){
stackPush.push(newValue);
}
public Integer Poll(){
if (stackPush.empty()&&stackPop.empty()){
throw new RuntimeException("栈为空");
}else if (stackPop.empty()){
while (!stackPush.empty()){
stackPop.push(stackPush.pop());
}
}
return stackPop.pop();
}
public int peek() {
if (stackPop.empty() && stackPush.empty()) {
throw new RuntimeException("Queue is empty!");
} else if (stackPop.empty()) {
while (!stackPush.empty()) {
stackPop.push(stackPush.pop());
}
}
return stackPop.peek();
}
}
五、设计RandomPool结构
设计一种结构,在该结构中有如下三个功能:
insert(key):将某个key加入到该结构,做到不重复加入。
delete(key):将原本在结构中的某个key移除。
getRandom():等概率随机返回结构中的任何一个key。
package FaceQuestion;
import java.util.HashMap;
/**
* 设计RandomPool结构
* 设计一种结构,在该结构中有如下三个功能:
* insert(key):将某个key加入到该结构,做到不重复加入。
* delete(key):将原本在结构中的某个key移除。
* getRandom():等概率随机返回结构中的任何一个key。
*
*
* 思路:
* 使用两个hashmap,HashMap<T,Integer> keyIndexMap和HashMap<Integer,T> indexKeyMap
*/
public class RandomPool<K> {
private HashMap<K, Integer> keyIndexMap;
private HashMap<Integer, K> indexKeyMap;
private int size;
public RandomPool() {
this.keyIndexMap = new HashMap<>();
this.indexKeyMap = new HashMap<>();
//标记hashmap中存储的所有记录个数,同时保证HashMap中Integer为连续的正整数,我们就可以通过这个size来等概率返回元素
this.size = 0;
}
public void insert(K key){
if (!this.keyIndexMap.containsKey(key)){//保证不重复添加
this.keyIndexMap.put(key,this.size);
this.indexKeyMap.put(this.size++,key);
}
}
/**
* 删除时,将最后一条记录和要删除的记录交换,然后删除最后一条记录,可以保证下标连续不间断,从而保证等概率返回
* @param key
*/
public void delete(K key){
if (this.keyIndexMap.containsKey(key)){
int deleteIndex=this.keyIndexMap.get(key);//获取要删除元素的下标
int lastIndex=--this.size;
K lastKey=this.indexKeyMap.get(lastIndex);//获取最后一个元素
this.keyIndexMap.put(lastKey,deleteIndex);//把最后一个元素的下标赋值到最后一个元素的下标
this.indexKeyMap.put(deleteIndex,lastKey);//把最后一个元素赋值到要删除元素
this.keyIndexMap.remove(key);//删除key
this.indexKeyMap.remove(lastIndex);//删除最后一条记录
}
}
/**
*
* 等概率返回一个key
* @return
*/
public K getRandom() {
if (this.size == 0) {
return null;
}
int randomIndex = (int) (Math.random() * this.size);
return this.indexKeyMap.get(randomIndex);
}
}
六、转圈打印矩阵
思路:宏观观察,选择左上角和右下角两个点为观察点,每次打印一圈,然后两个点不断向中间逼近;
package FaceQuestion;
/**
* 打印矩阵问题
* 转圈,之字形打印
*
*/
public class PrintMatrixSpiralOrder {
public void spiralOrderPrint(int[][] matrix){
int tRow=0;//左上角x坐标
int tCol=0;//左上角y坐标
int dRow=matrix.length-1;//右下角x坐标
int dCol=matrix[0].length-1;//右下角y坐标
while (tRow<=dRow&&tCol<=dCol){//当还没有到达中点时,不断转圈打印
printEdge(matrix,tRow++,tCol++,dRow--,dCol--);
}
}
private void printEdge(int[][] matrix, int tRow, int tCol, int dRow, int dCol) {
if (tRow==dRow){//到了右边界
for (int i=tCol;i<=dCol;i++){
System.out.println(matrix[tRow][i]+" ");
}
}else if (tCol==dCol){//到了下边界
for (int i=tRow;i<=dRow;i++){
System.out.println(matrix[i][tCol]+" ");
}
}else {
int curC = tCol;
int curR = tRow;
while (curC != dCol) {
System.out.print(matrix[tRow][curC] + " ");
curC++;
}
while (curR != dRow) {
System.out.print(matrix[curR][dCol] + " ");
curR++;
}
while (curC != tCol) {
System.out.print(matrix[dRow][curC] + " ");
curC--;
}
while (curR != tRow) {
System.out.print(matrix[curR][tCol] + " ");
curR--;
}
}
}
}
七、“之”字形打印矩阵之类的问题
package FaceQuestion;
/**
* 之字形打印矩阵
* 设置三个观察点,t点,r点,end点
* t点起始点在(0,0)不断向右移动,移动到边界之后,再向下移动
* r点起始点在(0,0)不断向下移动,移动到边界之后,再向右移动
* end点一直在右下角
*/
public class ZigPrintMatrix {
public static void printMatrixZigZag(int[][] matrix) {
int tR = 0;//不断向右移动点的y坐标
int tC = 0;//不断向右移动点的x坐标
int dR = 0;//不断向下移动点的y坐标
int dC = 0;//不断向下移动点的x坐标
int endR = matrix.length - 1;
int endC = matrix[0].length - 1;
boolean fromUp = false;//判断移动的方向
while (tR != endR + 1) {//打印结束条件,t点向下移动到越界
printLevel(matrix, tR, tC, dR, dC, fromUp);//根据方向打印对角线的方法
//通过不断改变t点和r点的坐标,使得t点和r点处在对角线两端
tR = tC == endC ? tR + 1 : tR;//t点的y坐标起初为0,到达右边界之后,不断+1
tC = tC == endC ? tC : tC + 1;//t点x坐标起初不断+1,到达右边界之后,不变
dC = dR == endR ? dC + 1 : dC;//r点x坐标起初微微0,到达下边界后,不断+1
dR = dR == endR ? dR : dR + 1;//r点y坐标起初不断+1,到达下边界后,不变
fromUp = !fromUp;//一条对角线打印完之后,直接改变方向
}
System.out.println();
}
/**
* 打印t点和r点之间的点的方法
* @param m
* @param tR
* @param tC
* @param dR
* @param dC
* @param f
*/
public static void printLevel(int[][] m, int tR, int tC, int dR, int dC,
boolean f) {
if (f) {
while (tR != dR + 1) {
System.out.print(m[tR++][tC--] + " ");
}
} else {
while (dR != tR - 1) {
System.out.print(m[dR--][dC++] + " ");
}
}
}
public static void main(String[] args) {
int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
printMatrixZigZag(matrix);
}
}
八、在行列都排好序的矩阵中找数
思路:选取右上角或左下角的点为起始点,右上角的点存在这样的特点:当前列下方的点都比它大,当前行左边的数都比他小,
利用这个特点,每次比较就可以排除一行或一列的点,其时间复杂度最大为O(m+n);
package FaceQuestion;
/**
* 在已排好序的矩阵中判断一个数是否存在
*/
public class FindNumInSortMatrix {
public boolean isContains(int[][] matrix,int num){
int row = 0;
int col = matrix[0].length - 1;
while (row < matrix.length && col > -1) {
if (matrix[row][col] == num) {
return true;
} else if (matrix[row][col] > num) {
col--;
} else {
row++;
}
}
return false;
}
}