题目列表
面试题21:调整数组顺序使奇数位于偶数前面
public class Demo21 {
public static void main(String[] args) {
int[] arr = { 3, -3, 4, 7, 4, 2, 9, 0, -1 };
adjustOrder(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
public static void adjustOrder(int[] arr) {
int pre = 0; // 偶数指针,从前向后找
int after = arr.length - 1; // 奇数指针,从后向前找
while (pre < after) { // pre >= after 证明已经有序
// 前面的even指针移动到偶数
if (isOdd(arr[pre])) {
pre++;
}
// 后面的指针移动到奇数上
if (!isOdd(arr[after])) {
after--;
}
// 上面两个if同时失效,满足交换条件,做一次交换,指针分别向中间靠拢一步
if (!isOdd(arr[pre]) && isOdd(arr[after])) {
int temp = arr[pre];
arr[pre] = arr[after];
arr[after] = temp;
pre++;
after--;
}
}
}
private static boolean isOdd(int num) {
return (num & 1) == 1;
}
}
面试题22:链表中倒数第k个节点
public class Demo22 {
public static void main(String[] args){
// 测试链表
ListNode head = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
ListNode node4 = new ListNode(4);
ListNode node5 = new ListNode(5);
ListNode node6 = new ListNode(6);
ListNode node7 = new ListNode(7);
ListNode node8 = new ListNode(8);
head.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node6;
node6.next = node7;
node7.next = node8;
int[] ks = {8,7,6,5,4,3,2,1,0,9};
// 打印原链表
System.out.print("测试链表:");
ListNode p = head;
while (p != null) {
System.out.print(p.val + " ");
p = p.next;
}
// 测试
System.out.println();
for(int i = 0; i < ks.length; i++){
ListNode node = lastNodeK(head, ks[i]);
if(node != null)
System.out.println("倒数第" + ks[i] + "个结点为:" + node.val);
}
}
// 单指针法:该方法用一个指针走两遍
public static ListNode lastNodeK(ListNode head, int k){
// 判空
if(head == null){ return head; }
ListNode p = head;
// 先遍历一遍确定链表长度
int len = 0;
while(p !=null){
len++;
p = p.next;
}
// 判断 k是否合理
if(k > len || k <= 0){
System.out.println( "k = " + k +", 而链表长度为" + len + ", 所以k的合理取值为 1~" + len);
return null;
}
// 找到第k个节点
p = head;
int steps = len - k;
while(steps -- > 0){
p = p.next;
}
return p;
}
// 前后指针法,效率比前一种要高一点
public static ListNode lastNodeK1(ListNode head, int k){
if(head == null || k == 0) {
return null;
}
ListNode pAhead = head;
ListNode pBehind = null;
// 前指针先走 k-1步
for(int i = 0; i < k - 1; i++){
if(pAhead.next != null){
pAhead = pAhead.next;
}else{
System.out.println("k = " + k + ", 不在合理范围");
return null;
}
}
// 一起走,直到前指针走到尾巴
pBehind = head;
while(pAhead.next != null){
pAhead = pAhead.next;
pBehind = pBehind.next;
}
return pBehind;
}
}
测试输出:
测试链表:1 2 3 4 5 6 7 8
倒数第8个结点为:1
倒数第7个结点为:2
倒数第6个结点为:3
倒数第5个结点为:4
倒数第4个结点为:5
倒数第3个结点为:6
倒数第2个结点为:7
倒数第1个结点为:8
k = 0, 而链表长度为8, 所以k的合理取值为 1~8
k = 9, 而链表长度为8, 所以k的合理取值为 1~8
面试题23:链表中环的入口
public class Demo23 {
public static void main(String[] args) {
// 测试链表
ListNode head = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
ListNode node4 = new ListNode(4);
ListNode node5 = new ListNode(5);
ListNode node6 = new ListNode(6);
ListNode node7 = new ListNode(7);
ListNode node8 = new ListNode(8);
head.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node6;
node6.next = node7;
node7.next = node8;
node8.next = node3; // node3是入口
ListNode in = meetingNode(head);
if(in != null)
System.out.println(in.val);
else
System.out.println("没有环");
}
/**
* 快慢指针法:
* 设起始点到环入口为:x,环长为c,入口到相遇点为a,相遇点到入口为b
* slow = x + mc + a
* fast = x + nc + a
* slow*2 = fast
* 推出:x = (n-2m)c - a = (n - 2m - 1)c + b
* 所以x长度为环的整数倍,加上相遇点到入口的距离,这时只需要一个
* 指针从起始点走,一个指针从相遇点走最后肯定会在入口相遇
*/
public static ListNode meetingNode(ListNode head) {
if(head == null){ return null;}
ListNode fast = head;
ListNode slow = head;
while(fast != null){
slow = slow.next;
fast = fast.next;
if(fast != null){ // 当前不为空才能在走一步,不然可能报空指针异常
fast = fast.next;
}
if(fast == slow){ break; }
}
if(fast == null) return null;
slow = head;
while(slow != fast){
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
面试题24:反转链表
public class Demo24 {
public static void main(String[] args) {
// 测试链表
ListNode head = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
ListNode node4 = new ListNode(4);
ListNode node5 = new ListNode(5);
ListNode node6 = new ListNode(6);
ListNode node7 = new ListNode(7);
ListNode node8 = new ListNode(8);
head.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node6;
node6.next = node7;
node7.next = node8;
System.out.print("反转之前:");
ListNode p = head;
while (p != null) {
System.out.print(p.val + " ");
p = p.next;
}
System.out.print("\n反转之后:");
p = reverseList(head);
while (p != null) {
System.out.print(p.val + " ");
p = p.next;
}
}
private static ListNode reverseList(ListNode head) {
// 空和一个结点不需反转,直接返回
if(head == null || head.next == null) return head;
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode p = head;
ListNode temp = null;
// 反转
while(p.next != null){
temp = p.next;
p.next = temp.next;
temp.next = dummyHead.next;
dummyHead.next = temp;
temp = p;
}
return dummyHead.next;
}
}
测试输出:
反转之前:1 2 3 4 5 6 7 8
反转之后:8 7 6 5 4 3 2 1
面试题25:合并两个排序的链表
public class Demo25 {
public static void main(String[] args) {
ListNode L1 = getList1(); // 1 3 5 7
ListNode L2 = getList2(); // 2 4 6 8
// 测试
ListNode p = mergeList(L1,L2);
while (p != null) {
System.out.print(p.val + " ");
p = p.next;
}
}
private static ListNode mergeList(ListNode l1, ListNode l2) {
// 如果一个为空就直接把另一个返回,剩下就是两个都不为空
if(l1 == null) return l2;
if(l2 == null) return l1;
ListNode dummy = new ListNode(-1);
ListNode p = dummy;
// 合并两个链表,直到有一个遍历完
while(l1 != null && l2 != null){
if(l1.val < l2.val){
p.next = l1;
l1 = l1.next;
}else{
p.next = l2;
l2 = l2.next;
}
p = p.next;
}
// 如果l1遍历完了,就把l2剩下的接在后面
// 如果l1没有遍历完则,把l1剩下的接在后面
p.next = (l1 == null)? l2:l1;
return dummy.next;
}
private static ListNode getList1() {
// 测试链表
ListNode head = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(5);
ListNode node4 = new ListNode(7);
head.next = node2;
node2.next = node3;
node3.next = node4;
return head;
}
private static ListNode getList2() {
// 测试链表
ListNode head = new ListNode(2);
ListNode node2 = new ListNode(4);
ListNode node3 = new ListNode(6);
ListNode node4 = new ListNode(8);
head.next = node2;
node2.next = node3;
node3.next = node4;
return head;
}
}
测试输出:
1 2 3 4 5 6 7 8
面试题26:树的子结构
/*
class BiTreeNode {
int val;
BiTreeNode left;
BiTreeNode right;
BiTreeNode(int x){
val = x;
}
}
*/
public class Demo26 {
public static void main(String[] args){
BiTreeNode mainTree = getMainTree();
BiTreeNode subTree = getSubTree();
boolean has = hasSubTree(mainTree, subTree);
System.out.println(has);
}
// 遍历主树
private static boolean hasSubTree(BiTreeNode root1, BiTreeNode root2) {
boolean result = false;
if (root1 != null && root2 != null) {
if (root1.val == root2.val) // 如果根节点相等
result = isSubTree(root1, root2);
if (!result)
result = hasSubTree(root1.left, root2);
if (!result)
result = hasSubTree(root1.right, root2);
}
return result;
}
private static boolean isSubTree(BiTreeNode root1, BiTreeNode root2) {
if(root2 == null) return true;
if(root1 == null) return false;
if(root1.val != root2.val) return false;
return isSubTree(root1.left, root2.left) && isSubTree(root1.right, root2.right);
}
public static BiTreeNode getMainTree() {
BiTreeNode A = new BiTreeNode(8);
BiTreeNode A2 = new BiTreeNode(8);
BiTreeNode A3 = new BiTreeNode(7);
BiTreeNode A4 = new BiTreeNode(9);
BiTreeNode A5 = new BiTreeNode(2);
BiTreeNode A6 = new BiTreeNode(4);
BiTreeNode A7 = new BiTreeNode(7);
A.left = A2;
A.right = A3;
A2.left = A4;
A2.right = A5;
A5.left = A6;
A5.right = A7;
return A;
}
public static BiTreeNode getSubTree() {
BiTreeNode A2 = new BiTreeNode(8);
BiTreeNode A4 = new BiTreeNode(9);
BiTreeNode A5 = new BiTreeNode(2);
A2.left = A4;
A2.right = A5;
return A2;
}
}
面试题27:二叉树的镜像
public class Demo27 {
public static void main(String[] args){
/* 要镜像翻转的二叉树
* 8
* 6 10
* 5 7 9 11
*/
BiTreeNode root = createBiTree();
// 层次遍历
System.out.println("原二叉树:");
traverse(root);
System.out.println("\n镜像对称后:");
mirror(root);
traverse(root);
}
private static void mirror(BiTreeNode root) {
if(root == null) return;
if(root.left == null && root.right == null) return;
BiTreeNode temp = root.left;
root.left = root.right;
root.right = temp;
if(root.left != null)
mirror(root.left);
if(root.right != null)
mirror(root.right);
}
// 层次遍历
private static void traverse(BiTreeNode root){
if(root == null) return;
Queue<BiTreeNode> queue = new LinkedList<BiTreeNode>();
queue.offer(root);
while(!queue.isEmpty()){
BiTreeNode node = queue.poll();
System.out.print(node.val + " ");
if(node.left != null){
queue.offer(node.left);
}
if(node.right != null){
queue.offer(node.right);
}
}
}
// 构造一颗树
private static BiTreeNode createBiTree() {
BiTreeNode root = new BiTreeNode(8);
BiTreeNode node2 = new BiTreeNode(6);
BiTreeNode node3 = new BiTreeNode(10);
BiTreeNode node4 = new BiTreeNode(5);
BiTreeNode node5 = new BiTreeNode(7);
BiTreeNode node6 = new BiTreeNode(9);
BiTreeNode node7 = new BiTreeNode(11);
root.left = node2;
root.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;
node3.right = node7;
return root;
}
}
测试输出:
原二叉树:
8 6 10 5 7 9 11
镜像对称后:
8 10 6 11 9 7 5
面试题28:对称的二叉树
public class Demo28 {
public static void main(String[] args){
/* 准备一颗对称二叉树
* 8
* 6 6
* 5 7 7 5
*/
BiTreeNode root = createBiTree();
boolean bool = isSymetrical(root);
System.out.println(bool);
}
public static boolean isSymetrical(BiTreeNode root) {
return isSymetrical(root, root);
}
private static boolean isSymetrical(BiTreeNode left, BiTreeNode right) {
// 都为空
if(left == null && right == null) return true;
// 有一个为空
if(left == null || right == null) return false;
// 都不为空
if(left.val != right.val) return false;
return isSymetrical(left.left, right.right) && isSymetrical(left.right, right.left);
}
// 层次遍历
private static void traverse(BiTreeNode root){
if(root == null) return;
Queue<BiTreeNode> queue = new LinkedList<BiTreeNode>();
queue.offer(root);
while(!queue.isEmpty()){
BiTreeNode node = queue.poll();
System.out.print(node.val + " ");
if(node.left != null){
queue.offer(node.left);
}
if(node.right != null){
queue.offer(node.right);
}
}
}
// 构造一颗树
private static BiTreeNode createBiTree() {
BiTreeNode root = new BiTreeNode(8);
BiTreeNode node2 = new BiTreeNode(6);
BiTreeNode node3 = new BiTreeNode(6);
BiTreeNode node4 = new BiTreeNode(5);
BiTreeNode node5 = new BiTreeNode(7);
BiTreeNode node6 = new BiTreeNode(7);
BiTreeNode node7 = new BiTreeNode(5);
root.left = node2;
root.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;
node3.right = node7;
return root;
}
}
测试输出:true
面试题29:顺时针打印矩阵
public class Demo29 {
public static void main(String[] args){
// int[][] mat1 = {{}};
int[][] matrix = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 },
{ 13, 14, 15, 16 } };
ArrayList<Integer> list = printMatrix(matrix);
for(Integer i : list){
System.out.print(i + " ");
}
}
// 方法1
public static ArrayList<Integer> printMatrix(int[][] matrix) {
ArrayList<Integer> list = new ArrayList<Integer>();
if(matrix == null) return list; // 这里只检查了输入为空的情况,输入不是矩阵的情况没检查
int row = matrix.length;
int col = matrix[0].length;
if (row == 0 || col == 0) // 如果是空的就返回
return list;
int left = 0, right = col - 1, up = 0, down = row - 1;
while (left <= right && up <= down) {
for (int i = left; i <= right; i++) {
list.add(matrix[up][i]);
}
for (int i = up + 1; i <= down; i++) {
list.add(matrix[i][right]);
}
if (up != down)
for (int i = right - 1; i >= left; i--) {
list.add(matrix[down][i]);
}
if (left != right)
for (int i = down - 1; i > up; i--) {
list.add(matrix[i][left]);
}
left++;
up++;
right--;
down--;
}
return list;
}
// 方法2
public static ArrayList<Integer> printMatrix2(int[][] matrix) {
ArrayList<Integer> list = new ArrayList<Integer>();
if(matrix == null) return list; // 这里只检查了输入为空的情况,输入不是矩阵的情况没检查
int rows = matrix.length;
int cols = matrix[0].length;
if (rows == 0 || cols == 0) // 如果是空的就返回
return list;
int left = 0, right = cols - 1, up = 0, down = rows - 1;
int totalSteps = rows*cols; // 一共要走的步数
int x, y;
for(x = 0, y = 0; totalSteps > 0; totalSteps--){
list.add(matrix[x][y]);
// 向右走
if(x == up){
if(y < right) y++;
else if(y == right) x++;
continue;
}
// 向下走
if(y == right){
if(x < down) x++;
else if(x == down) y--;
continue;
}
// 向左走
if(x == down){
if(y > left) y--;
else if(y == left) x--;
continue;
}
// 向上走
if(y == left){
if(x > up + 1) x--;
else if(x == up + 1){y++; left++; up++; right--; down--;}
continue;
}
}
return list;
}
}
测试输出:
1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10
面试题30:包含min函数的栈
public class MinInStack {
private Stack<Integer> dataStack;
private Stack<Integer> minStack;
public MinInStack(){
this.dataStack = new Stack<Integer>();
this.minStack = new Stack<Integer>();
}
public boolean isEmpty(){
return dataStack.isEmpty();
}
public Integer peek(){
return dataStack.peek();
}
public void push(Integer item){
dataStack.push(item);
if(minStack.isEmpty() || item < minStack.peek()){
minStack.push(item);
}else{
minStack.push(minStack.peek());
}
}
public Integer pop(){
Integer i = null;
if(!dataStack.isEmpty() && !minStack.isEmpty()){
i = dataStack.pop();
minStack.pop();
}
return i;
}
public Integer min(){
if(!dataStack.isEmpty() && !minStack.isEmpty()){
return minStack.peek();
}
return null;
}
// 测试
public static void main(String[] args){
MinInStack minStack = new MinInStack();
minStack.push(3);
minStack.push(4);
minStack.push(2);
minStack.push(1);
System.out.print("min = " + minStack.min() + " peek = " + minStack.pop() + "\n");
System.out.print("min = " + minStack.min() + " peek = " + minStack.pop() + "\n");
System.out.print("min = " + minStack.min() + " peek = " + minStack.pop() + "\n");
System.out.print("min = " + minStack.min() + " peek = " + minStack.pop() + "\n");
System.out.print("min = " + minStack.min() + " peek = " + minStack.pop() + "\n");
System.out.print("min = " + minStack.min() + " peek = " + minStack.pop() + "\n");
}
}
测试输出:
min = 1 peek = 1
min = 2 peek = 2
min = 3 peek = 4
min = 3 peek = 3
min = null peek = null
min = null peek = null