Java贪心算法(含面试大厂题和源码)

本文介绍了贪心算法的概念,特点,如局部最优选择和无回溯策略,并通过实例探讨了其在找零、背包问题、最小生成树和最短路径等问题中的应用。同时,提供了三个常见编程面试题,展示了贪心算法在实际问题中的运用,涉及数据结构和算法策略。
摘要由CSDN通过智能技术生成

贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法策略。贪心算法解决问题的过程中,每一步都做出一个看似最优的决定,它永远不会回溯,这种做法在很多情况下可以得到最优解,但在某些情况下可能不会得到全局最优解。

贪心算法的特点:

  • 局部最优选择:在每个步骤中,根据某种规则选择当前最优的解决方案。
  • 无回溯:一旦作出了选择,就不再改变。
  • 高效性:通常情况下,贪心算法可以快速找到解决方案,运行效率较高。
  • 应用范围有限:只有当问题满足贪心选择性质(即局部最优解能导致全局最优解)和最优子结构性质时,才能保证得到全局最优解。

贪心算法的应用实例包括:

  • 找零问题:如何用最少的硬币找零。
  • 背包问题:在不超过背包容量的前提下,如何选择物品以使得总价值最大(贪心算法解决的是背包问题的分数版本)。
  • 最小生成树问题:如Kruskal算法和Prim算法。
  • 单源最短路径问题:如Dijkstra算法。

贪心算法的设计思路通常包括两个主要部分:一是贪心策略,用于决定做出哪个选择;二是问题的约束条件,贪心策略需要在满足所有约束的前提下进行。

举一个简单的例子,假设你有面值为1元、2元、5元的硬币,需要支付9元,如何使用最少的硬币完成支付?按照贪心算法,我们每次选择能够支付的最大面值的硬币,直到完成支付。因此,首先选择一个5元的硬币,剩下4元,再选择两个2元的硬币,共使用了3枚硬币,这就是贪心算法的解决方案。

需要注意的是,贪心算法并不适用于所有问题,其正确性需要根据具体问题进行分析。在某些问题上,贪心策略可能无法得到全局最优解。当然,让我们来看三道常见的大厂面试题,这些题目不仅考察基本算法和数据结构的理解,还考验解题思路和编码能力。

题目1: 两数之和

问题描述
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。

示例:

给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

解题思路:
使用哈希表来减少查找时间,遍历数组,每个元素在哈希表中寻找是否存在一个数与当前元素相加等于目标值。

Java代码:

import java.util.HashMap;

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

题目2: 二叉树的最大深度

问题描述
给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

示例:
给定二叉树 [3,9,20,null,null,15,7]

返回它的最大深度 3 。

解题思路:
使用递归的方式,每次递归调用计算左子树和右子树的深度,最后取最大值加1(当前节点的深度)。

Java代码:

public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

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

题目3: 字符串的排列

问题描述
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。

示例1:

输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").

解题思路:
滑动窗口法。用数组记录s1中每个字符的出现次数,然后用一个滑动窗口扫描s2,如果窗口中的字符和s1中字符出现的次数一致,则说明找到了一个匹配。

Java代码:

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int[] count = new int[26];
        for (char c : s1.toCharArray()) count[c - 'a']++;
        
        int start = 0, end = 0, len = s1.length();
        while (end < s2.length()) {
            if (count[s2.charAt(end++) - 'a']-- > 0) len--;
            
            if (len == 0) return true;
            
            if (end - start == s1.length() && count[s2.charAt(start++) - 'a']++ >= 0) len++;
        }
        
        return false;
    }
}

这些题目覆盖了数组、树、字符串和滑动窗口等常见算法和数据结构,希望对你的面试准备有所帮助!

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值