贪心算法面试题

250 阅读3分钟

「这是我参与2022首次更文挑战的第35天,活动详情查看:2022首次更文挑战」。

一、字典序最小的结果

给定一个由字符串组成的数组strs,必须把所有的字符串拼接起来,返回所有可能的拼接结果中,字典序最小的结果

1、分析

arr = {"b", "ba"}

  • 先拼b,后拼ba,则结果是bba
  • 先拼ba,后拼b,则结果是bab
  • 字典序最小的结果是bab

贪心:如果x.y < y.x,x前,否则y前

贪心的解法:排序(比较器)

2、实现

public static class MyComparator implements Comparator<String> {
    @Override
    public int compare(String a, String b) {
        return (a + b).compareTo(b + a);
    }
}

// 贪心解
public static String lowestString2(String[] strs) {
    if (strs == null || strs.length == 0) {
        return "";
    }
    Arrays.sort(strs, new MyComparator());
    String res = "";
    for (int i = 0; i < strs.length; i++) {
        res += strs[i];
    }
    return res;
}

二、最多会议室宣讲场次

一些项目要占用一个会议室宣讲,会议室不能同时容纳两个项目的宣讲。

给你每一个项目开始的时间和结束的时间,

你来安排宣讲的日程,要求会议室进行的宣讲的场次最多。

返回最多的宣讲场次。

1、分析

贪心的核心思路

所有会议的结束时间从小到大排序,定义会议的结束时间为timeLine,遍历每个会议,每个会议的开始时间只要大于等于timeLine,就可以安排,当前的timeLine来到当前会议的结束时间

2、实现

public static int bestArrange2(Program[] programs) {
    Arrays.sort(programs, new ProgramComparator());
    int timeLine = 0;
    int result = 0;
    // 依次遍历每一个会议,结束时间早的会议先遍历
    for (int i = 0; i < programs.length; i++) {
        if (timeLine <= programs[i].start) {
            result++;
            timeLine = programs[i].end;
        }
    }
    return result;
}

public static class ProgramComparator implements Comparator<Program> {

    @Override
    public int compare(Program o1, Program o2) {
        return o1.end - o2.end;
    }

}

三、金条分割的最小代价

一块金条切成两半,是需要花费和长度数值一样的铜板的。

比如长度为20的金条,不管怎么切,都要花费20个铜板。 一群人想整分整块金条,怎么分最省铜板?

例如,给定数组{10,20,30},代表一共三个人,整块金条长度为60,金条要分成10,20,30三个部分。

如果先把长度60的金条分成10和50,花费60; 再把长度50的金条分成20和30,花费50;一共花费110铜板。

但如果先把长度60的金条分成30和30,花费60;再把长度30金条分成10和20, 花费30;一共花费90铜板。

输入一个数组,返回分割的最小代价。

1、分析

arr = {2, 1, 7, 3, 4, 2, 1} 金条长度为20

贪心策略:小根堆

准备一个小根堆,依次放进去

每次从小根堆里弹出两个数,两个数合成一个数(加起来)再让进去,周而复始,小根堆里只存在一个数的时候停,整个过程(这棵树)就是金条最小代价的分割方法,此过程就是著名的赫夫曼编码

金条最优的划分代价就是所有画圈的加起来 = 20 + 8 + 12 + 4 + 5 + 2 = 51

2、实现

public static int lessMoney(int[] arr) {
    PriorityQueue<Integer> pQ = new PriorityQueue<>();
    for (int i = 0; i < arr.length; i++) {
        pQ.add(arr[i]);
    }
    int sum = 0;
    int cur = 0;
    while (pQ.size() > 1) {
        cur = pQ.poll() + pQ.poll();
        sum += cur;
        pQ.add(cur);
    }
    return sum;
}

四、总结

贪心算法解题常常用到排序堆来实现

贪心算法不要证明,贪心的本质就是每个策略都是最好的,通过对数器进行验证即可

贪心策略有时候不一定就贪的对