2

I've been using regex to solve the "Broken Necklace" problem at USACO. While it works fine for smaller inputs, albeit a very complicated regex expression, it exceeds the given time limit for larger inputs.

For further input, here is the code I used. My question is on how I could improve the runtime while still using regex.

All help is greatly appreciated. I'm a total newbie to competitive programming and am really stuck:s!

class beads {

    public static void main(String[] args) throws IOException{
        BufferedReader f = new BufferedReader(new FileReader("beads.in"));
        //BufferedReader f = new BufferedReader(new FileReader("beads.txt"));
        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("beads.out")));

        int numBeads=Integer.parseInt(f.readLine());
        String input=f.readLine();
        String beadSequence=input.concat(input);

        Pattern p1=Pattern.compile("^(w*r*)|^(w*b*)*");
        Matcher m1=p1.matcher(input);


        while(m1.find()){
            String k=m1.group();
            //System.out.println(k);
            if(k.length()==numBeads){
                out.println(k.length());
                out.close();
                System.exit(0);
            }
        }


        //System.out.println(input);
        //System.out.println(beadSequence);
        Pattern p=Pattern.compile("(?=((b*w*)*b+w*r+(w*r*)*|(r*w*)*r+w*b+(w*b*)*))(^|(?<=w)b|(?<=b)w|(?<=w)r|(?<=r)w)");

        Matcher m=p.matcher(beadSequence);


        List<String> solutions=new ArrayList<String>();
        int length=0;

        while(m.find()){

            String k=m.group(1);
            //System.out.println(m.group(1));
            if (k.length()>length)length=k.length();
        }


       out.println(length);

        out.close();                                 
        System.exit(0);  
    }
}
1
  • 1
    Looks like you need to use basic String manipulation here. Commented Mar 31, 2013 at 16:56

2 Answers 2

2

Stuff like (b*w*)* does have many possibilities to match a sequence of "b" and "w" this will lead to catastrophic backtracking.

Because this will match any sequence of those two letters it would be better to replace it with a character class [bw]*.

So your expression would look something like this:

Pattern p=Pattern.compile("(?=([bw]*b+w*r+[rw]*|[rw]*r+w*b+[bw]*))(^|(?<=w)b|(?<=b)w|(?<=w)r|(?<=r)w)");

This expression should match a lot quicker.

Sign up to request clarification or add additional context in comments.

1 Comment

It indeed does and passed the test! Its a really valuable technique. Thank you!
0

There is a much simpler regular expression than the ones given so far

(?=([bw]*b+[rw]*|[rw]*r+[bw]*)).

You can see a really nice visualization of your algorithm on debuggex. Slide the black triangle along the test string and keep your eye on the group 1 match. This is what your algorithm is looking at to determine the length. Note that the example string has already been concatenated to itself so that the endpoints work.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.