java 经典面试题 包含各大厂真题

经典java 面试题详解

  1. 请谈谈Java中的多态性是什么?

答:多态性是指一个对象可以被不同的角度来看待,也可以有多种形态。Java中有两种形态:静态多态和动态多态。静态多态是指方法的重载,而动态多态则是指方法的覆盖。

  1. Java中什么是反射?

答:反射是指在运行时动态地获取类的信息并对类进行操作的一种机制。通过反射可以在运行时获取类的名称、属性、方法等信息,并对其进行访问和修改。

  1. 请谈谈Java中的异常是什么?

答:Java中的异常是指程序在运行中出现的错误,包括运行时异常和检查时异常。运行时异常通常是由于程序逻辑错误导致的,而检查时异常则是由于外部因素导致的,比如输入输出问题。

  1. 请谈谈Java中的HashMap是如何工作的?

答:HashMap是一种基于哈希表实现的映射表,用于存储键-值对。在HashMap中,每个键都必须是唯一的,而值可以不唯一。HashMap通过将键的哈希值映射到内部数组的索引来查找对应的值。

  1. 请谈谈Java中的线程是什么?

答:Java中的线程是指程序执行的最小单位,可以同时运行多个线程以实现并发操作。线程包含了一个执行上下文(堆栈、计数器等)以及消耗的资源(内存、CPU时间等)。

  1. 请谈谈Java中的集合是什么?

答:Java中的集合是指一组元素的容器,可以用来存储、操作和访问数据。Java中的集合分为List、Set、Queue和Map四类,分别用来存储有序的元素列表、无序的元素集合、先进先出的元素队列和键-值对映射表。

  1. 请谈谈Java中的静态变量和静态方法是什么?

答:Java中的静态变量和静态方法是指属于类而不是属于对象的变量和方法。静态变量和静态方法可以通过类名直接访问,无需创建对象。静态变量的值对所有对象都是一样的,而静态方法只能访问静态变量和调用静态方法。

  1. 请谈谈Java中的注解是什么?

答:Java中的注解是一种元数据,用于向编译器或运行时环境提供说明性信息。Java中的注解可以修饰类、方法、字段等元素,注解本身是通过Java代码编写的,可以在编译时保留或者运行时保留。

  1. 请谈谈Java中的字符串是如何工作的?

答:Java中的字符串是一种不可变的对象,每次对字符串的修改都会创建一个新的字符串对象。Java中的字符串使用Unicode编码表示,每个字符占用两个字节。

  1. 请谈谈Java中的设计模式是什么?

答:Java中的设计模式是一种通用的解决方案,用于解决各种问题。设计模式把一些常用的解决方案抽象成类、接口和对象,并通过组合和继承等方式实现不同的功能。Java中的常用设计模式有单例模式、工厂模式、装饰器模式、观察者模式等。

经典机试真题:
题目描述:

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
要求算法的时间复杂度为 O(log(m+n))。

示例1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例二:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

解题思路:

对于两个长度分别为m和n的有序数组,可以将其视为列,通过列的方式求中位数。

假设将两个有序数组A,B合并到一起,将这两个数组分别在i,j处分成两部分:A[0:i-1],A[i,m-1]和B[0:j-1],B[j,n-1],其中i+j=m-i+n-j(或者j=m-i+n-j),如果这个划分恰好满足如下条件:

  1. A[i-1]≤B[j] && B[j-1]≤A[i]

  2. 将两个集合合并在一起后的长度为偶数时:(max(A[i-1],B[j-1])+min(A[i],B[j]))/2

  3. 将两个集合合并在一起后的长度为奇数时:max(A[i-1],B[j-1])

那么这个数就是中位数。

为了满足这些条件,可以对于这两个有序数组进行二分查找,找到恰当的i和j,使得上述条件满足。

程序解释如下:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;

    // 确保 nums1 的长度小于等于 nums2 的长度
    if (m > n) {
        int[] temp = nums1;
        nums1 = nums2;
        nums2 = temp;
        int tmp = m;
        m = n;
        n = tmp;
    }

    int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
    while (iMin <= iMax) {
        int i = (iMin + iMax) / 2;
        int j = halfLen - i;
        if (i < iMax && nums2[j - 1] > nums1[i]) {
            iMin = i + 1; // i 太小,增大它
        } else if (i > iMin && nums1[i - 1] > nums2[j]) {
            iMax = i - 1; // i 太大,减小它
        } else {
            int maxLeft = 0;
            if (i == 0) { maxLeft = nums2[j - 1]; }
            else if (j == 0) { maxLeft = nums1[i - 1]; }
            else { maxLeft = Math.max(nums1[i - 1], nums2[j - 1]); }
            if ((m + n) % 2 == 1) { return maxLeft; }

            int minRight = 0;
            if (i == m) { minRight = nums2[j]; }
            else if (j == n) { minRight = nums1[i]; }
            else { minRight = Math.min(nums2[j], nums1[i]); }

            return (maxLeft + minRight) / 2.0;
        }
    }
    return 0.0;
}

}

这是一个求两个有序数组的中位数的解法,时间复杂度为O(log (m+n))。

  1. 最短回文串

题目描述:

给定一个字符串 s, 你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。

示例1:

输入: s = “aacecaaa”
输出: “aaacecaaa”

示例2:

输入: s = “abcd”
输出: “dcbabcd”

题解:

首先需要找到s的最长回文前缀,然后将s的所有未匹配的字符反转,并拼接在s前即可。

比如对于字符串s = “aacecaaa"来说,最长回文前缀就是"aa”,反转后未匹配的字符就是"cec",将其反转并拼接在字符串前面,得到的最短回文串就是"aaacecaaa"。

Java代码实现:

class Solution {
public String shortestPalindrome(String s) {
int j = 0;
for (int i = s.length() - 1; i >= 0; i–) {
if (s.charAt(i) == s.charAt(j)) {
j += 1;
}
}
if (j == s.length()) {
return s;
}
String suffix = s.substring(j);
String prefix = new StringBuilder(suffix).reverse().toString();
String mid = shortestPalindrome(s.substring(0, j));
return prefix + mid + suffix;
}
}

时间复杂度:O(n^2)

  1. 最大子序和

题目描述:

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例2:

输入:nums = [1]
输出:1

示例3:

输入:nums = [0]
输出:0

题解:

我们可以定义状态f[i]表示以第i个元素结尾的最大子序和,那么有:

  • f[0] = nums[0]
  • f[i] = max(f[i-1] + nums[i], nums[i])

用一个变量maxSum来记录f数组中的最大值即可。

Java代码实现:

class Solution {
public int maxSubArray(int[] nums) {
int maxSum = nums[0];
int[] f = new int[nums.length];
f[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
f[i] = Math.max(f[i-1] + nums[i], nums[i]);
maxSum = Math.max(maxSum, f[i]);
}
return maxSum;
}
}

时间复杂度:O(n)

  1. 重建二叉树

题目描述:

根据一棵树的前序遍历和中序遍历构造二叉树。

示例:

输入:

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]

输出:

3

/
9 20
/
15 7

题解:

前序遍历的第一个元素是根节点,根据根节点在中序遍历中的位置可以将中序遍历分成左右两部分。左边是根节点的左子树,右边是根节点的右子树。这样就可以递归的构建左子树和右子树。

Java代码实现:

class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = preorder.length;
Map<Integer, Integer> indexMap = new HashMap<>();
for (int i = 0; i < n; ++i) {
indexMap.put(inorder[i], i);
}
return build(preorder, inorder, 0, n - 1, 0, n - 1, indexMap);
}

private TreeNode build(int[] preorder, int[] inorder, int preStart, int preEnd, int inStart, int inEnd, Map<Integer, Integer> indexMap) {
    if (preStart > preEnd) {
        return null;
    }

    int rootVal = preorder[preStart];
    TreeNode root = new TreeNode(rootVal);

    int rootIndex = indexMap.get(rootVal);
    int leftSize = rootIndex - inStart;

    root.left = build(preorder, inorder, preStart + 1, preStart + leftSize, inStart, rootIndex - 1, indexMap);
    root.right = build(preorder, inorder, preStart + leftSize + 1, preEnd, rootIndex + 1, inEnd, indexMap);
    return root;
}

}

时间复杂度:O(n)

  1. 正则表达式匹配

题目描述:

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

输入: s = “aa” p = “a*”
输出: true
解释: ‘*’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。

输入: s = “mississippi” p = “misisp*.”
输出: false

题解:

本题需要用到动态规划来进行求解。

假设dp[i][j]表示字符串s的前i个字符和p的前j个字符是否匹配。

当p[j-1]!='*'时,dp[i][j] = dp[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] == ‘.’)

当p[j-1]=='*'时,分为以下两种情况:

  • '*'匹配0个前元素,即忽略p的前j-2个字符,dp[i][j] = dp[i][j-2]
  • '*'匹配1个或多个前元素,即s的第i个字符匹配p的前j-2个字符,且s的前i-1个字符和p的前j个字符也匹配,dp[i][j] = dp[i-1][j] && (s[i-1] == p[j-2] || p[j-2] == ‘.’)

Java代码实现:

class Solution {
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[m + 1][n + 1];
dp[0][0] = true;
for (int i = 0; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (p.charAt(j - 1) != ‘*’) {
dp[i][j] = i > 0 && dp[i - 1][j - 1] && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == ‘.’);
} else {
dp[i][j] = dp[i][j - 2] || (i > 0 && dp[i - 1][j] && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == ‘.’));
}
}
}
return dp[m][n];
}
}

时间复杂度:O(mn)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一心向上的小奥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值