贪心处理任务(华为od机考题)

一、题目

1.原题

在某个项目中有多个任务(用 tasks 数组表示)需要您进行处理,
其中 tasks[i] = [si, ei],
你可以在 si <= day <= ei 中的任意一天处理该任务。
请返回你可以处理的最大任务数。
注:一天可以完成一个任务的处理。
[排序, 队列, 贪心]

2.题目理解

贪心算法‌:如果任务可以按照结束时间排序,并且后续任务的开始时间晚于或等于当前任务的结束时间,那么可以贪心地选择尽可能多的任务。

例如,平时购物找零钱时,为使找回的零钱的硬币数最少,不要求找零钱的所有方案,而是从最大面值的币种开始,按递减的顺序考虑各面额,先尽量用大面值的面额,当不足大面值时才去考虑下一个较小面值,这就是贪心算法 。

将任务按结束时间排序后:

eg:[1, 4][3, 5][2, 7][6, 9]

task[0]可选择时间有:{1,2,3,4};

task[1]可选择时间有:{3,4,5};

task[2]可选择时间有:{2,3,4,5,6,7};

task[3]可选择时间有:{6,7,8,9}。

完整时间片为:1-9:{1,2,3,4,5,6,7,8,9}

从结束时间最晚的task[3]开始抓取,

选取9后task[3]完成了;

再到了task[2]选取最大值7;

再到了task[1]选取最大值5;

再到了task[0]选取最大值4;

每次都选择最大的,确保前边的值选择空间更多!

二、思路与代码过程

1.思路

输入:

任务数量n

tasks[n]数组

输出:

可以处理的最大任务数

贪心算法

2.代码过程

①main函数

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入该项目所含有的任务数量n:");
        int n = sc.nextInt();
        System.out.println("请输入任务数组tasks:");
        int [][] tasks = new int[n][2];
        for (int i = 0; i < n; i++) {
            tasks[i][0] = sc.nextInt();
            tasks[i][1] = sc.nextInt();
        }
        int maxTake = TaskCount(tasks) ;
        System.out.println("可以处理的最大任务数为:"+maxTake);
    }

②TaskCount

private static int TaskCount(int[][] tasks) {
        int canTake = 0 ;
        /*1.找到AllCanChose数组*/
        int min = Arrays.stream(tasks) // 将二维数组转换为流
                .flatMapToInt(Arrays::stream) // 展平为一维流
                .min() // 获取最小值
                .orElseThrow(() -> new IllegalArgumentException("Array is empty"));
        int max = Arrays.stream(tasks)
                .flatMapToInt(Arrays::stream)
                .max()
                .orElseThrow(()->new IllegalArgumentException("Array is empty"));
        Set<Integer> AllCanChose = new HashSet<>();//固定值
        for (int i = min ;i<=max ;i++) {
            AllCanChose.add(i);
        }
       /*2.对任务数组排序*/
        int[][] sortedTasks = Arrays.stream(tasks)
                .sorted(Comparator.comparing(a -> a[1]))
                .toArray(int[][]::new);
        /*3.将一个个任务数组拆分为时间点和所有可选择天数数组一起传给TakeOrNot函数进行处理*/
        for (int i = sortedTasks.length-1; i >= 0; i--) {
            ArrayList<Integer> partCanTake = new ArrayList<>();//随i改变,每一次都是一组新的
            int start = sortedTasks[i][0];
            int end = sortedTasks[i][1];
            for (int j =start;j<=end;j++) {
                partCanTake.add(j);
            }
            boolean takeOrnot =  TakeOrNot(AllCanChose,partCanTake);
            if (takeOrnot){
                canTake++;
            }
        }
        return canTake;
    }

③TakeOrNot

/*判断当前任务是否可以接取,在哪一天接*/
    private static boolean TakeOrNot(Set<Integer> allCanChose, ArrayList<Integer> partCanTake) {
        boolean takeOrnot = false;
        if (allCanChose.size() !=0) {
            int deadline = partCanTake.get(partCanTake.size()-1);
            //如果在可选天里边当前任务的deadline还在,就选取deadline
            if (allCanChose.contains(deadline)) {
               allCanChose.remove(deadline);
               takeOrnot = true;
            }
            //如果deadline已经被前边一个选走了:eg; 1,2 1,2 2,4 3,4
            //顺延到前一天,若前一天也被选取了,继续前一天,如果没有可以选的,该任务就做不了(递归)
            else {
                if (partCanTake.size()>1){
                    partCanTake.remove(partCanTake.size()-1);
                    takeOrnot = TakeOrNot(allCanChose, partCanTake);
                } else if (partCanTake.size()==1){
                    return takeOrnot;
                }
            }
        }else {
            return takeOrnot;
        }

        return takeOrnot;
    }

三、运行结果

1.运行截图

2.带数据分析运行结果

tasks数组的最小值为:1
tasks数组的最大值为:4
所有可以选择的天有:[1, 2, 3, 4]
按照结束时间排序后的任务组为:
[1, 2]
[1, 2]
[2, 4]
[3, 4]

当前处理任务为:[3, 4]
当前任务可选择的天数有:[3, 4]
partCanTake的最后一天还可以选择!
选走最后一天后,剩余可选天数为:[1, 2, 3]

当前处理任务为:[2, 4]
当前任务可选择的天数有:[2, 3, 4]
移除最后一天后可选的有:[2, 3]
partCanTake的最后一天还可以选择!
选走最后一天后,剩余可选天数为:[1, 2]

当前处理任务为:[1, 2]
当前任务可选择的天数有:[1, 2]
partCanTake的最后一天还可以选择!
选走最后一天后,剩余可选天数为:[1]

当前处理任务为:[1, 2]
当前任务可选择的天数有:[1, 2]
移除最后一天后可选的有:[1]
partCanTake的最后一天还可以选择!
选走最后一天后,剩余可选天数为:[]

可以处理的最大任务数为:4

3.带数据分析完整代码

import javax.net.ssl.SSLContext;
import java.util.*;

public class test34 {
    public static void main(String[] args) {
        /*
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入该项目所含有的任务数量n:");
        int n = sc.nextInt();
        System.out.println("请输入任务数组tasks:");
        int [][] tasks = new int[n][2];
        for (int i = 0; i < n; i++) {
            tasks[i][0] = sc.nextInt();
            tasks[i][1] = sc.nextInt();
        }
        for (int[] task : tasks) {
            System.out.println(Arrays.toString(task));
        }
        */
        int [][] tasks = {{1,2},{1,2},{2,4},{3,4}};
        int maxTake = TaskCount(tasks) ;
        System.out.println("可以处理的最大任务数为:"+maxTake);
    }

    private static int TaskCount(int[][] tasks) {
        int canTake = 0 ;
        /*1.找到AllCanChose数组*/
        int min = Arrays.stream(tasks) // 将二维数组转换为流
                .flatMapToInt(Arrays::stream) // 展平为一维流
                .min() // 获取最小值
                .orElseThrow(() -> new IllegalArgumentException("Array is empty"));
        int max = Arrays.stream(tasks)
                .flatMapToInt(Arrays::stream)
                .max()
                .orElseThrow(()->new IllegalArgumentException("Array is empty"));
        System.out.println("tasks数组的最小值为:" +min);
        System.out.println("tasks数组的最大值为:" +max);
        Set<Integer> AllCanChose = new HashSet<>();//固定值
        for (int i = min ;i<=max ;i++) {
            AllCanChose.add(i);
        }
        System.out.println("所有可以选择的天有:"+AllCanChose);

        /*2.对任务数组排序*/
        int[][] sortedTasks = Arrays.stream(tasks)
                .sorted(Comparator.comparing(a -> a[1]))
                .toArray(int[][]::new);
        System.out.println("按照结束时间排序后的任务组为:");
        for (int[] task : sortedTasks) {
            System.out.println(Arrays.toString(task));
        }
        System.out.println();

        /*3.将一个个任务数组拆分为时间点和所有可选择天数数组一起传给TakeOrNot函数进行处理*/
        for (int i = sortedTasks.length-1; i >= 0; i--) {
            System.out.println("当前处理任务为:"+Arrays.toString(sortedTasks[i]));
            ArrayList<Integer> partCanTake = new ArrayList<>();//随i改变,每一次都是一组新的
            int start = sortedTasks[i][0];
            int end = sortedTasks[i][1];
            for (int j =start;j<=end;j++) {
                partCanTake.add(j);
            }
            System.out.println("当前任务可选择的天数有:"+partCanTake);
            boolean takeOrnot =  TakeOrNot(AllCanChose,partCanTake);
            //System.out.print("每一次的判断:"+takeOrnot);
            if (takeOrnot){
                canTake++;
            }
        }
        return canTake;
    }

    /*判断当前任务是否可以接取,在哪一天接*/
    private static boolean TakeOrNot(Set<Integer> allCanChose, ArrayList<Integer> partCanTake) {
        boolean takeOrnot = false;
        if (allCanChose.size() !=0) {
            int deadline = partCanTake.get(partCanTake.size()-1);
            //如果在可选天里边当前任务的deadline还在,就选取deadline
            if (allCanChose.contains(deadline)) {
                System.out.println("partCanTake的最后一天还可以选择!");
                allCanChose.remove(deadline);
                System.out.println("选走最后一天后,剩余可选天数为:"+allCanChose);
                System.out.println();
                takeOrnot = true;
            }
            //如果deadline已经被前边一个选走了:eg; 1,2 1,2 2,4 3,4
            //顺延到前一天,若前一天也被选取了,继续前一天,如果没有可以选的,该任务就做不了(递归)
            else {
                if (partCanTake.size()>1){
                    partCanTake.remove(partCanTake.size()-1);
                    System.out.println("移除最后一天后可选的有:"+partCanTake);
                    takeOrnot = TakeOrNot(allCanChose, partCanTake);
                } else if (partCanTake.size()==1){
                    System.out.println("没有时间选啦,这个任务完成不了!");
                }
            }
        }else {
            System.out.println("可选时间已经没了,当前任务量就是最大的啦!");
        }

        return takeOrnot;
    }
}

  • 22
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值