Java程序员面试需要注意啥?面试常见手撕模板题以及笔试模板总结

本文汇总了Java程序员面试中常见的手撕模板题和笔试题,包括Java快速输入、排序算法、二分查找、二叉树非递归遍历、01背包问题、最长递增子序列等经典题目,旨在帮助面试者准备面试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文转载自:Java程序员面试需要注意啥?面试常见手撕模板题以及笔试模板总结


一. 目录

  1. 排序
  2. 二分
  3. 二叉树非递归遍历
  4. 01背包
  5. 最长递增子序列
  6. 最长公共子序列
  7. 最长公共子串
  8. 大数加法
  9. 大数乘法
  10. 大数阶乘
  11. 全排列
  12. 子集
  13. N皇后
  14. 并查集
  15. 树状数组
  16. 线段树
  17. 字典树
  18. 单调栈
  19. 单调队列
  20. KMP
  21. Manacher算法
  22. 拓扑排序
  23. 最小生成树
  24. 最短路
  25. 欧拉回路
  26. GCD和LCM
  27. 素数筛法
  28. 唯一分解定理
  29. 乘法快速幂
  30. 矩阵快速幂

二. 面试常见手撕模板题以及笔试模板总结

0. Java快速输入

先给一个干货,可能有些题用Java会超时(很少),下面是Petr刷题时的模板,一般用了这个就不会出现C++能过Java不能过的情况了。

import java.io.*;
import java.util.*;
public class Main {
	static class FR {
		BufferedReader br;
		StringTokenizer tk;
		FR(InputStream stream) {
			br = new BufferedReader(new InputStreamReader(stream), 32768);
			tk = null;
		}
		String next() {
			while (tk == null || !tk.hasMoreElements()) {
				try {
					tk = new StringTokenizer(br.readLine());
				}
				catch (IOException e) {
					e.printStackTrace();
				}
			}
			return tk.nextToken();
		}
		int nextint() {
			return Integer.parseint(next());
		}
	}
	static void solve(InputStream stream, PrintWriter out) {
		FR in = new FR(stream);
		//  start code.....
	}
	public static void main(String[] args) {
		OutputStream os = System.out;
		InputStream is = System.in;
		PrintWriter out = new PrintWriter(os);
		solve(is, out);
		out.close();
		// 不关闭就没有输出
	}
}

1. 排序

先给出一个swap函数,代表交换数组两个位置的值,很多排序用到这个函数:

static void swap(int[] arr, int a, int b){
	int t = arr[a];
	arr[a] = arr[b];
	arr[b] = t;
}

面试主要考察比较排序(O(N^2)、O(NlogN))排序(非比较排序可以看下面的详细总结)。

①. 冒泡

static void bubbleSort(int[] arr){
	for (int end = arr.length - 1; end > 0; end--){
		Boolean isSort = true;
		for (int i = 0; i < end; i++){
			if(arr[i] > arr[i+1]) {
				swap(arr, i, i + 1);
				isSort = false;
			}
		}
		if(isSort) break;
	}
}

②. 选择

static void selectSort(int[] arr){
	for (int i = 0; i < arr.length; i++){
		int minIdx = i;
		for (int j = i + 1; j < arr.length; j++) minIdx = arr[j] < arr[minIdx] ? j : minIdx;
		swap(arr, minIdx, i);
	}
}

③. 插入

// 几个边界: i=1开始(不是必须)、j >= 0, arr[j+1] = key注意一下
static void insertSort(int[] arr) {
	for (int i = 1; i < arr.length; i++) {
		int key = arr[i], j;
		for (j = i - 1; j >= 0 && arr[j] > key; j--) arr[j + 1] = arr[j];
		arr[j + 1] = key;
	}
}

第二种写法:

// 边界 j > 0
static void insertSort2(int[] arr) {
    for (int i = 1; i < arr.length; i++) {
        for (int j = i; j > 0 && arr[j - 1] > arr[j]; j--) swap(arr, j, j - 1);
    }
}

二分插入排序:

// 注意 R = i-1,注意找第一个>=key的,注意arr[i]先用key保存
static void binaryInsertSort(int[] arr) {
    for (int i = 1; i < arr.length; i++) {
        int L = 0, R = i - 1;
        // 找第一个大于的 二分边界搞不清的看下面的二分链接
        int key = arr[i];
        while (L <= R) {
            int m = L + (R - L) / 2;
            if (arr[m] > arr[i]) {
                R = m - 1;
            } else {
                L = m + 1;
            }
        }
        for (int j = i - 1; j >= L; j--) arr[j + 1] = arr[j];
        arr[L] = key;
    }
}

④. 希尔排序

采取的是增量序列每次减半的策略。

static void shellSort(int[] arr) {
    for (int g = arr.length; g > 0; g /= 2) { // 增量序列 gap
        for (int end = g; end < arr.length; end++) { // 每一个组的结束元素, 从数组第gap个元素开始
            // 每组做插入排序
            int key = arr[end], i;
            for (i = end - g; i >= 0 && key < arr[i]; i -= g) arr[i + g] = arr[i];
            arr[i + g] = key;
        }
    }
}

⑤. 快排

给出的是三路快排

static void quickSort(int[] arr){
    if(arr == null || arr.length == 0) return;
    quickRec(arr, 0, arr.length - 1);
}

static void quickRec(int[] arr, int L, int R) {
    if (L >= R) return;
    swap(arr, L, L + (int) (Math.random() * (R - L + 1)));
    int[] p = partition(arr, L, R);
    quickRec(arr, L, p[0] - 1);
    quickRec(arr, p[1] + 1, R);
}

// 用arr[L]作为划分点
static int[] partition(int[] arr, int L, int R) {
    int key = arr[L];
    int less = L, more = R + 1;
    int cur = L + 1;
    while (cur < more) {
        if (arr[cur] < key) {
            swap(arr, ++less, cur++);
        } else if (arr[cur] > key) {
            swap(arr, --more, cur);
        } else {
            cur++;
        }
    }
    swap(arr, L, less);
    // 返回相等的两个下标, less位置是我最后交换过来的划分值,more位置是>的,所以返回more-1
    return new int[]{less, more - 1};
}

⑥. 归并排序

static void mergeSort(int[] arr){
    if(arr == null || arr.length == 0) return;
    mergeRec(arr, 0, arr.length - 1);
}

//注意是mergeSort(arr, L, m); 不是mergeSort(arr, L, m-1)
static void mergeRec(int[] arr, int L, int R) {
    if (L >= R) return;
    int m = L + (R - L) / 2;
    mergeRec(arr, L, m);
    mergeRec(arr, m + 1, R);
    merge(arr, L, m, R);
}

static void merge(int[] arr, int L, int mid, int R) {
    int[] h = new int[R - L + 1];
    int p1 = L, p2 = mid + 1;
    int k = 0;
    while (p1 <= mid && p2 <= R)
        h[k++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];  // 注意保证稳定性
    while (p1 <= mid) h[k++] = arr[p1++];
    while (p2 <= R) h[k++] = arr[p2++];
    for (int i = 0; i < k; i++) arr[L + i] = h[i];
}

非递归归并排序:

static void mergeSortBU(int[] arr) {
    for (int sz
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值