ThoughtWorks笔试题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_25605637/article/details/90265726

题目:

Problem One: Conference Track Management

You are planning a big programming conference and have received many proposals which have passed the initial screen process but you're having trouble fitting them into the time constraints of the day -- there are so many possibilities! So you write a program to do it for you.

  • The conference has multiple tracks each of which has a morning and afternoon session.
  • Each session contains multiple talks.
  • Morning sessions begin at 9am and must finish before 12 noon, for lunch.
  • Afternoon sessions begin at 1pm and must finish in time for the networking event.
  • The networking event can start no earlier than 4:00 and no later than 5:00.
  • No talk title has numbers in it.
  • All talk lengths are either in minutes (not hours) or lightning (5 minutes).
  • Presenters will be very punctual; there needs to be no gap between sessions.

Note that depending on how you choose to complete this problem, your solution may give a different ordering or combination of talks into tracks. This is acceptable; you don’t need to exactly duplicate the sample output given here.

Test input:

Writing Fast Tests Against Enterprise Rails 60min

Overdoing it in Python 45min

Lua for the Masses 30min

Ruby Errors from Mismatched Gem Versions 45min

Common Ruby Errors 45min

Rails for Python Developers lightning

Communicating Over Distance 60min

Accounting-Driven Development 45min

Woah 30min

Sit Down and Write 30min

Pair Programming vs Noise 45min

Rails Magic 60min

Ruby on Rails: Why We Should Move On 60min

Clojure Ate Scala (on my project) 45min

Programming in the Boondocks of Seattle 30min

Ruby vs. Clojure for Back-End Development 30min

Ruby on Rails Legacy App Maintenance 60min

A World Without HackerNews 30min

User Interface CSS in Rails Apps 30min

Test output:

Track 1:

09:00AM Writing Fast Tests Against Enterprise Rails 60min

10:00AM Overdoing it in Python 45min

10:45AM Lua for the Masses 30min

11:15AM Ruby Errors from Mismatched Gem Versions 45min

12:00PM Lunch

01:00PM Ruby on Rails: Why We Should Move On 60min

02:00PM Common Ruby Errors 45min

02:45PM Pair Programming vs Noise 45min

03:30PM Programming in the Boondocks of Seattle 30min

04:00PM Ruby vs. Clojure for Back-End Development 30min

04:30PM User Interface CSS in Rails Apps 30min

05:00PM Networking Event

Track 2:

09:00AM Communicating Over Distance 60min

10:00AM Rails Magic 60min

11:00AM Woah 30min

11:30AM Sit Down and Write 30min

12:00PM Lunch

01:00PM Accounting-Driven Development 45min

01:45PM Clojure Ate Scala (on my project) 45min

02:30PM A World Without HackerNews 30min

03:00PM Ruby on Rails Legacy App Maintenance 60min

04:00PM Rails for Python Developers lightning

05:00PM Networking Event

思路:

  1. 题目要求输出一种活动时间安排方案,要求将所有活动安排在2天的4个时间段内
  2. 首先从文件中读入活动,并从0开始编号,依次递增
  3. 首先判断活动时长是否大于14个小时,如果大于,则没有安排方案,否则进入下一步
  4. 对活动按照编号进行全排列,得到一种排列方案后则判断,活动是否能全部放在3h,4h,3h,4h这四个时间段内,如果能,则输出安排方案。如果不能,则继续进行全排列,直到找到一种方案。

代码:

package com.st;

/**
 * @Author: lilimin
 * @Date: 2019/5/8 0:10
 */
public class Activity {

    /** 活动id,从0开始计数 */
    private int id;
    /** 活动名称 */
    private String name;
    /** 活动时间 */
    private int time;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getTime() {
        return time;
    }

    public void setTime(int time) {
        this.time = time;
    }

}
/**
 * @Author: lilimin
 * @Date: 2019/5/7 23:51
 */
public class FileUtil {

    /**
     * 根据文件解析出活动,并放到map中
     * @param fileName 文件名
     * @return 活动id -> 活动对象 的映射关系
     */
    public static Map<Integer, Activity> loadFile(String fileName) {

        BufferedReader reader = null;
        Map<Integer, Activity> activityMap = new HashMap<>();

        try {

            reader = new BufferedReader(new FileReader(new File(fileName)));
            String line = null;
            int activityId = 0;
            while ((line = reader.readLine()) != null) {
                int lastBlankIndex = line.lastIndexOf(" ");
                String activityName = line.substring(0, lastBlankIndex);
                String activityTimeStr = line.substring(lastBlankIndex + 1);
                int activityTime = 0;
                if (activityTimeStr.equals("lightning")) {
                    activityTime = 5;
                } else {
                    activityTime = Integer.valueOf(activityTimeStr.substring(0, activityTimeStr.length() - 3));
                }
                Activity activity = new Activity();
                activity.setId(activityId);
                activity.setName(activityName);
                activity.setTime(activityTime);
                activityMap.put(activityId, activity);
                activityId++;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return activityMap;
    }
}
/**
 * @Author: lilimin
 * @Date: 2019/5/8 0:04
 */
public class PlanningTime {

    /** 2天可以安排的时间为14小时 */
    public final int ALL_MINUTES = 14 * 60;
    /** 上午3小时常量 */
    public final int THREE_HOUR_MINUTES = 3 * 60;
    /** 下午4小时常量 */
    public final int FOUR_HOUR_MINUTES = 4 * 60;
    /** 保存了 活动id -> 活动对象 的映射关系 */
    public Map<Integer, Activity> activityMap;
    /** 最终输出的时间方案 */
    public List<String> planList = new ArrayList<>();
    /** 最终除活动安排的其他输出行数,例如 Track 2: */
    public int OTHER_OUTPUT_LINE_NUMBER = 7;
    /** 是否找到一种可行方案 */
    boolean flag;

    /**
     * 根据输入的文件,输出活动安排
     * @param fileName 文件名
     * @return 活动安排
     */
    public List<String> startPlan(String fileName) {

        activityMap = FileUtil.loadFile(fileName);
        int totalTime = 0;
        for (Map.Entry<Integer, Activity> entry : activityMap.entrySet()) {
            totalTime += entry.getValue().getTime();
        }
        if (totalTime > ALL_MINUTES) {
            planList.add("活动总时间超过14个小时,无法安排");
            return planList;
        }
        int[] nums = new int[activityMap.size()];
        for (int i = 0; i < activityMap.size(); i++) {
            nums[i] = i;
        }
        getFullPermutation(nums, 0);
        return planList;
    }

    /**
     * 尝试按照全排列弄好的顺序,看是否能正好分成4个部门,且包含所有的活动
     * @param permutationList 活动顺序
     * @return 最终输出格式的活动列表
     */
    public List<String> tryPlan(List<Integer> permutationList) {

        List<String> planList = new ArrayList<>();
        // 第一天上午的活动
        List<Activity> partOneList = new ArrayList<>();
        // 第一天下午的活动
        List<Activity> partTwoList = new ArrayList<>();
        // 第二天上午的活动
        List<Activity> partThreeList = new ArrayList<>();
        // 第二天下午的活动
        List<Activity> partFourList = new ArrayList<>();
        int nextIndex = getGropupList(0, permutationList, partOneList, THREE_HOUR_MINUTES);
        nextIndex = getGropupList(nextIndex, permutationList, partTwoList, FOUR_HOUR_MINUTES);
        nextIndex = getGropupList(nextIndex, permutationList, partThreeList, THREE_HOUR_MINUTES);
        nextIndex = getGropupList(nextIndex, permutationList, partFourList, FOUR_HOUR_MINUTES);
        // 活动没有全部安排完
        if (nextIndex != permutationList.size()) {
            return planList;
        }
        planList.add("Track 1:");
        planList.addAll(getPlanStrList(partOneList, 9, "AM"));
        planList.add("12:00PM Lunch");
        planList.addAll(getPlanStrList(partTwoList, 1, "PM"));
        planList.add("05:00PM Networking Event");
        planList.add("");
        planList.add("Track 2:");
        planList.addAll(getPlanStrList(partThreeList, 9, "AM"));
        planList.add("12:00PM Lunch");
        planList.addAll(getPlanStrList(partFourList, 1, "PM"));
        planList.add("05:00PM Networking Event");
        return planList;
    }

    /**
     * 获得每个活动最后的格式化输出
     * @param activityList 放每个分组的活动
     * @param startHour 上午活动开始的时间为9点,下午活动开始的时间为1点
     * @param unit 活动所在的时间,AM为上午,PM为下午
     * @return 每个时间段的格式化输出
     */
    public List<String> getPlanStrList(List<Activity> activityList, int startHour, String unit) {

        List<String> planList = new ArrayList<>();
        int hour = 0;
        int minute = 0;
        int totlaMinute = 0;
        for (Activity activity : activityList) {
            String hourStr = String.format("%02d", hour + startHour);
            String minuteStr = String.format("%02d", minute);
            String timeStr = activity.getTime() == 5 ? "lightning" : activity.getTime() + "min";
            String nowTimeStr = hourStr + ":" + minuteStr + unit;
            planList.add(String.join(" ", Arrays.asList(nowTimeStr, activity.getName(), timeStr)));
            totlaMinute += activity.getTime();
            hour = totlaMinute / 60;
            minute = totlaMinute % 60;
        }
        return planList;
    }

    /**
     *
     * @param index 要安排的活动的索引下标
     * @param permutationList 活动的排序顺序
     * @param activityList 放活动的列表
     * @param limitTime 超过这个时间,就不能再放活动了
     * @return 下一个要分组的活动的下标
     */
    public Integer getGropupList(int index, List<Integer> permutationList, List<Activity> activityList, int limitTime) {

        int planedTime = 0;
        int i;
        for (i = index; i < permutationList.size(); i++) {
            Activity activity = activityMap.get(permutationList.get(i));
            planedTime += activity.getTime();
            if (planedTime <= limitTime) {
                activityList.add(activity);
            } else {
                break;
            }
        }
        return i;
    }

    /**
     * 从nums数组的全排列中找一种解决方案,找到就退出
     * @param nums
     * @param index
     */
    public void getFullPermutation(int[] nums, int index) {

        // 已经找到解决方案
        if (flag == true) {
            return;
        }

        if (index == nums.length - 1) {
            List<Integer> list = new LinkedList<Integer>();
            for(int j = 0; j < nums.length; j++){
                list.add(nums[j]);
            }
            List<String> onePlanList = tryPlan(list);
            // 活动的个数+7(多余输出的行数)= 格式化输出的行数,则说明活动都能被安排
            if (onePlanList.size() == activityMap.size() + OTHER_OUTPUT_LINE_NUMBER) {
                planList.addAll(onePlanList);
                flag = true;
                return;
            }
        }
        for(int i = index; i < nums.length; i++){
            swap(nums, index , i);
            getFullPermutation(nums, index + 1);
            swap(nums, index, i);
        }
    }

    /**
     * 交换数组中num[i]和num[j]的值
     * @param nums
     * @param i
     * @param j
     */
    public void swap(int[] nums, int i, int j){
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }

    public static void main(String[] args) {
        PlanningTime planningTime = new PlanningTime();
        List<String> list = planningTime.startPlan("src/main/resources/task-test1.txt");
        for (String str : list) {
            System.out.println(str);
        }
    }

}

猜你喜欢

转载自blog.csdn.net/qq_25605637/article/details/90265726