从给定模式中挑选m个不同对象的最快方法?

给出n个元素的数组,其中每个元素的范围为2到10 ^ 5。现在,如果我们绘制数组的元素,使得对于每m(m

Ex:对于n = 4,A = {10 20 15 28} m = 2,我们可以将元素绘制为RGRG或GRGR。在两种情况下,如果我们选择任意m个连续元素,则没有两个元素具有相同的元素颜色,例如RG或GR或RG。有4种方法可以选择2个元素10 20或10 28或20 15或1528。但是20-15 = 5,这是最好的答案。

**数组中允许重复

我的解决方法是首先将所有类似的颜色元素放入单独的数组中。像上面的示例一样,我可以这样做:[[[10,15] [20,28]] 10 15是R,20 28是G。然后我对R的每个元素使用递归并尝试使用连续颜色的所有组合。>

void recurse(List<List<Integer>> bs,int max,int min,int depth) {
    if(depth == bs.size()) {
        int diference = max - min;
        // compare diff with old res here
        return;
    }

    for(int i=0;i<bs.get(depth).size();++i) {
        int newMax = Math.max(max,bs.get(depth).get(i));
        int newMin = Math.min(min,bs.get(depth).get(i));
        recurse(bs,newMax,newMin,depth+1);
    }
}

这没错,确实可以产生正确的结果。但是我正在寻找一种更快的算法。预期的时间复杂度为O(n)或更准确地说,我想在1秒内通过每个测试用例。请注意2

doitsc 回答:从给定模式中挑选m个不同对象的最快方法?

我们可以在O(n log n)时间和O(n)空间中解决此问题。首先请注意,任何指定的颜色必须与相同颜色的相邻元素相距m个元素,否则我们将使约束无效。

将每个这种颜色相同的元素列表(仅由彼此之间的距离定义)分隔到自己的列表中并进行排序。

现在将所有m排序列表合并到一个排序列表中,其中每个值还与其来源列表颜色的标签配对(例如,合并列表可以是元组)。 / p>

(或者,我们可以先创建整个标签列表,然后对那个进行排序。)

使用大小为m的滑动窗口在排序的,带有标签的列表上进行迭代,从而每次仅允许每种颜色的一个元素留在窗口中。 (我们可以使用哈希图或简单数组来跟踪窗口。请记住,在这种情况下,窗口具有唯一标签,而不是标签列表的连续子数组。)在迭代过程中更新窗口中存在的最小范围以确定答案。

,

我认为您可以对数字进行排序(但要跟踪其颜色),然后从开始就逐步查看结果,首先要培养出候选人以显示所有颜色(因此head将涵盖子列表中的唯一颜色),然后缩小它,以便从tail抛出重复的颜色(因此它也指向唯一的颜色),然后检查到目前为止是否是最佳候选,然后丢弃{{ 1}}(这样就会丢失颜色),然后再次使用head:

tail

输出(一个3色常量随机序列-因为提供了种子-您的2色示例和您所修复的错误的测试用例):

import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class NewClass {
    public static void doThing(int nums[],int m){
        int n=nums.length;
        ColorNumber l[]=new ColorNumber[n];
        for(int i=0;i<n;i++)
            l[i]=new ColorNumber(nums[i],i%m);
        System.out.println(Arrays.asList(l));
        Arrays.sort(l,null);
        List printlist=Arrays.asList(l);
        System.out.println(printlist);
        int present[]=new int[m];
        int head=0,tail=0;
        int minhead=0,mintail=0,mindiff=Integer.MAX_VALUE;
        while(head<n){
            System.out.println("try growing");
            int i=0;
            while(i<m && head<n){
                while(present[i]==0 && head<n){
                    present[l[head].color]++;
                    head++;
                }
                //if(present[i]>0)i++;           // the bug
                while(i<m && present[i]>0)i++;   // the fix
            }
            if(i==m){
                System.out.println(printlist.subList(tail,head));
                System.out.println("try shrinking");
                while(present[l[tail].color]>1){
                    present[l[tail].color]--;
                    tail++;
                }
                int diff=l[head-1].number-l[tail].number;
                System.out.println(printlist.subList(tail,head)+" diff: "+diff);
                if(diff<mindiff){minhead=head;mintail=tail;mindiff=diff;}
                present[l[tail].color]--;
                tail++;
            }
        }
        System.out.println("min: "+mindiff+","+printlist.subList(mintail,minhead));
    }

    static class ColorNumber implements Comparable<ColorNumber>{
        final int number;
        final int color;

        public ColorNumber(int number,int color) {
            this.number = number;
            this.color = color;
        }

        @Override
        public int compareTo(ColorNumber o) {
            return number-o.number;
        }

        @Override
        public String toString() {
            return number+"("+color+")";
        }
    }

    public static void main(String args[]){
        Random r=new Random(0);
        int nums[]=new int[10];
        for(int i=0;i<nums.length;i++)
            nums[i]=r.nextInt(100);
        doThing(nums,3);
        System.out.println("---");
        doThing(new int[]{10,20,15,28},2);
        System.out.println("---");
        doThing(new int[] {2,1},2);              // test case for bug
    }
}

在输出中,只有最低值和最高值的颜色才是唯一的,可以随意选择中间的元素,因为它们不会造成差异(此代码将它们全部输出,就像第一个序列([60(0),48(1),29(2),47(0),15(1),53(2),91(0),61(1),19(2),54(0)] [15(1),54(0),60(0),91(0)] try growing [15(1),47(0)] try shrinking [15(1),47(0)] diff: 32 try growing [19(2),48(1)] try shrinking [29(2),48(1)] diff: 19 try growing [47(0),53(2)] try shrinking [47(0),53(2)] diff: 6 try growing [48(1),54(0)] try shrinking [48(1),54(0)] diff: 6 try growing [53(2),61(1)] try shrinking [53(2),61(1)] diff: 8 try growing min: 6 [47(0),53(2)] --- [10(0),20(1),15(0),28(1)] [10(0),28(1)] try growing [10(0),20(1)] try shrinking [15(0),20(1)] diff: 5 try growing min: 5 [15(0),20(1)] --- [2(0),1(1)] [1(1),2(0)] try growing [1(1),2(0)] try shrinking [1(1),2(0)] diff: 1 min: 1,[1(1),2(0)] )中的最后一次尝试。如果需要特定的输出,则可以使用一些[53(2),61(1)]或在颜色上进行Set循环,为每种颜色仅打印一个(遇到的第一个)元素(并使用简单的for)。

本文链接:https://www.f2er.com/3129977.html

大家都在问