会议重排问题:最大重排可以达到值k

时间:2018-09-02 08:46:48

标签: algorithm data-structures

我的一个朋友最近在一次技术采访中遇到了这个问题。

问题名称-长时间休息

  

您正在组织一个活动,将有很多演示者。事件从时间0开始,并为   在活动期间的任何时间都没有联网   正在制作演示文稿。演示文稿可能不会重叠   在同一个房间里,但这使它们可以连续运行,而无需   休息。虽然语音顺序无法更改,但是有一个   给定的最大数目,指示可以讲话多少次   重新安排。您的目标是最大化最长的长度   您可以安排交流时间。例如,有n = 4   主持人预定在时间开始的活动过程中   0,在时间t = 15结束。会议在时间开始= [4,6,   7,10],有时结束= [5,7,8,11]。你可以重新整理   到k = 2次会议。绿色电池是免费的,并标有小时数,   和蓝色单元格安排了演示,并标有演示   数字。

enter image description here

  

在这种情况下,我们有4个时段未安排发言人:[(0-3),(5),(8-9),(11-14)]。会议在14小时后结束。   会议被转移到一个小时之后,从0到5、5创建了休息时间   小时。如果最后一个语音移至8,它将在9结束,剩下一个   从9跌至15。没有必要将中间的两个移动   在这种情况下的演讲。可以达到的最长中断时间是15-   将最后一个语音移到两个小时之前,即9到6个小时。他们俩   选项如下所示。

enter image description here

不幸的是,我无法将问题映射到标准问题。我已经尝试过我自己的幼稚实现,对于给定的输入来说似乎效果很好(必须针对极端情况重新制定策略)

这是我的实现方式

import java.util.ArrayList;
import java.util.Iterator;
class Test {

public static void main(String args[]) {
    Test T  = new Test();
    int  n = 4;
    int k = 2;
    int start[] = {4, 6, 7, 10};
    int end[] = {5, 7, 8, 11};
    int t = 15;
    System.out.println(T.findBreakDuration(n, k, start, end, t));
}

int findBreakDuration(int n, int k, int start[], int end[], int t) {
    boolean meetings[] = new boolean[t]; // false means empty slot
    int i = 0;
    while (i < n) {
        for (int j = start[i]; j < end[i]; j++)
            meetings[j] = true;
        i++;
    }


    ArrayList<Integer> emptySlots = new ArrayList<Integer>();
    int count = 0;
    for (i  = 0; i < meetings.length; i++) {
        if (!meetings[i])
            count++;
        else {
            if (count > 0) {
                emptySlots.add(count);
                count = 0;
            }

        }
    }
    if (count > 0)
        emptySlots.add(count);

    if(emptySlots.size()<=1)
        return -1;
    int maxSoFar = Integer.MIN_VALUE;
    for(i = 0;i<emptySlots.size();i++){
        int e = emptySlots.get(i);
        if(e<=k){
            if(i==0){
                int increasedRight = e + emptySlots.get(i+1);
                if(maxSoFar<increasedRight)
                    maxSoFar = increasedRight;
            }
            else if(i==emptySlots.size()-1)
            {
                int increasedLeft = e + emptySlots.get(i-1);
                if(maxSoFar<increasedLeft)
                    maxSoFar = increasedLeft;
            }
            else{
                int increasedLeft = e + emptySlots.get(i-1);
                int increasedRight = e + emptySlots.get(i+1);

                if(maxSoFar<increasedLeft)
                    maxSoFar = increasedLeft;
                if(maxSoFar<increasedRight)
                    maxSoFar = increasedRight;
            }
        }
    }
    return maxSoFar; // Output : 6, in this case
}
} 

以上代码的简短说明-

我只是跟踪空插槽,并在允许的重新排列(即<= k)之后比较最大可用插槽。最终的最大值为我提供了空插槽序列的最大可能长度或最大持续时间。

我知道这是一个非常幼稚的实现,我敢肯定有一种更好,更优雅的方法来解决问题。我非常强烈地感觉到我在这里缺少一些基本知识。有没有办法优雅地解决这个问题?

4 个答案:

答案 0 :(得分:3)

工作流程确实非常优雅。

1)从作业中提取空白点,请注意连续的演示文稿之间有0个空位。

slotLengths = { 4, 1, 0, 2, 4 }

2)对于给定的k,比较slotLengths的k + 1个相邻值的总和。因此,对于k = 2,比较以下各项的总和:

 { 4, 1, 0 }

 { 1, 0, 2 }

 { 0, 2, 4 }

3)最后一个获胜,因此请将这些演示文稿移到另一侧。

答案 1 :(得分:1)

如@ingen所建议

要解决的步骤:-

第一步:创建一个空时隙列表

第2步:找到最大和为k + 1的子数组

我想补充一件事。

我们可以维护一个大小为k + 1的窗口,并在前面添加元素,而从后面删除元素,而不是从每个起始元素计算子数组的总和。 < / strong>

维护变量以跟踪此窗口的总和。 此变量的最大值是我们正在寻找的答案。

int findMaximumEmptyTimeSlot(List<Integer> emptySlots, int k){

    if(emptySlots.size() == 0) return 0;

    int maxSum = 0;
    int sum = 0;
    for(int i = 0; i < emptySlots.size() && i < k+1; i++)
        sum += emptySlots.get(i);

    maxSum = Math.max(sum, maxSum);

    for(int i = k+1; i < emptySlots.size(); i++){
        int newidx = i;
        int remidx = i - (k+1);

        sum = sum - emptySlots.get(remidx) + emptySlots.get(newidx);

        maxSum = Math.max(sum, maxSum);
    }

    return maxSum;
}

答案 2 :(得分:0)

问题在于不需要检查e <= k。计算空槽后, 由于最多只能移动两个会议,因此您需要将三个连续的空位加起来并取其中的最大值,这是因为两个会议最多创建三个空位,每个空位前后都有一个空位。

for(i = 0;i<emptySlots.size()-2;i++){
      int newmax = emptySlots.get(i)+emptySlots.get(i+1)+emptySlots.get(i+2);            
      if(max<newmax) max=newmax;
      }

答案 3 :(得分:0)

我已经实现了@ ingen

建议的方法

1)从作业中提取空白点,请注意连续的演示文稿之间有0个空位。

slotLengths = { 4, 1, 0, 2, 4 }

2)对于给定的k,比较k + 1个相邻时隙长度值的总和。因此,对于k = 2,比较以下各项的总和:

 { 4, 1, 0 }

 { 1, 0, 2 }

 { 0, 2, 4 }

3)从子集的总和中获得最大值。最大值将是允许的位移长度!

public class Solution
{
    public static void main(String[] args)
    {
    Solution T  = new Solution();
    int  n = 4;
    int k = 2;
    int start[] = {4, 6, 7, 10};
    int end[] = {5, 7, 8, 11};
    int t = 15;
    T.findBreakDuration(n, k, start, end, t);
   }

    int findBreakDuration(int n, int k, int start[], int end[], int t) {
     int max = Integer.MIN_VALUE;

         int initialTime = 0;
         List<Integer> freeSlots = new ArrayList<Integer>();

         for(int i =0;i<start.length;i++)
         {
             int startTime = start[i];
             int slot = startTime - initialTime;
             freeSlots.add(slot);
             initialTime = end[i];
         }
         freeSlots.add(t - end[end.length-1]);

         for(int i  =0 ; i< freeSlots.size()-k; i++)
         {
             int sum = 0;
             int m = i;
             for(int j=1;j<=k+1;j++)
             {
                 sum = sum + freeSlots.get(m);
                 m++;
             }
             System.out.println(sum);
             if(sum > max)
                 max = sum;
         }

        return max;
    }
}