第一部分主要讨论:栈、队列、数组矩阵相关的面试题
题目一
用数组结构实现大小固定的队列和栈
public static class ArrayStack { private Integer[] arr; private Integer size; public ArrayStack(int initSize) { if (initSize < 0) { throw new IllegalArgumentException("The init size is less than 0"); } arr = new Integer[initSize]; size = 0; } public Integer peek() { if (size == 0) { return null; } return arr[size - 1]; } public void push(int obj) { if (size == arr.length) { throw new ArrayIndexOutOfBoundsException("The queue is full"); } arr[size++] = obj; } public Integer pop() { if (size == 0) { throw new ArrayIndexOutOfBoundsException("The queue is empty"); } return arr[--size]; } } public static class ArrayQueue { private Integer[] arr; private Integer size; private Integer first; private Integer last; public ArrayQueue(int initSize) { if (initSize < 0) { throw new IllegalArgumentException("The init size is less than 0"); } arr = new Integer[initSize]; size = 0; first = 0; last = 0; } public Integer peek() { if (size == 0) { return null; } return arr[first]; } public void push(int obj) { if (size == arr.length) { throw new ArrayIndexOutOfBoundsException("The queue is full"); } size++; arr[last] = obj; last = last == arr.length - 1 ? 0 : last + 1; } public Integer poll() { if (size == 0) { throw new ArrayIndexOutOfBoundsException("The queue is empty"); } size--; int tmp = first; first = first == arr.length - 1 ? 0 : first + 1; return arr[tmp]; } }
题目二
实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。
【要求】
1.pop、push、getMin操作的时间复杂度都是O(1)。
2.设计的栈类型可以使用现成的栈结构。
思路:利用两个栈来实现
public class Code_02_GetMinStack { public static class MyStack1 { private Stack<Integer> stackData; private Stack<Integer> stackMin; public MyStack1() { this.stackData = new Stack<Integer>(); this.stackMin = new Stack<Integer>(); } public 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; } public int getmin() { if (this.stackMin.isEmpty()) { throw new RuntimeException("Your stack is empty."); } return this.stackMin.peek(); } } public static class MyStack2 { private Stack<Integer> stackData; private Stack<Integer> stackMin; public MyStack2() { this.stackData = new Stack<Integer>(); this.stackMin = new Stack<Integer>(); } public void push(int newNum) { if (this.stackMin.isEmpty()) { this.stackMin.push(newNum); } else if (newNum < this.getmin()) { this.stackMin.push(newNum); } else { int newMin = this.stackMin.peek(); this.stackMin.push(newMin); } this.stackData.push(newNum); } public int pop() { if (this.stackData.isEmpty()) { throw new RuntimeException("Your stack is empty."); } this.stackMin.pop(); return this.stackData.pop(); } public int getmin() { if (this.stackMin.isEmpty()) { throw new RuntimeException("Your stack is empty."); } return this.stackMin.peek(); } } public static void main(String[] args) { MyStack1 stack1 = new MyStack1(); stack1.push(3); System.out.println(stack1.getmin()); stack1.push(4); System.out.println(stack1.getmin()); stack1.push(1); System.out.println(stack1.getmin()); System.out.println(stack1.pop()); System.out.println(stack1.getmin()); System.out.println("============="); MyStack1 stack2 = new MyStack1(); stack2.push(3); System.out.println(stack2.getmin()); stack2.push(4); System.out.println(stack2.getmin()); stack2.push(1); System.out.println(stack2.getmin()); System.out.println(stack2.pop()); System.out.println(stack2.getmin()); } }
题目三
如何仅用队列结构实现栈结构?
思路:两个队列复制到只剩下一个,留着最晚进入的然后给用户。
public static class TwoStacksQueue { private Stack<Integer> stackPush; private Stack<Integer> stackPop; public TwoStacksQueue() { stackPush = new Stack<Integer>(); stackPop = new Stack<Integer>(); } public void push(int pushInt) { stackPush.push(pushInt); } public int poll() { if (stackPop.empty() && stackPush.empty()) { throw new RuntimeException("Queue is empty!"); } 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(); } }
如何仅用栈结构实现队列结构?
思路:①push要一次倒完 ②如果pop有东西一定不要倒
public static class TwoQueuesStack { private Queue<Integer> queue; private Queue<Integer> help; public TwoQueuesStack() { queue = new LinkedList<Integer>(); help = new LinkedList<Integer>(); } public void push(int pushInt) { queue.add(pushInt); } public int peek() { if (queue.isEmpty()) { throw new RuntimeException("Stack is empty!"); } while (queue.size() != 1) { help.add(queue.poll()); } int res = queue.poll(); help.add(res); swap(); return res; } public int pop() { if (queue.isEmpty()) { throw new RuntimeException("Stack is empty!"); } while (queue.size() > 1) { help.add(queue.poll()); } int res = queue.poll(); swap(); return res; } private void swap() { Queue<Integer> tmp = help; help = queue; queue = tmp; } }
题目四
猫狗队列 【题目】 宠物、狗和猫的类如下:
public class Pet {
private String type; public Pet(String type) { this.type = type;
}
public String getPetType() { return this.type; } }
public class Dog extends Pet { public Dog() { super("dog"); } }
public class Cat extends Pet { public Cat() { super("cat"); } }
实现一种狗猫队列的结构,要求如下:
用户可以调用add方法将cat类或dog类的实例放入队列中;
用户可以调用pollAll方法,将队列中所有的实例按照进队列的先后顺序依次弹出;
用户可以调用pollDog方法,将队列中dog类的实例按照进队列的先后顺序依次弹出;
用户可以调用pollCat方法,将队列中cat类的实例按照进队列的先后顺序依次弹出;
用户可以调用isEmpty方法,检查队列中是否还有dog或cat的实例;
用户可以调用isDogEmpty方法,检查队列中是否有dog类的实例;
用户可以调用isCatEmpty方法,检查队列中是否有cat类的实例。
(思路很简单就加多一个时间戳count变量来区分,哪个先进入)
public class Code_04_DogCatQueue { public static class Pet { private String type; public Pet(String type) { this.type = type; } public String getPetType() { return this.type; } } public static class Dog extends Pet { public Dog() { super("dog"); } } public static class Cat extends Pet { public Cat() { super("cat"); } } public static class PetEnterQueue { private Pet pet; private long count; public PetEnterQueue(Pet pet, long count) { this.pet = pet; this.count = count; } public Pet getPet() { return this.pet; } public long getCount() { return this.count; } public String getEnterPetType() { return this.pet.getPetType(); } } public static class DogCatQueue { private Queue<PetEnterQueue> dogQ; private Queue<PetEnterQueue> catQ; private long count; public DogCatQueue() { this.dogQ = new LinkedList<PetEnterQueue>(); this.catQ = new LinkedList<PetEnterQueue>(); this.count = 0; } public void add(Pet pet) { if (pet.getPetType().equals("dog")) { this.dogQ.add(new PetEnterQueue(pet, this.count++)); } else if (pet.getPetType().equals("cat")) { this.catQ.add(new PetEnterQueue(pet, this.count++)); } else { throw new RuntimeException("err, not dog or cat"); } } public Pet pollAll() { if (!this.dogQ.isEmpty() && !this.catQ.isEmpty()) { if (this.dogQ.peek().getCount() < this.catQ.peek().getCount()) { return this.dogQ.poll().getPet(); } else { return this.catQ.poll().getPet(); } } else if (!this.dogQ.isEmpty()) { return this.dogQ.poll().getPet(); } else if (!this.catQ.isEmpty()) { return this.catQ.poll().getPet(); } else { throw new RuntimeException("err, queue is empty!"); } } public Dog pollDog() { if (!this.isDogQueueEmpty()) { return (Dog) this.dogQ.poll().getPet(); } else { throw new RuntimeException("Dog queue is empty!"); } } public Cat pollCat() { if (!this.isCatQueueEmpty()) { return (Cat) this.catQ.poll().getPet(); } else throw new RuntimeException("Cat queue is empty!"); } public boolean isEmpty() { return this.dogQ.isEmpty() && this.catQ.isEmpty(); } public boolean isDogQueueEmpty() { return this.dogQ.isEmpty(); } public boolean isCatQueueEmpty() { return this.catQ.isEmpty(); } } public static void main(String[] args) { DogCatQueue test = new DogCatQueue(); Pet dog1 = new Dog(); Pet cat1 = new Cat(); Pet dog2 = new Dog(); Pet cat2 = new Cat(); Pet dog3 = new Dog(); Pet cat3 = new Cat(); test.add(dog1); test.add(cat1); test.add(dog2); test.add(cat2); test.add(dog3); test.add(cat3); test.add(dog1); test.add(cat1); test.add(dog2); test.add(cat2); test.add(dog3); test.add(cat3); test.add(dog1); test.add(cat1); test.add(dog2); test.add(cat2); test.add(dog3); test.add(cat3); while (!test.isDogQueueEmpty()) { System.out.println(test.pollDog().getPetType()); } while (!test.isEmpty()) { System.out.println(test.pollAll().getPetType()); } } }
题目五
锻炼宏观思路解题
转圈打印矩阵
【题目】 给定一个整型矩阵matrix,请按照转圈的方式打印它。
打印结果为:1,2,3,4,8,12,16,15,14,13,9,5,6,7,11, 10
【要求】 额外空间复杂度为O(1)。
思路:
package class_03; public class Code_06_PrintMatrixSpiralOrder { public static void spiralOrderPrint(int[][] matrix) { //左上角 int tR = 0; int tC = 0; //右下角 int dR = matrix.length - 1;//行数 int dC = matrix[0].length - 1;//列数 while (tR <= dR && tC <= dC) { //左上角和右下角 printEdge(matrix, tR++, tC++, dR--, dC--); } } public static void printEdge(int[][] m, int tR, int tC, int dR, int dC) { if (tR == dR) {//行先相遇,打印目标是横的长方形 for (int i = tC; i <= dC; i++) { System.out.print(m[tR][i] + " "); } } else if (tC == dC) {//列先相遇,打印目标是竖的长方形 for (int i = tR; i <= dR; i++) { System.out.print(m[i][tC] + " "); } } else { int curC = tC; int curR = tR; //模拟转圈打印 while (curC != dC) { System.out.print(m[tR][curC] + " "); curC++; } while (curR != dR) { System.out.print(m[curR][dC] + " "); curR++; } while (curC != tC) { System.out.print(m[dR][curC] + " "); curC--; } while (curR != tR) { System.out.print(m[curR][tC] + " "); curR--; } } } public static void main(String[] args) { int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 16 } }; spiralOrderPrint(matrix); } }
题目六
旋转正方形矩阵
【题目】 给定一个整型正方形矩阵matrix,请把该矩阵调整成顺时针旋转90度的样子。
【要求】 额外空间复杂度为O(1)。
思路:
package class_03; public class Code_05_RotateMatrix { public static void rotate(int[][] matrix) { int tR = 0; int tC = 0; int dR = matrix.length - 1; int dC = matrix[0].length - 1; while (tR < dR) { rotateEdge(matrix, tR++, tC++, dR--, dC--); } } public static void rotateEdge(int[][] m, int ax, int ay, int bx, int by) { int times = by - ay; int tmp = 0; for (int i = 0; i != times; i++) { tmp = m[ax][ay + i]; m[ax][ay + i] = m[bx - i][ay]; m[bx - i][ay] = m[bx][by - i]; m[bx][by - i] = m[ax + i][by]; m[ax + i][by] = tmp; } } public static void printMatrix(int[][] matrix) { for (int i = 0; i != matrix.length; i++) { for (int j = 0; j != matrix[0].length; j++) { System.out.print(matrix[i][j] + " "); } System.out.println(); } } 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(matrix); rotate(matrix); System.out.println("========="); printMatrix(matrix); } }
题目七
反转单向和双向链表
【题目】 分别实现反转单向链表和反转双向链表的函数。
【要求】 如果链表长度为N,时间复杂度要求为O(N),额外空间复杂度要求为O(1)
package class_03; public class Code_07_ReverseList { public static class Node { public int value; public Node next; public Node(int data) { this.value = data; } } public static Node reverseList(Node head) { Node pre = null; Node next = null; while (head != null) { //把下一个节点先存起来 next = head.next; //翻转节点指向 head.next = pre; //把当前节点设置为下一个节点的前节点 pre = head; //为下一次循环,推进一步 head = next; } return pre; } public static class DoubleNode { public int value; public DoubleNode last; public DoubleNode next; public DoubleNode(int data) { this.value = data; } } public static DoubleNode reverseList(DoubleNode head) { DoubleNode pre = null; DoubleNode next = null; while (head != null) { next = head.next; head.next = pre; head.last = next; //把当前节点设置为下一个节点的前节点 pre = head; //为下一循环做准备,往下一个要操作的节点移动 head = next; } return pre; } public static void printLinkedList(Node head) { System.out.print("Linked List: "); while (head != null) { System.out.print(head.value + " "); head = head.next; } System.out.println(); } public static void printDoubleLinkedList(DoubleNode head) { System.out.print("Double Linked List: "); DoubleNode end = null; while (head != null) { System.out.print(head.value + " "); end = head; head = head.next; } System.out.print("| "); while (end != null) { System.out.print(end.value + " "); end = end.last; } System.out.println(); } public static void main(String[] args) { Node head1 = new Node(1); head1.next = new Node(2); head1.next.next = new Node(3); printLinkedList(head1); head1 = reverseList(head1); printLinkedList(head1); DoubleNode head2 = new DoubleNode(1); head2.next = new DoubleNode(2); head2.next.last = head2; head2.next.next = new DoubleNode(3); head2.next.next.last = head2.next; head2.next.next.next = new DoubleNode(4); head2.next.next.next.last = head2.next.next; printDoubleLinkedList(head2); printDoubleLinkedList(reverseList(head2)); } }
题目八
“之”字形打印矩阵
【题目】 给定一个矩阵matrix,按照“之”字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 “之”字形打印的结果为:1,2,5,9,6,3,4,7,10,11,8,12
【要求】 额外空间复杂度为O(1)。
思路:
package class_03; public class Code_08_ZigZagPrintMatrix { public static void printMatrixZigZag(int[][] matrix) { int ax = 0; int ay = 0; int bx = 0; int by = 0; int endX = matrix.length - 1; int endY = matrix[0].length - 1; boolean fromUp = false; while (ax != endX + 1) { printLevel(matrix, ax, ay, bx, by, fromUp); ax = ay == endY ? ax + 1 : ax; ay = ay == endY ? ay : ay + 1; by = bx == endX ? by + 1 : by; bx = bx == endX ? bx : bx + 1; fromUp = !fromUp; } System.out.println(); } public static void printLevel(int[][] m, int ax, int ay, int bx, int by, boolean f) { if (f) { while (ax != bx + 1) { System.out.print(m[ax++][ay--] + " "); } } else { while (bx != ax - 1) { System.out.print(m[bx--][by++] + " "); } } } public static void main(String[] args) { int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; printMatrixZigZag(matrix); } }
题目九
在行列都排好序的矩阵中找数
【题目】 给定一个有N*M的整型矩阵matrix和一个整数K,matrix的每一行和每一 列都是排好序的。实现一个函数,判断K是否在matrix中。
例如: 0 1 2 5 2 3 4 7 4 4 4 8 5 7 7 9
如果K为7,返回true;如果K为6,返回false。
【要求】 时间复杂度为O(N+M),额外空间复杂度为O(1)。
思路:
package class_03; public class Code_09_FindNumInSortedMatrix { public static boolean isContains(int[][] matrix, int K) { int row = 0; int col = matrix[0].length - 1; while (row < matrix.length && col > -1) { if (matrix[row][col] == K) { return true; } else if (matrix[row][col] > K) { col--; } else { row++; } } return false; } public static void main(String[] args) { int[][] matrix = new int[][] { { 0, 1, 2, 3, 4, 5, 6 },// 0 { 10, 12, 13, 15, 16, 17, 18 },// 1 { 23, 24, 25, 26, 27, 28, 29 },// 2 { 44, 45, 46, 47, 48, 49, 50 },// 3 { 65, 66, 67, 68, 69, 70, 71 },// 4 { 96, 97, 98, 99, 100, 111, 122 },// 5 { 166, 176, 186, 187, 190, 195, 200 },// 6 { 233, 243, 321, 341, 356, 370, 380 } // 7 }; int K = 233; System.out.println(isContains(matrix, K)); } }