在模式中找出奇数字符


20

输入值

第一行将是重复一定次数的某个字符串。例如,它可以是abcabcabcabc[];[];[];等。例如:1231231231。总是找到最短的字符串;例如,如果该行是22222,则该字符串是2,不是2222222或其他任何字符串。该字符串将始终重复至少2次。

所有后续行将是该模式偏移任何数字。例如,可能是:

abcabcabc
cabcabcab
bcabcabca

(偏移1),或者可能是:

abcdefabcdefabcdefabc
cdefabcdefabcdefabcde
efabcdefabcdefabcdefa

(偏移量为4)。

输入中的字符之一将是错误的。(保证不在第一行。)例如,在此输入中:

a=1a=1a=1
=1a=1a=1a
1a=11=1a=
a=1a=1a=1
=1a=1a=1a

1第3行是奇数一个出来。

输出量

您必须输出奇数之一的(从左上角开始,从零开始)。例如,在上述输入中,对应的输出为4,2。您也可以输出4 2,或"4""2"什至[[4],[2]]或任何其他格式,只要您可以知道输出应该是什么即可。

测试用例

输入:

codegolfcodegolfco
egolfcodegolfcodeg
lfcodegolfcodegoff
odegolfcodegolfcod
golfcodegolfcodego
fcodegolfcodegolfc

输出: 16,2

输入:

][[][][[][][[][][[][][[
[][][[][][[][][[][][[][
[][[][][[][][[][][[][][
[[][][[]]][[][][[][][[]

输出: 8,3

输入:

...
. .
...

输出: 1,1

输入:

ababa
babab
ababb
babab

输出: 4,2

走!


字符串中可以包含哪些字符?可打印的ASCII吗?ASCII?Unicode?
丹尼斯

@Dennis只是可打印的ASCII(对于涉及字符串的任何挑战,基本上都可以假定为ASCII;否则,对于几乎所有挑战,我们都必须指定它:P)
Doorknob

我猜是这样。我正在考虑一种需要使用未使用的char的方法,所以我想问一下。
丹尼斯

我们是否应该检查这种情况:abc/cab/abc-并0 2在此处输出?
user2846289 2014年

@VadimR不,因为只有一个字符是错误的。
门把手

Answers:


7

Bash Perl,231 229 218 178 164 166 138 106 74字节

/^(((.*).*)\2+)\3$/;$_.=$1x2;$.--,die$+[1]if/^(.*)(.)(.*)
.*\1(?!\2).\3/

该脚本需要使用-n开关,该开关占两个字节。

MT0的答案中提出了将模式的所有完整重复附加两个副本的想法。

与所有其他答案相反,此方法尝试在每次迭代中提取当前输入线的模式;它将在包含奇数字符的行上失败(并改用前一行的模式)。这样做是为了将模式提取包括在循环中,从而节省了一些字节。

非高尔夫版本

#!/usr/bin/perl -n

# The `-n' switch makes Perl execute the entire script once for each input line, just like
# wrapping `while(<>){…}' around the script would do.

/^(((.*).*)\2+)\3$/;

# This regular expression matches if `((.*).*)' - accessible via the backreference `\2' -
# is repeated at least once, followed by a single repetition of `\3" - zero or more of the
# leftmost characters of `\2' - followed by the end of line. This means `\1' will contain
# all full repetitions of the pattern. Even in the next loop, the contents of `\1' will be
# available in the variable `$1'.

$_.=$1x2;

# Append two copies of `$1' to the current line. For the line, containing the odd
# character, the regular expression will not have matched and the pattern of the previous
# line will get appended.
#
# Since the pattern is repeated at least two full times, the partial pattern repetition at
# the end of the previous line will be shorter than the string before it. This means that
# the entire line will the shorter than 1.5 times the full repetitions of the pattern, 
# making the two copies of the full repetitions of the pattern at least three times as 
# long as the input lines.

$.-- , die $+[1] if

# If the regular expression below matches, do the following:
#
#   1. Decrement the variable `$.', which contains the input line number.
#
#      This is done to obtain zero-based coordinates.
#
#   2. Print `$+[1]' - the position of the last character of the first subpattern of the
#      regular expression - plus some additional information to STDERR and exit.
#
#      Notably, `die' prints the (decremented) current line number.

/^(.*)(.)(.*)
.*\1(?!\2).\3/;

# `(.*)(.)(.*)', enclosed by `^' and a newline, divides the current input line into three
# parts, which will be accesible via the backreferences `\1' to `\3'. Note that `\2'
# contains a single character.
#
# `.*\1(?!\2).\3' matches the current input line, except for the single character between
# `\1' and `\3' which has to be different from that in `\2', at any position of the line
# containing the pattern repetitions. Since this line is at least thrice as long as
# `\1(?!\2).\3', it will be matched regardless of by how many characters the line has been
# rotated.

对于测试用例

codegolfcodegolfco
egolfcodegolfcodeg
lfcodegolfcodegoff
odegolfcodegolfcod
golfcodegolfcodego
fcodegolfcodegolfc

高尔夫版本的输出是

16 at script.pl line 1, <> line 2.

表示奇数字符具有坐标16,2

这种公然的滥用利用了自由输出格式。

在退出之前,Perl的一些特殊变量的内容是:

$_  = lfcodegolfcodegoff\ncodegolfcodegolfcodegolfcodegolf
$1  = lfcodegolfcodego
$2  = f
$3  = f

$n包含可通过向后引用访问的子模式的匹配\n。)


巧妙捕捉回复单元。可以将其优化一个字节:^((.*?)(.*?))(?=\1+\2$)
Heiko Oberdiek 2014年

我改用了流行孩子使用的语言。可以进一步打下去;这是我十多年来的第一个Perl脚本...
丹尼斯

2
...如果您认为perl是受欢迎的孩子正在使用的东西,那么您已经晚了十年
ardnew 2014年

这个答案并没有得到应有的爱。在我看来就像赢家@Doorknob
ardnew 2014年

8

Perl中,212个 191 181 168字节

$_=<>;/^(((.*?)(.*?))\2+)\3$/;$x=$1x4;while(<>){chop;$x=~/\Q$_\E/&&next;for$i(0..y///c-1){for$r(split//,$x){$b=$_;$b=~s/(.{$i})./$1$r/;$x=~/\Q$b\E/&&die$i,$",$.-1,$/}}}
  • 该版本使用了优化的技巧来捕获回复单元,这是从丹尼斯的答案中学到的。
  • 通过使用所有行的长度相等的属性进行优化。
  • 还需要最后一行行结束,否则chomp不是chop应该被使用。
  • 优化了ardnew的注释

旧版本,212个字节:

$_=<>;chop;/^(.+?)\1+(??{".{0,".(-1+length$1).'}'})$/;$;=$1;while(<>){$x=$;x length;chop;$x=~/\Q$_\E/&&next;for$i(0..-1+length$_){for$r(split//,$;){$b=$_;$b=~s/(.{$i})./$1$r/;$x=~/\Q$b\E/&&exit print$i,$",$.-1}}}

非高尔夫版本:

$_ = <>;  # read first line
/^(((.*?)(.*?))\2+)\3$/;
# The repeat unit \2 consists of \3 and \4,
# and the start part \2 can be added at the end (as partial or even full unit).
$x = $1 x 4; # $x is long enough to cover each following line

# Old version:
# /^(.+?)\1+(??{ ".{0," . (-1 + length $1) . '}' })$/;
# $a = $1; # $a is the repeat unit.
# The unit is caught by a non-greedy pattern (.+?) that is
# repeated at least once: \1+
# The remaining characters must be less than the unit length.
# The unit length is known at run-time, therefore a "postponed"
# regular expression is used for the remainder.

# process the following lines until the error is found
while (<>) {
    # old version:
    # $x = $a x length;
    # $x contains the repeated string unit, by at least one unit longer
    # than the string in the current line
    chop; # remove line end of current line
    $x =~ /\Q$_\E/ && next;
          # go to next line, if current string is a substring of the repeated units;
          # \Q...\E prevents the interpretation of special characters
    # now each string position $x is checked, if it contains the wrong character:
    for $i (0 .. y///c - 1) {  # y///c yields the length of $_
        for $r (split //, $x) { #/ (old version uses $a)
            # replace the character at position $i with a
            # character from the repeat unit
            $b = $_;
            $b =~ s/(.{$i})./$1$r/;
            $x =~ /\Q$b\E/
               && die $i, $", $. - 1, $/;
               # $" sets a space and the newline is added by $/;
               # the newline prevents "die" from outputting line numbers
        }
    }
}

很棒的解决方案和评论,我需要学习更多正则表达式;)
Newbrict 2014年

1
首先chop是不必要的-应该删除。最终版本exit print可以替换为die(添加,$/以隐藏多余的内容(如果需要))。也length$_可以替换为y///c
ardnew 2014年

@ardnew:非常感谢,我删除了first chop,因为$在字符串末尾的换行符之前有匹配项。隐藏对die通过添加的换行符的额外的东西对我来说似乎是必要的。也比没有不必要的y///c要短很多length$_,比一个字节要短一个字节。length$_
Heiko Oberdiek 2014年

1
@ardnew:我忘记了die的冗长。它甚至包括打印行号!我将在下次更新中使用它。
丹尼斯

3

C,187字节

局限性。

  • 不要使用超过98个字符的输入字符串:)

高尔夫版

char s[99],z[99],*k,p,i,I,o,a;c(){for(i=0;k[i]==s[(i+o)%p];i++);return k[i];}main(){for(gets(k=s);c(p++););for(;!(o=o>p&&printf("%d,%d\n",I,a))&&gets(k=z);a++)while(o++<p&&c())I=I<i?i:I;}

非高尔夫版本

char s[99],z[99],*k,p,i,I,o,a;

c()
{
    for(i=0
       ;k[i]==s[(i+o)%p]
       ;i++)
       ;
    return k[i];
}

main()
{
    for(gets(k=s);c(p++);)
         ;
    for(;!(o=o>p&&printf("%d,%d\n",I,a)) && gets(k=z);a++)
           while(o++ < p && c())
            I=I<i?i:I;
}

2

Python中,303 292

r=raw_input
R=range
s=r()
l=len(s)
m=1
g=s[:[all((lambda x:x[1:]==x[:-1])(s[n::k])for n in R(k))for k in R(1,l)].index(True)+1]*l*2
while 1:
 t=r()
 z=[map(lambda p:p[0]==p[1],zip(t,g[n:l+n]))for n in R(l)]
 any(all(y)for y in z)or exit("%d,%d"%(max(map(lambda b:b.index(False),z)),m))
 m+=1

输入通过标准输入。如果有需求,我会解释,但无论如何我似乎都不会赢。


1

Perl中,157 154

编辑:-3感谢ardnew'的建议。

<>=~/^(((.*?).*?)\2+)\3$/;$p=$2;$n=$+[1];while(<>){s/.{$n}/$&$&/;/(\Q$p\E)+/g;$s=$p;1while/./g*$s=~/\G\Q$&/g;print$n>--($m=pos)?$m:$m-$n,$",$.-1,$/if pos}

我花了一些时间(开和关,当然不是5天;-)),关于算法的想法起初是难以捉摸的(尽管我觉得它在那里),但最终(突然)一切都变得清晰了。

如果字符串长度是模式长度的倍数,并且即使字符串不是以模式的开头开头,那么将字符串与自身连接起来将产生模式以代替串联(想象在圆带上无限重复一个单词-位置焊接并不重要)。因此,其想法是将线修剪为多个单位长度,然后将其连接起来。即使对于包含错误字符的字符串,结果也保证至少匹配一次模式。从那里很容易找到冒犯角色的位置。

第一行从Heiko Oberdiek的答案中无耻地借来了:-)

<>=~/^(((.*?).*?)\2+)\3$/;      # Read first line, find the repeating unit
$p=$2;                          # and length of whole number of units.
$n=$+[1];                       # Store as $p and $n.
while(<>){                      # Repeat for each line.
    s/.{$n}/$&$&/;              # Extract first $n chars and
                                # append original line to them.
    /(\Q$p\E)+/g;               # Match until failure (not necessarily from the
                                # beginning - doesn't matter).
    $s=$p;                      # This is just to reset global match position
                                # for $s (which is $p) - we could do without $s,
                                # $p.=''; but it's one char longer.
                                # From here, whole pattern doesn't match -
    1while/./g*$s=~/\G\Q$&/g;   # check by single char.
                                # Extract next char (if possible), match to 
                                # appropriate position in a pattern (position 
                                # maintained by \G assertion and g modifier).
                                # We either exhaust the string (then pos is 
                                # undefined and this was not the string we're
                                # looking for) or find offending char position.

    print$n>--($m=pos)?$m:$m-$n,$",$.-1,$/if pos
}

1
做得好。我认为您可以替换/.{$n}/;$_=$&.$_;s/.{$n}/$&$&/;
ardnew 2014年

1

的JavaScript(ES6) - 147个 133 136特性

s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

期望要测试的字符串在变量中,s然后将结果输出到控制台。

var repetitionRE = /^(((.*).*)\2+)\3\n/;
                                        // Regular expression to find repeating sequence
                                        // without any trailing sub-string of the sequence.
var sequence = repetitionRE.exec(s)[1]; // Find the sequence string.
s.split('\n')                           // Split the input into an array.
 .map(
   ( row, index ) =>                    // Anonymous function using ES6 arrow syntax
   {
     var testStr = row + '᛫'+ sequence + sequence;
                                        // Concatenate the current row, a character which won't
                                        // appear in the input and two copies of the repetitions
                                        // of the sequence from the first line.
     var match = /^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(testStr);
                                        // Left of the ᛫ finds sub-matches for a single
                                        // character and the sub-strings before and after.
                                        // Right of the ᛫ looks for any number of characters
                                        // then the before and after sub-matches with a
                                        // different character between.
      if ( match )
       console.log( match[1].length, index );
                                        // Output the index of the non-matching character
                                        // and the row.
   }         
 );

测试用例1

s="codegolfcodegolfco\negolfcodegolfcodeg\nlfcodegolfcodegoff\nodegolfcodegolfcod\ngolfcodegolfcodego\nfcodegolfcodegolfc"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

产出

16 2

测试案例2

s="][[][][[][][[][][[][][[\n[][][[][][[][][[][][[][\n[][[][][[][][[][][[][][\n[[][][[]]][[][][[][][[]"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

产出

8 3

测试案例3

s="...\n. .\n..."
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

产出

1 1

测试案例4

s="ababa\nbabab\nababb\nbabab"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

产出

4 2

测试案例5

s="xyxy\nyyxy"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

产出

0 1

测试案例6

s="ababaababa\nababaaaaba"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

产出

6 1

可悲的是,如果,例如,该方法将失败s="xyxy\nyyxy"。对于第二行,match[4]将为yy; 应该是公正的y
丹尼斯

重新设计并缩短了14个字符。
MT0

非常好!我曾经在同一点尝试过相同的第二个正则表达式,但是我将最小模式两次而不是最大模式附加两次(因此失败了,惨不忍睹)。一个小问题:第一个正则表达式将报告ababast模式ababaababa;您需要使用^…$
丹尼斯

/^…\n/作品或/^…$/m
MT0

1
它可能不需要引导符^(至少对于我列出的6个测试用例而言,不需要它-但可能有一个相反的示例,因此我将其保留了下来)。
MT0
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.