F*ck Leetcode medium 1090. Largest Values From Labels

题干:https://leetcode.com/problems/largest-values-from-labels/

 

本体可以看成是背包问题的进阶版,目标类似,是让value最大化,不过有两个约束条件,一是选取综述不超过num_wanted, 二是选出的子集如果用label分组的话,每组的元素数量不超过use_limit。

思路大概如下:先把value值分组,并对每组内元素从大到小排序,然后组间按照第一个元素排序(从大到小)。

排序号每次摘取第一个组的第一个元素,即为整体最大元素,这样摘取num_wanted次,或者到无元素可摘的情况,每次摘取还要注意每组摘取的数量不得超过use_limit个,为了更方便地实现这一点,可以在分组时就实现吧每组的元素限制在use_limit个,超过的就直接丢弃,因为反正也选不上。

 

这里的方法其实属于贪心法,其实严格来说,这里需要证明的为什么本处贪心法是work的,是能达到全局最优的,因为这里是个简答求最大值问题,所以证明不会特别复杂,我这里略过了。

 

代码如下:

package com.example.demo.leetcode;

import java.util.*;

public class LargestValuesFromLabels {
    public int largestValsFromLabels(int[] values, int[] labels, int num_wanted, int use_limit) {

        Map<Integer, List<Integer>> label2values = new HashMap<>();
        for(int i=0;i<labels.length;i++){
            add2map(label2values, labels[i], values[i], use_limit);
        }

        List<List<Integer>> sortedList = new ArrayList<>();

        for(Map.Entry<Integer, List<Integer>> entry : label2values.entrySet()){
            //就是为了收集排好序的分组,按照每组第一个元素的大小,从大到小排列
            sortedList.add(entry.getValue());
        }

        Comparator<List<Integer>> comp = new Comparator<List<Integer>>(){
            @Override
            public int compare(List<Integer> s1, List<Integer> s2) {
                if(s2.get(0)>s1.get(0)){
                    return 1;
                }else if(s2.get(0).equals(s1.get(0))){
                    return 0;
                }else if(s2.get(0)<s1.get(0)){
                    return -1;
                }
                return -1000;
            }
        };

        Collections.sort(sortedList, comp);
        int sum = 0;
        for(int i=0;i<num_wanted;i++){
            if(sortedList.size()<1){
                break;
            }
            List<Integer> k = sortedList.get(0);
            if(k.size()>0){
                sum+=k.get(0);
                sortedList.remove(0);
                k.remove(0);
                if(k.size()>0){
                    sortedList.add(k);
                }
                Collections.sort(sortedList, comp);
            }
        }
        return sum;
    }

    private void add2map(Map<Integer, List<Integer>> mp, Integer key, Integer val, int longest){
        if(mp.get(key)!=null){
            List<Integer> list = mp.get(key);

            int i=0;
            while(i<list.size() && list.get(i)>val){
                i++;
            }

            list.add(i, val);

            if(list.size()>longest){
                list.remove(list.size()-1);
            }
        }else{
            List<Integer> eIndexs = new ArrayList<>();
            eIndexs.add(val);
            mp.put(key, eIndexs);
        }
    }


    public static void main(String[] args) {

        LargestValuesFromLabels demo = new LargestValuesFromLabels();

//        int[] values = {5,4,3,2,1};
//        int[] values = {9,8,8,7,6};
        int[] values = {3,2,3,2,1};
//        int[] values = {5963,15066,7870,4883,18205,19694,1938,2291,13915,16317,12347,19514,2766,13578,18721,892,1683,12691,6700,17793,19514,10687,8106,11006,11841,5992,602,7538,13220,15178,14142,7813,17632,16438,3652,9630,19297,19328,12118,18871,1024,10888,2668,6695,6990,8680,13515,10150,6218,18402};
//        int[] labels = {0,0,0,1,1};
        int[] labels = {1,0,2,2,1};
//        int[] labels = {1,1,2,2,3};
//        int[] labels = {7149,19554,17254,15626,5710,9132,9068,1432,14982,3596,12403,1746,10231,11836,449,15140,17696,17094,795,4355,1227,5973,18464,6046,10232,5538,10066,14692,18832,11861,7265,13952,9448,6164,14014,8073,13446,18649,18769,6285,13127,2109,13319,10794,9828,15545,12451,11604,4072,9114};
//        int num_wanted = 3;
        int num_wanted = 2;
        int use_limit = 1;
        int ret = demo.largestValsFromLabels(values, labels, num_wanted, use_limit);

        System.out.println(ret);
    }

}

 

反思: 一开始没有想到用贪心法,导致尝试用动态规划做了很久,到头来却是OJ不停地报timeout,心力憔悴,还是不能一招动态规划打天下啊。。。理论联系实际一下,扒动态规划和贪心的关系: https://labuladong.gitbook.io/algo/dong-tai-gui-hua-xi-lie/tan-xin-suan-fa-zhi-qu-jian-tiao-du-wen-ti

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值