采访拼图:如何找到所有“坏”的工人历史?

时间:2012-05-25 18:26:48

标签: java string algorithm combinatorics

这是一个面试问题。假设我们将工人的工作历史表示为字符串。每个字符串由N个字符组成;每个字符都是{A - “缺席”,L - “迟到”和O - “确定”之一。如果有两个“缺席”或三个随后的“迟到”,系统会发出警报。例如:AOOAO - 引发警报,ALLOL - 没有。

编写一个函数(用Java编写)来生成所有大小为N的字符串,这会引发警报。

我建议循环遍历所有可能的“工作历史”字符串(很明显如何生成它们)并使用正则表达式过滤所需的字符串。

你会如何解决这个问题?

3 个答案:

答案 0 :(得分:4)

这将是一种智能方法,不会检查任何内容,但只能直接生成正确的案例:

  1. 使用N-2天(即3 ^(N-2)组合)进行所有可能的变化。对于如此获得的每个变体,通过在每个可能的位置拼接“AA”来制作N-1个最终字符串(加上简单地附加在最后,这就是为什么它是N-1)。

  2. 重复N-3天并拼接“LLL”。

  3. 你们已经完成了。

  4. 修改

    现在我看到缺席不需要连续。这稍微改变了解决方案:在第一种情况下,你将独立地拼接两个“A”,首先拼接一个,然后将另一个拼接成结果字符串。

    编辑2

    有一个非常对称的附加检查,可以在拼接时避免重复。在这两个步骤中,检查插入点左侧的字符。在步骤1中,如果它是A,则停止当前的拼接迭代(这也控制第二个A的拼接)。在步骤2中,如果它是L,则转到下一个插入点(跳过当前插入点)。

答案 1 :(得分:1)

这是一个类似于蛮力的解决方案,除了一些优化。我们的想法是创建所有可能序列的组合(由于必须返回警报字符串,因此无需额外费用)。然后跟踪报警条件(绝对没有正则表达式),以便只需要检查当前字符(参见#2)。一旦子字符串引发了警报,让我们说位置i,该函数可以继续为n-i字符创建组合而不检查警报条件。

  1. 创建一个char数组,大小为N,以及一个计算组合的函数(3^N)。
  2. 创建一个变量numLate,它将跟踪到目前为止系列中的连续'L'和变量numAbsences,它将跟踪系列中的'A'数量,以便远。
  3. 在组合过程中的每个步骤中,请检查以下内容:
    • 如果已找到匹配项(match == true),请继续。
    • 否则:
      • 检查当前字符是否为“A”,如果是,则增加numAbsences。如果numAbsences > 1,请设置match = true。继续。
      • 如果当前字符为“L”增量numLate,则设置为numLate = 0。如果numLate > 2,请设置match = true。继续。
  4. 在组合期间,当设置第N个字符时,如果match==true返回当前字符串。否则,跳过,它不匹配。如果您在最后一个角色上并且到目前为止已经有0个缺席,则可以通过不检查缺席来进行额外(次要)优化。或者在组合的最后2个字符中,已经有0个晚了。

    编辑:我发布了一个递归(groovy)解决方案。例如,Test.combination(0, new char[10], false, 0, 0);会返回55513个组合,但不确定它是否正确。

    class Test{
        public static final char[] rep = ['O', 'A', 'L'];
    
        public static void combination(int index, char[] arr, boolean match, int numLate, int numAbsence){
            if(index==arr.length){
                if(match)
                    println arr;
                return;
            }
            for(int i=0;i<rep.length;i++){
                arr[index] = rep[i];
                if(!match){
                    boolean tempMatch = match;
                    int tempNumLate = numLate;
                    int tempNumAbsence = numAbsence;
                    switch(arr[index]){
                        case 'L': tempNumLate++; break;
                        case 'A': tempNumAbsence++; tempNumLate=0; break;
                        default: tempNumLate = 0; break;
                    }
                    if(tempNumLate > 2)
                        tempMatch = true;
                    if(tempNumAbsence > 1)
                        tempMatch = true;
    
                    combination(index+1, arr, tempMatch, tempNumLate, tempNumAbsence);
                }else{
                    combination(index+1, arr, match, numLate, numAbsence);
                }
            }
        }
    }
    

答案 2 :(得分:1)

对于完全不同的东西,这里有一种方法可以生成所需的字符串,而不是其他任何东西。将其视为状态机,并使每个状态成为一个函数。非常冗长但直截了当。 (如果你做了很多这样的事情,你可以很容易地安排自动生成这段代码。)

因为我们被要求使用Java,所以这里是Java。 (我也在Perl中编写了相同的代码。我只是为.=chop编写了一个字符串而不是StringBuilder,它的运行速度比Java版快3倍。奇怪。)

import java.io.*;

public class ListAllAlarmedStrings {
    static StringBuilder builder;
    static int length;

    public static void main(String[] args) throws IOException {
        length = 5;
        if (args.length > 0) {
            try {
                length = Integer.parseInt(args[0]);
            } catch (NumberFormatException e) {
                System.err.println("Argument" + " must be an integer");
                System.exit(1);
            }
        }
        builder = new StringBuilder(length);
        for (int i = 0; i < length; i++)
          builder.append("O");
        stateA(0, 'A');
        stateL(0, 'L');
        stateNone(0, 'O');
    }

    static void stateNone (int pos, char chr) {
        if (length < pos + 3)
            return;
        builder.setCharAt(pos, chr);
        //System.out.println("stateNone " + pos + " " +builder.toString());
        stateA(pos + 1, 'A');
        stateL(pos + 1, 'L');
        stateNone(pos + 1, 'O');
    }

    static void stateL (int pos, char chr) {
        if (length < pos + 3)
            return;
        builder.setCharAt(pos, chr);
        //System.out.println("stateL " + pos + " " +builder.toString());
        stateA(pos + 1, 'A');
        stateLL(pos + 1, 'L');
        stateNone(pos + 1, 'O');
    }

    static void stateLL (int pos, char chr) {
        if (length < pos + 2)
            return;
        builder.setCharAt(pos, chr);
        //System.out.println("stateLL " + pos + " " +builder.toString());
        stateA(pos + 1, 'A');
        stateAlarmed(pos + 1, 'L');
        stateNone(pos + 1, 'O');
    }

    static void stateA (int pos, char chr) {
        if (length < pos + 2)
            return;
        builder.setCharAt(pos, chr);
        //System.out.println("stateA " + pos + " " +builder.toString());
        stateAlarmed(pos + 1, 'A');
        stateAL(pos + 1, 'L');
        stateA(pos + 1, 'O');
    }

    static void stateAL (int pos, char chr) {
        if (length < pos + 2)
            return;
        builder.setCharAt(pos, chr);
        //System.out.println("stateAL " + pos + " " +builder.toString());
        stateAlarmed(pos + 1, 'A');
        stateALL(pos + 1, 'L');
        stateA(pos + 1, 'O');
    }

    static void stateALL (int pos, char chr) {
        if (length < pos + 2)
            return;
        builder.setCharAt(pos, chr);
        //System.out.println("stateALL " + pos + " " +builder.toString());
        stateAlarmed(pos + 1, 'A');
        stateAlarmed(pos + 1, 'L');
        stateA(pos + 1, 'O');
    }

    static void stateAlarmed (int pos, char chr) {
        if (length <= pos)
            return;
        if (length == pos + 1) {
            builder.setCharAt(pos, chr);
            System.out.println(builder.toString());
            return;
        }
        builder.setCharAt(pos, chr);
        stateAlarmed(pos + 1, 'A');
        stateAlarmed(pos + 1, 'L');
        stateAlarmed(pos + 1, 'O');
    }
}