贪心算法实例

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。 [1]

--------------------------------------------------------------------------------------------------------------------------------------------------摘自百度百科

1、现有一个字符数组,将字符数组中的所有字符串拼接起来,使得到的字符串字典序最小。

思路:使前两个拼接起来字典序最小,依次向后遍历。

注意:并不一定是字典序小的在前边,大的在后边,比如{  {ba} , {b}  }, 显然并不是bba最小,而是bab。

    public static String method(String[] strings) {
        Comparator<String> comparator = new Comparator<String>() {
            @Override
            public int compare(String string1, String string2) {
                return (string1 + string2).compareTo(string2 + string1);
            }
        };

        Arrays.sort(strings, comparator);
        StringBuilder stringBuilder = new StringBuilder();
        for (String string : strings) {
            stringBuilder.append(string);
        }
        return stringBuilder.toString();
    }

2 、一块金条切成两半,是需要花费和长度数值一样的铜板的。比如长度为20的金条,不管切成长度多大的两半,都要花费20个铜板。一群人想整分整块金 条,怎么分最省铜板?
例如,给定数组{10,20,30},代表一共三个人,整块金条长度为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铜板。
输入一个数组,返回分割的最小代价

思路:哈夫曼树问题

每次取出现有数据中最小的两个数。

    public static int method(int[] arr) {
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
        for (int num : arr) {
            priorityQueue.add(num);
        }

        int res = 0;
        while (priorityQueue.size() > 1) {
            int cur = priorityQueue.poll() + priorityQueue.poll();
            priorityQueue.add(cur);
            res += cur;
        }
        return res;
    }

3、IPO问题

现有两个数组cost[m], profile[m] 分别为 1~m-1 号项目的花费资金与完成项目后的纯利润。你的起始资金n,你最多只能投资k个项目,同一时间只能投资一个项目。求你经过一段时间后最多所拥有的资金数。

思路:贪心:每次投资现有资金所能投资的收益最大的项目。

  //项目类
    static class Note {
        int cost;
        int profile;

        public Note(int cost, int profile) {
            this.cost = cost;
            this.profile = profile;
        }
    }


    public static int method(int[] cost, int[] profile, int k, int n) {

//将cost和profile封存到Note数组中
        Note[] notes = new Note[cost.length];
        for (int i = 0; i < cost.length; i++) {
            notes[i] = new Note(cost[i], profile[i]);
        }
//比较器,分别按cost从小到大,profile从大到小排列
        PriorityQueue<Note> costMinPQ = new PriorityQueue<>((note1, note2) -> note1.cost - note2.cost);
        PriorityQueue<Note> proMaxPQ = new PriorityQueue<>((note1, note2) -> note2.profile - note1.profile);

//将所有note添加到costMinPQ优先队列中
        for (Note note : notes) {
            costMinPQ.offer(note);
        }

        while (k-- > 0) {
//costMinPQ队列中,cost小于当前资金的,加入到proMaxPQ中
            while (!costMinPQ.isEmpty() && costMinPQ.peek().cost <= n) {
                Note note = costMinPQ.poll();
                proMaxPQ.offer(note);
            }
            if (proMaxPQ.isEmpty()) {
                return n;
            }
//此时proMaxPq中弹出的就是当前资金所能作的收益最大的项目
            n += proMaxPQ.poll().profile;
        }
        return n;
    }

 

4、一些项目要占用一个会议室宣讲,会议室不能同时容纳两个项目的宣讲。 给你每一个项目开始的时间和结束的时间(给你一个数组,里面 是一个个具体的项目),你来安排宣讲的日程,要求会议室进行 的宣讲的场次最多。返回这个最多的宣讲场次。

思路:贪心,优先选择当前时间所能开的会议中,完成时间最早的。

    public static int method(Note[] notes) {
        Arrays.sort(notes, (note1, note2) -> note1.end - note2.end);
        int cur = 0;
        int res = 0;

        for (int i = 0; i < notes.length; i++) {
            if (cur < notes[i].begin) {
                cur = notes[i].end;
                res++;
            }
        }
        return res;
    }

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值