专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java面试高频算法题总结:从入门到精通

temp10 2025-03-29 22:09:59 java教程 6 ℃ 0 评论

Java面试高频算法题总结:从入门到精通

大家好呀!今天我们来聊聊Java面试中那些让人头疼却又不得不面对的算法题。这些题目就像考试里的压轴大题一样,总是出现在各种大厂面试中。别担心,我今天就带大家梳理一下常见的高频算法题,而且我会用一种轻松愉快的方式让大家快速掌握它们!

首先,我们来认识一下今天的主要角色——数组、链表、字符串和树。这四个家伙就像是算法题中的四大天王,几乎每场面试都会轮番登场。

Java面试高频算法题总结:从入门到精通

数组篇:稳扎稳打的基础

1. 两数之和

这个题目可以说是数组界的“明星”,几乎所有程序员的第一道算法题都是它。给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的两个整数,并返回它们的数组下标。

public int[] twoSum(int[] nums, int target) {
    Map map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement)) {
            return new int[] { map.get(complement), i };
        }
        map.put(nums[i], i);
    }
    throw new IllegalArgumentException("No two sum solution");
}

这段代码利用了哈希表来存储已经遍历过的元素及其索引,这样可以做到一次遍历就能找到答案,时间复杂度为O(n)。

2. 最接近的三数之和

继续深挖数组的潜力,接下来是三数之和的变种——最接近的三数之和。给定一个包括 n 个整数的数组 nums 和一个目标值 target,请找出三数之和最接近目标值的整数。

public int threeSumClosest(int[] nums, int target) {
    Arrays.sort(nums);
    int closestSum = nums[0] + nums[1] + nums[nums.length - 1];
    for (int i = 0; i < nums.length - 2; i++) {
        int left = i + 1, right = nums.length - 1;
        while (left < right) {
            int currentSum = nums[i] + nums[left] + nums[right];
            if (Math.abs(currentSum - target) < Math.abs(closestSum - target)) {
                closestSum = currentSum;
            }
            if (currentSum < target left else if currentsum> target) {
                right--;
            } else {
                return closestSum;
            }
        }
    }
    return closestSum;
}

这里采用了排序+双指针的方法,时间复杂度为O(n^2)。

链表篇:灵活多变的高手

1. 反转链表

链表类的题目总能让人感到一丝紧张,但其实它们并不那么可怕。比如反转链表,就是一个非常经典的例子。给定单向链表的头节点 head,将其反转。

public ListNode reverseList(ListNode head) {
    ListNode prev = null;
    ListNode curr = head;
    while (curr != null) {
        ListNode nextTemp = curr.next;
        curr.next = prev;
        prev = curr;
        curr = nextTemp;
    }
    return prev;
}

这段代码使用迭代的方法,逐个将当前节点的next指向前一个节点,直到整个链表反转完成。

2. 合并两个有序链表

再来看一个稍微复杂一点的题目,合并两个有序链表。假设这两个链表已经按升序排列,我们需要将它们合并成一个新的有序链表。

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode dummy = new ListNode(0);
    ListNode curr = dummy;
    while (l1 != null && l2 != null) {
        if (l1.val < l2.val) {
            curr.next = l1;
            l1 = l1.next;
        } else {
            curr.next = l2;
            l2 = l2.next;
        }
        curr = curr.next;
    }
    if (l1 != null) {
        curr.next = l1;
    } else {
        curr.next = l2;
    }
    return dummy.next;
}

这段代码创建了一个虚拟头节点,然后依次比较两个链表的节点值,选择较小的那个接入新链表中。

字符串篇:文字游戏的乐趣

1. 最长回文子串

现在让我们进入字符串的世界,看看最长回文子串是如何工作的。给定一个字符串 s,你需要找到其中最长的回文子串。

public String longestPalindrome(String s) {
    if (s == null || s.length() < 1) return "";
    int start = 0, end = 0;
    for (int i = 0; i < s.length i int len1='expandAroundCenter(s,' i i int len2='expandAroundCenter(s,' i i 1 int len='Math.max(len1,' len2 if len> end - start) {
            start = i - (len - 1) / 2;
            end = i + len / 2;
        }
    }
    return s.substring(start, end + 1);
}

private int expandAroundCenter(String s, int left, int right) {
    while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
        left--;
        right++;
    }
    return right - left - 1;
}

这段代码通过中心扩展法,分别考虑奇数长度和偶数长度的回文串,最终找到最长的那个。

2. 最小覆盖子串

最后一个字符串相关的题目是寻找最小覆盖子串。给定一个字符串 S 和 T,找到 S 中包含 T 的所有字符且长度最短的子串。

public String minWindow(String s, String t) {
    if (t.length() > s.length()) return "";
    Map dictT = new HashMap<>();
    for (char c : t.toCharArray()) {
        dictT.put(c, dictT.getOrDefault(c, 0) + 1);
    }
    int required = dictT.size();
    int left = 0, right = 0;
    int formed = 0;
    Map windowCounts = new HashMap<>();
    int[] ans = {-1, 0, 0};
    while (right < s.length()) {
        char c = s.charAt(right);
        windowCounts.put(c, windowCounts.getOrDefault(c, 0) + 1);
        if (dictT.containsKey(c) && windowCounts.get(c).intValue() == dictT.get(c).intValue()) {
            formed++;
        }
        while (left <= right && formed == required) {
            c = s.charAt(left);
            if (ans[0] == -1 || right - left + 1 < ans[0]) {
                ans[0] = right - left + 1;
                ans[1] = left;
                ans[2] = right;
            }
            windowCounts.put(c, windowCounts.get(c) - 1);
            if (dictT.containsKey(c) && windowCounts.get(c).intValue() < dictT.get(c).intValue()) {
                formed--;
            }
            left++;
        }
        right++;
    }
    return ans[0] == -1 ? "" : s.substring(ans[1], ans[2] + 1);
}

这段代码利用滑动窗口技术,动态调整窗口大小,找到满足条件的最小覆盖子串。

树篇:结构之美

1. 二叉树的最大深度

最后我们来看看树相关的题目,首先是二叉树的最大深度。给定一个二叉树,找到它的最大深度。

public int maxDepth(TreeNode root) {
    if (root == null) return 0;
    return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}

递归方法简单明了,直接计算左右子树的最大深度并加一即可。

2. 二叉搜索树验证

另一个经典题目是判断一棵二叉树是否为二叉搜索树。这里需要确保左子树的所有节点都小于根节点,右子树的所有节点都大于根节点。

public boolean isValidBST(TreeNode root) {
    return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
}

private boolean isValidBST(TreeNode node, long lower, long upper) {
    if (node == null) return true;
    if (node.val <= lower node.val>= upper) return false;
    return isValidBST(node.left, lower, node.val) && isValidBST(node.right, node.val, upper);
}

这段代码通过递归检查每个节点是否符合二叉搜索树的性质。

好了,今天的分享就到这里啦!希望这些算法题目的总结能帮到你们,在未来的面试中游刃有余。记住,练习是提高的关键,多做题多思考,相信你一定能在面试中脱颖而出!如果有任何疑问或者想要了解更多内容,随时欢迎来找我交流哦~

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表