解决学生参加的最大课程的算法

时间:2019-02-12 13:02:09

标签: java algorithm data-structures

Algo在公司的一次顶级采访中问,我找不到可行的解决方案。需要专家的建议。 假设一个学生想在一天内参加最多一幅拼贴画的课程,详细信息如下: 提供了科目名称以及课程的开始时间和结束时间。 输入将为

    **SUBJECT START_TIME END_TIME**
    Maths 16:00 18:00
    ComputerScience 12:00 13:00 
    Physics 12:30 14:00
    Chemistry 14:00 16:30

输出将是学生可以参加的课程数量。 输出为2,根据上述数据(即计算机科学以及数学或化学),学生最多可以参加2个课程。 以下是我的解决方案,但我没有得到正确的答案:

private void getMaxClass(String input) {

                Map<String, Long> classTime = new LinkedHashMap<>();
                Map<String, List<String>> timeMap = new LinkedHashMap<>();
                String [] split = input.split(" ");
                String subject = split[0];
                String StartTime = split[1];
                String endTime = split[2];
                List<String> lvalue = new ArrayList<>();
                lvalue.add(StartTime); lvalue.add(endTime);
                timeMap.put(subject, lvalue);
                long difference = FineDifferenceInTime(StartTime, endTime);
                classTime.put(subject, difference);
                int count =0;
                Date date1 = null;
                Date date2 = null;
                Map<String, Long> sortedByValueDesc = 
                classTime .entrySet() .stream() 
                .sorted(Map.Entry.<String, Long> comparingByValue())
                .collect( Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
                for (Map.Entry<String, Long> entry : sortedByValueDesc.entrySet()) {
                String sub = entry.getKey();
                List<String> startEnd = timeMap.get(sub);
                Date dateBefore = null;
                Date dateAfter = null;
                SimpleDateFormat format = new SimpleDateFormat("HH:mm");
                try {
                    dateBefore = format.parse(startEnd.get(0));
                    dateAfter = format.parse(startEnd.get(1));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                if(count ==0){
                    count++;
                try {
                    date1 = format.parse(startEnd.get(0));
                    date2 = format.parse(startEnd.get(1));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                }
                if(dateBefore.after(date1) && dateBefore.before(date2)){
                    timeMap.remove(sub);
                }
            }
            System.out.println(timeMap.size());
}

5 个答案:

答案 0 :(得分:0)

我用Python尝试过。它给出正确的输出。 我按班级开始时间进行排序。

sorted_by_start = [{'sub': 'ComputerScience', 'start': '12:00', 'end': '13:00', 
'duration': 60}, {'sub': 'Physics', 'start': '12:30', 'end': '14:00', 'duration': 
90}, {'sub': 'Chemistry', 'start': '14:00', 'end': '16:30', 'duration': 150}, 
{'sub': 'Maths', 'start': '16:00', 'end': '18:00', 'duration': 120}]

possible_sub = set()

for a, b in itertools.combinations(sorted_by_start, 2):
    strt_tme = datetime.datetime.strptime(a["end"], '%H:%M')
    end_tme = datetime.datetime.strptime(b["start"], '%H:%M')
      if(strt_tme <= end_tme) :
        possible_sub.add((a["sub"],b["sub"]))

print("A student can attend these combinations of subject classes:",possible_sub)
print("Maximum classes student can attend in a day is: ",max(map(len,possible_sub)))

这里的诀窍是确定可以组合的数量。因此,您可以这样添加额外的for循环,范围从2到sorted_list的长度,然后将i传递给组合(sorted_list,i),就像这样。

输出是:

A student can attend these combinations of subject classes:  {('Physics', 'Maths'), ('Physics', 'Chemistry'), ('ComputerScience', 'Chemistry'), ('Compu
terScience', 'Maths')}
Maximum classes student can attend in a day is:  2

答案 1 :(得分:0)

这在文献中被称为Interval Scheduling Problem。有很多解决方法,但是由于它是NP-complete (as there is a a polynomial reduction from VC),因此您必须探索所有组合。

确实存在贪婪的算法(就像您和@PriyankaDeshmukh的解决方案一样),但是它们不能保证您对问题的所有实例都有确切的解决方案。

下面的解决方案是一个简单的树搜索:在每个级别上,我们决定是否选择给定的课程,然后继续确定下一门课程。

您还可以实现动态编程解决方案。

Here是一篇非常不错的博客文章,内容涉及 Interval Scheduling 问题的解决方案。

decision tree


我通过以下方式对学生类进行了建模:

class StudentClass {
    public int _start;
    public int _end;
    public String _name;
    public StudentClass(String name, int start, int end) {
        _name = name;
        _start = start;
        _end = end;
    }
    public boolean overlapsWith(StudentClass other) {
        return _start < other._end && _end > other._start;
    }
    public String toString() {
        return "[" + _start + " - " + _end + "] " + _name;
    }
}

虽然有一些类可以代表一天中的时间,但是它们的语法/实例化却有点烦人/冗长-不过请随时改进此答案!我的Java也很生锈,所以请随时纠正我:-)


Schedule班级有一个getMaxSchedule(),它返回问题的解决方案-学生可以参加的最大班级数是什么,以使它们都没有重叠?

有几种方法可以对其进行优化,但我相信它会更容易理解,因此我将其保持不变。

public class Schedule {

    List<StudentClass> _classes = new LinkedList<>();

    public void addClass(String name, int startTime, int endTime) {
        _classes.add(new StudentClass(name, startTime, endTime));
    }

    private int getMaxSchedule(int index, Collection<StudentClass> selected) {
        // check if we reached the end of the array
        if (index >= _classes.size()) {
            return 0;
        }

        StudentClass current = _classes.get(index);

        // check if taking this class doesn't conflict with the
        // previously-selected set of classes
        boolean canTakeThisClass = true;
        for (StudentClass other : selected) {
            if (current.overlapsWith(other)) {
                canTakeThisClass = false;
                break;
            }
        }

        // check best schedule if we don't take this class
        int best = getMaxSchedule(index + 1, selected);

        // check best schedule if we take this class (if such is possible)
        if (canTakeThisClass) {
            selected.add(current);
            best = Math.max(best, 1 + getMaxSchedule(index + 1, selected));
            selected.remove(current);
        }

        return best;
    }

    public int getMaxSchedule() {
        Collection<StudentClass> selected = new ArrayList<>();
        return getMaxSchedule(0, selected);
    }
}

通过以下操作,您可以看到具体问题的结果为3

public static void main(String[] args) {
    Schedule s = new Schedule();
    s.addClass("Maths", 1600, 1800);
    s.addClass("Computer Science", 1200, 1300);
    s.addClass("Physics", 1230, 1400);
    s.addClass("Chemistry", 1400, 1630);
    System.out.println("maximum classes: " + s.getMaxSchedule());
}

答案 2 :(得分:0)

dism.exe /Online /Enable-Feature:Microsoft-Hyper-V /All

答案 3 :(得分:0)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class InputSubject implements Comparable<InputSubject>{
    String subject;
    String startTime;
    String endTime;
    InputSubject(){
        
    }
    InputSubject(String subject, String startTime, String endTime){
        this.subject = subject;
        this.startTime = startTime;
        this.endTime =  endTime;
    }
    
    public String getSubject() {
        return subject;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    public String getStartTime() {
        return startTime;
    }
    public void setStartTime(String startTime) {
        this.startTime = startTime;
    }
    public String getEndTime() {
        return endTime;
    }
    public void setEndTime(String endTime) {
        this.endTime = endTime;
    }
    @Override
    public int compareTo(InputSubject o) {
        
        return this.endTime.compareTo(o.endTime);
    }

}

public class solution {
    
    static int getToatlSubject(List<InputSubject> list){
        String sTime = null;
        String eTime =  null;
        int count = 0;
        int noOfSubject = 0;
        for(InputSubject object : list){
            if(count == 0){
                count++;
                eTime = object.getEndTime();
                noOfSubject ++;
            }
            else {
                if(object.getStartTime().compareTo(eTime) >= 0){
                    eTime = object.getEndTime();
                    noOfSubject ++;
                }
            }
        }
        return noOfSubject;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        try {
            int days = Integer.parseInt(reader.readLine());
            for(int i = 0 ; i < days ;i++){
                int sub = Integer.parseInt(reader.readLine());
                List<InputSubject> list = new ArrayList<>();
                for(int k = 0 ; k < sub ; k++){
                    InputSubject inputSubject = null;
                    String subDetails =  reader.readLine();
                    String[] subAndTimes = subDetails.split(" ");
                    inputSubject = new InputSubject(subAndTimes[0],subAndTimes[1],subAndTimes[2]);
                    list.add(inputSubject);
                }
                Collections.sort(list);
                System.out.println(getToatlSubject(list));
            }
        
        } catch (Exception e) {
        }

    }

}

答案 4 :(得分:-1)

我在招聘的编码回合中遇到了同样的问题,我已经通过以下方式解决了它,并给出了正确的答案。但不幸的是,这段代码仅通过了挑战中给出的 1 个测试用例。我相信测试用例是不正确的。谁能指出我是否在代码中遗漏了一些可能导致此代码无法通过其他测试用例的内容?

import java.util.*;
import java.time.*;
import java.time.format.DateTimeFormatter; 
import static java.time.temporal.ChronoUnit.*;

class solution {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        for (int i = 0; i < t; i++) {
            int n=sc.nextInt();
            String trash=sc.nextLine();
            HashMap subjects=new HashMap<String,String>();
            HashMap starttime=new HashMap<String,LocalTime>();
            HashMap endtime=new HashMap<String,LocalTime>();
            HashMap length=new HashMap<String,Long>();
            for (int j = 0; j < n; j++){
                String classes = sc.nextLine();
                String[] classesArray=classes.split(" ");
                String subject=classesArray[0];
                if(classesArray[1].split(":")[0].length()==1){
                    classesArray[1]="0"+classesArray[1];
                }
                if(classesArray[2].split(":")[0].length()==1){
                    classesArray[2]="0"+classesArray[2];
                }
                LocalTime startTime=LocalTime.parse(classesArray[1]);
                LocalTime endTime=LocalTime.parse(classesArray[2]);
                DateTimeFormatter formatter = DateTimeFormatter.ISO_TIME; 
                Long lengthLecture=MINUTES.between(startTime, endTime);
                subjects.put(subject,subject);
                starttime.put(subject,startTime);
                endtime.put(subject,endTime);
                length.put(subject,lengthLecture);
                String value = startTime.format(formatter);
                String value1 = endTime.format(formatter);
                // System.out.printf("Sub:%s st:%s et:%s length:%d\n",subject,value,value1,lengthLecture);
            }
            findMax(subjects,starttime,endtime,length);
            //System.out.println(num);
        }
    }
    public static void findMax(HashMap<String,String> subs,HashMap<String,LocalTime> strt,HashMap<String,LocalTime> endt,HashMap<String,Long> length){
      int number=0;
      List<Integer> list = new ArrayList<Integer>();
      String curr,next1;
      for (Map.Entry<String,String> entry : subs.entrySet()){
      //System.out.println("Checkign for number: "+entry.getKey());
      number=findnext(entry.getKey(),strt,endt);
      // System.out.println("Number is: "+number);
      list.add(number);
      }
      System.out.println(Collections.max(list));
    }
   
    public static int findnext(String subjt,HashMap<String,LocalTime> strt,HashMap<String,LocalTime> endt){
        String sub=subjt;
        int number=1;
        LocalTime substtime=strt.get(subjt);
        LocalTime subedtime=endt.get(subjt);
        Long timetillstart=922337203L;
        for (Map.Entry<String,LocalTime> entry : strt.entrySet()){
            if((entry.getValue().compareTo(subedtime)>=0) && (MINUTES.between(subedtime, entry.getValue())<=timetillstart)){
                sub=entry.getKey();
                substtime=strt.get(entry.getKey());
                timetillstart=MINUTES.between(subedtime, entry.getValue());
            }
        }
        if(sub!=subjt){
            number=number+findnext(sub,strt,endt);
        }
        return number;
    }
}