第二个非重复字符是什么?


18

基于代码审查中的这个问题

给定一个可打印的ASCII字符的非空字符串,输出第二个非重复字符。例如,对于input DEFD,output F

输入值

输出量

  • 从左到右读取时,第二个不会重复的字符也将以适当的格式显示。
  • 输出字符不区分大小写。
  • 如果不存在这样的字符(例如,所有字符都重复),则输出一个空字符串。

规则

  • 该算法应忽略大小写。也就是说,Dd算作相同的字符。
  • 完整的程序或功能都是可以接受的。
  • 输入字符串将被保证为非空(即,至少一个字符的长度)。
  • 输入字符串为ASCII。任何有效字符都可以重复,而不仅仅是字母数字(包括空格)。
  • 禁止出现标准漏洞
  • 这是因此所有常见的高​​尔夫规则都适用,并且最短的代码(以字节为单位)获胜。

例子

输入在第一行,输出在第二行。

DEFD
F

FEED
D

This is an example input sentence.
x

...,,,..,,!@
@

ABCDefgHijklMNOPqrsTuVWxyz
B

AAAAAABBBBB


Thisxthis


This this.
.

8
如果它不区分大小写,我会考虑在Forth中进行。但是,字符串操作会吸收这种语言。
mbomb007 '16

如果我的语言不支持小写字母怎么办?
亚当

@Adám是否使用其他代码页?如果不支持小写字母,通常如何输入ASCII字符串?
AdmBorkBork '16

1
我想到的系统有7位代码页;修改后的标准代码页,其中大写字母占据小写字母的位置,大写字母的位置用于字形。这是在旧的APL系统上完成的,因此可以使用Shift来访问APL字形,而未移位的字母是经典的编码样式大写字母。
ADAM

Answers:


10

MATL,11个字节

tk&=s1=)FT)

如果没有第二个非重复字符,则会退出并显示错误(默认情况下允许)。

在线尝试!

说明

t      % Implicitly take input string. Duplicate
k      % Convert to lowercase
&=     % 2D array of equality comparisons
s      % Sum of each column
1=     % True for entries that equal 1
)      % Apply logical index to the input string to keep non-repeated characters
TF)    % Apply logical index to take 2nd element if it exists. Implicitly display 

忍者编辑再次罢工。:P
丹尼斯

@丹尼斯·哈哈哈 好吧,我想您会很快删除几个字节
Luis Mendo

10

视网膜,25字节

i!2=`(.)(?<!\1.+)(?!.*\1)

在线尝试!(第一行允许在包含多个输入的测试套件上运行代码。)

说明

这只是一个正则表达式匹配项,正则表达式为:

(.)(?<!\1.+)(?!.*\1)

也就是说,匹配一个字符并确保它不会出现在输入中的其他任何地方。剩下的就是配置:

  • i 激活不区分大小写。
  • ! 告诉Retina打印匹配项而不是计数匹配项。
  • 2= 告诉视网膜只打印第二场比赛,而不是全部。

1
啊,谢谢您教我有关2=
Leaky Nun

6

05AB1E,15 12字节

l©v®y¢iy}}1@

讲解

l©            # store lower case string in register
  v     }     # for each char in lower case string
   ®y¢iy      # if it occurs once in string, push it to stack
         }    # end if
          1@  # push the 2nd element from stack and implicitly display

在线尝试

@Adnan节省了3个字节


或为12个字节l©v®y¢iy}}1@:)。
阿德南

@Adnan:太好了!没想到使用@。
Emigna '16


5

果冻,11 字节

Œlµḟœ-Q$Ḋḣ1

在线尝试!验证所有测试用例

怎么运行的

Œlµḟœ-Q$Ḋḣ1  Main link. Argument: s (string)

Œl           Convert s to lowercase.
  µ          Begin a new, monadic chain. Argument: s (lowercase string)
       $     Combine the two links to the left into a monadic chain.
      Q        Unique; yield the first occurrence of each character.
    œ-         Perform multiset subtraction, removing the last occurrence of each
               character.
   ḟ         Filterfalse; keep characters that do not appear in the difference.
        Ḋ    Dequeue; remove the first character.
         ḣ1  Head 1; remove everything but the first character.

4

批处理,171字节

@echo off
set a=.
set s=%~1
:l
if "%s%"=="" exit/b
set c=%s:~0,1%
call set t=%%s:%c%=%%
if "%s:~1%"=="%t%" set a=%a%%c%
set s=%t%
if "%a:~2%"=="" goto l
echo %c%

备用公式,也为171个字节:

@echo off
set a=.
set s=%~1
:l
if "%s%"=="" exit/b
set c=%s:~0,1%
set t=%s:~1%
call set s=%%s:%c%=%%
if "%s%"=="%t%" set a=%a%%c%
if "%a:~2%"=="" goto l
echo %c%

无法使其在W2008R2上运行。行“ call set ...”扩展为“ call set t =%s:D =%”,并中止“命令语法不正确”消息。
默登

@meden对不起,我的帖子里有些错字。死亡的礼物是那个职位比我说的要短!现在已修复。
尼尔

3

Pyth,16 15字节

1字节感谢@ mbomb007

= rz1.xhtfq1 / zTzk
= rz1:fq1 / zTz1 2

测试套件。


2
我什至不认识Pyth,但如果您这么说。:D
mbomb007 '16

@ mbomb007你知道的[1:2]把戏。
Leaky Nun

您可以使用t<…2代替来保存一个字节:…1 2=rz1如果您也将更1改为Z(小写而不是大写),则可以将移至第一次使用来保存另一个字节:t<fq1/zT=rzZ2
安德斯·卡塞格

3

其实是19个位元组

;╗`ù╜ùc1=`░ε;(qq1@E

在线尝试!

说明:

;╗`ù╜ùc1=`░ε;(qq1@E
;╗                   push a copy of input to reg0
  `ù╜ùc1=`░          [v for v in s if
   ù╜ùc1=              s.lower().count(v.lower()) == 1]
           ε;(qq     append two empty strings to the list
                1@E  element at index 1 (second element)

3

C#,129128字节

char c(string i){var s=i.Where((n,m)=>i.ToLower().Where(o=>o==Char.ToLower(n)).Count()<2).ToArray();return s.Length>1?s[1]:' ';}

工作良好。我希望我不需要将所有内容都小写


当我将“ Thisxthis”作为参数传递时,引发IndexOutOfRangeException。除此之外,我认为== 1可以更改为<2。
Yytsi '16


2

C#,141个字节

void p(){var x=Console.ReadLine().ToLower();var c=0;foreach(char i in x){if(x.Split(i).Length-1<2){if(++c==2){Console.WriteLine(i);break;}}}}

不间断(最小),135个字节

void p(){var x=Console.ReadLine().ToLower();var c=0;foreach(char i in x){if(x.Split(i).Length-1<2){if(++c==2){Console.WriteLine(i);}}}}

使用for(;;),150个字节

void p(){for(;;){var x=Console.ReadLine().ToLower();var c=0;foreach(char i in x){if(x.Split(i).Length-1<2){if(++c==2){Console.WriteLine(i);break;}}}}}

取消评论

void p()
{
    var x=Console.ReadLine().ToLower();//Get lowercase version of input from STDIN
    var c=0; //Create "count" integer
    foreach(char i in x){//For each char in input from STDIN
        if(x.Split(i).Length-1<2)//If current char occurs once in input from STDIN
        {
            if(++c==2){ //Add 1 to count and if count is 2
                Console.WriteLine(i); //Print result to STDOUT
                break; //Exit foreach
            } //End of IF
         } //End of IF
     } //End of FOREACH
} //End of VOID

TuukkaX保存了12个字节(将计数更改为c)。

TuukkaX保存了3个字节(将字符串更改为var)。

TuukkaX在“ With for(;;)”中保存了4个字节(while(true)更改为for(;;))。

TuukkaX保存2个字节(将c ++; if(c == 2)更改为if(++ c == 2))。

Bryce Wagner保存了14个字节(将x.ToCharArray()更改为x)。


@TuukkaX哦,真的。谢谢!
r3pear16年

欢迎来到PPCG!那是一篇不错的第一篇文章!由于规则提到对这个问题的答案应该是函数还是完整程序,因此您的代码几乎不需要进行任何调整。您还可以通过使用var代替string和拥有类似c代替来保存字节count
Yytsi '16

@TuukkaX再次感谢您!不久,我将修改代码并将字符串更改为var。
r3pear16年

@TuukkaX是否应该添加诸如void program(){}的内容????
r3pear16年

是的,但是给一个字节的函数名来保存字节!:)
Yytsi '16

2

x86机器码,43个字节

十六进制:

FC31C031C95641AC84C0740E3C6172F63C7A77F28066FFDFEBEC5EAC49740B89F751F2AE5974F44A77F1C3

函数将指针指向(E)SI中的输入字符串,并指向(E)DX中的整数,并返回第(E)DX个非重复字符,如果没有这样的字符,则返回零。作为副作用,它将字符串转换为大写。

拆卸:

fc             cld
31 c0          xor    eax,eax
31 c9          xor    ecx,ecx
56             push   esi
_loop0:                         ;Search for the NULL char,
41             inc    ecx       ;counting the length in the process
ac             lodsb
84 c0          test   al,al
74 0e          je     _break0   ;NULL found, break
3c 61          cmp    al,0x61   ;If char is
72 f6          jb     _loop0    ;between 'a' and 'z'
3c 7a          cmp    al,0x7a   ;convert this char
77 f2          ja     _loop0    ;to uppercase in-place
80 66 ff df    and    byte ptr [esi-0x1],0xdf
eb ec          jmp    _loop0
_break0:
5e             pop    esi       ;Reset pointer to the string
_loop:                          ;ECX=string length with NULL
ac             lodsb            ;Load next char to AL
49             dec    ecx
74 0b          je     _ret      ;End of string found, break (AL==0)
89 f7          mov    edi,esi   ;EDI points to the next char
51             push   ecx
f2 ae          repnz scasb      ;Search for AL in the rest of the string
59             pop    ecx
74 f4          je     _loop     ;ZF==1 <=> another instance found, continue
4a             dec    edx
77 f1          ja     _loop     ;If not yet the EDX-th non-rep char, continue
_ret:
c3             ret

2

APL,32字节

{⊃1↓⍵/⍨1=+/∘.=⍨(⎕UCS ⍵)+32×⍵∊⎕A}

试试看 || 所有测试用例

说明:

                (⎕UCS ⍵)+32×⍵∊⎕A  Add 32 to uppercase letters
            ∘.=⍨                    Make an equality matrix
          +/                        Check how many matches
    ⍵/⍨1=                           Keep elements with 1 match
  1↓                                Drop the first one
⊃                                   Return the second one

我本来打算用16个字节来发布它,但是我意识到它必须不区分大小写...


1
(⎕UCS ⍵)+32×⍵∊⎕A819⌶⍵
亚当

我以前从未见过那个运算符。它在什么版本中工作?
Woofmao

它称为电子束。它是Dyalog APL所有版本中的运算符。它最初是IBM APL的旧版本中的功能,用于对IBM系统的特殊调用。得到它?IBM —电子束
亚当

一般性文件和服务性文件819(“ 819”≈“ BIg”)。在线尝试!
亚当

好吧,我学到了一些新东西。tryapl.org似乎无法识别它,所以您介意我仅使用您的TIO链接吗?
Woofmao


1

Mathematica,49个字节

Cases[Tally@ToUpperCase@#,{_,1}][[2,1]]~Check~""&

匿名函数。将字符列表作为输入。忽略生成的任何错误。


1

JavaScript(Firefox 48或更早版本),60字节

f=s=>(m=s.match(/(.).*\1/i))?f(s.replace(m[1],"","gi")):s[1]

返回undefined如果只有零个或一个不重复的字符。通过不区分大小写的方式删除字符串中出现多次的所有出现的字符。依赖于非标准的Firefox扩展,在火狐49取出119 91字节ES6版本:

f=s=>(m=s.match(/(.).*?(\1)(.*\1)?/i))?f((m[3]?s:s.replace(m[2],"")).replace(m[1],"")):s[1]

递归搜索字符串中至少出现两次的所有字符。如果角色正好出现两次,则两次出现都将被删除,否则只会删除第一次出现(稍后将删除其他出现)。这使得出现的情况有所不同。


我相信,你其实可以通过更换适应你的Firefox 48的回答是ES6兼容m[1]new RegExp(`${m[1]}`,"gi")
价值油墨

@ KevinLau-notKenny这对特殊字符不起作用,不幸的是,我花了33个字节来对它们进行特殊处理,这使我最多需要93个字节。
尼尔

noooooo不是特殊字符!现在,我还必须编辑我的Ruby答案以适应他们。
价值墨水

1

J,25个字节

(1{2{.]-.]#~1-~:)@tolower

用法

   f =: (1{2{.]-.]#~1-~:)@tolower
   f 'DEFD'
f
   f 'FEED'
d
   f 'This is an example input sentence.'
x
   f '...,,,..,,!@'
@
   f 'ABCDefgHijklMNOPqrsTuVWxyz'
b
   f 'AAAAAABBBBB'

   f 'Thisxthis'

   f 'This this.'
.

说明

(1{2{.]-.]#~1-~:)@tolower  Input: s
                  tolower  Converts the string s to lowercase
              ~:           Mark the indices where the first time a char appears
            1-             Complement it
         ]                 Identity function to get s
          #~               Copy only the chars appearing more than once
      ]                    Identity function to get s
       -.                  Remove all the chars from s appearing more than once
   2{.                     Take the first 2 chars from the result (pad with empty string)
 1{                        Take the second char at index 1 and return it

1

Bash,58个字节

tr A-Z a-z>t
tr -dc "`fold -1<t|sort|uniq -u`"<t|cut -c2

警告:这将创建一个名为t的临时文件。如果已经存在,它将被覆盖。


1

C,174字节

int c(char*s){int y=128,z=256,c[384],t;memset(c,0,z*6);for(;t=toupper(*s);s++){c[t]++?c[t]-2?0:c[z+(c[y+c[z+t]]=c[y+t])]=c[z+t]:c[z]=c[y+(c[z+t]=c[z])]=t;}return c[y+c[y]];}

这不是最短的,而是相当有效的实现。本质上,它使用双向链接列表来维护候选字符的有序集合,并仅扫描一次输入字符串。返回字符代码,如果找不到则返回零。

一点点高尔夫版本:

int c(char*s)
{
    int y=128,z=256,c[384],t;
    //It's basically c[3][128], but with linear array the code is shorter

    memset(c,0,z*6);

    for(;t=toupper(*s);s++)
    {
        c[t]++ ?        // c[0][x] - number of char x's occurrence
            c[t] - 2 ?  // > 0
                0       // > 1 - nothing to do  
                : c[z + (c[y + c[z + t]] = c[y + t])] = c[z + t]  // == 1 - remove char from the list
            : c[z] = c[y + (c[z + t] = c[z])] = t; // == 0 - add char to the end of the list
    }
    return c[y + c[y]];
}

1

C#,143个字节

char c(string s){var l=s.Select(o=>Char.ToLower(o)).GroupBy(x=>x).Where(n=>n.Count()<2).Select(m=>m.Key).ToList();return l.Count()>1?l[1]:' ';}

1

TSQL,128个字节

打高尔夫球:

DECLARE @ varchar(99)=',,zzzbb@kkkkkkJgg'

,@i INT=99WHILE @i>1SELECT
@i-=1,@=IIF(LEN(@)>LEN(x)+1,x,@)FROM(SELECT
REPLACE(@,SUBSTRING(@,@i,1),'')x)x PRINT SUBSTRING(@,2,1)

取消高尔夫:

DECLARE @ varchar(99)=',,zzzbb@kkkkkkJgg'

,@i INT=99

WHILE @i>1
  SELECT
    @i-=1,@=IIF(LEN(@)>LEN(x)+1,x,@)
  FROM
    (SELECT 
       REPLACE(@,SUBSTRING(@,@i,1),'')x
    )x

PRINT SUBSTRING(@,2,1)

小提琴


1

Ruby,53个字节

输入为STDIN,输出为STDOUT。在Ruby中,数组或字符串中索引不足的位置返回nil,但不会打印。

String#count在Ruby中是一个奇怪的函数,因为它不计算传入的字符串的出现次数,而是计算该字符串中每个字母的出现次数。通常这很烦人,但这次我们可以利用它来发挥自己的优势。String#swapcase交换大写和小写字母。

$><<gets.chars.reject{|c|$_.count(c+c.swapcase)>1}[1]

旧版本对特殊字符(例如.46个字节)不安全

$><<gets.chars.reject{|c|$_=~/#{c}.*#{c}/i}[1]

1

爪哇8,172个 157字节

(String s)->{s=s.toLowerCase();for(char i=0,c;s.length()>0;s=s.replace(c+"","")){c=s.charAt(0);if(!s.matches(".*"+c+".*"+c+".*")&&++i>1)return c;}return' ';}

-15个字节..当我那时打高尔夫球很烂。;)

说明:

在这里尝试。

(String s)->{                          // Method with String parameter and character return-type
  s=s.toLowerCase();                   // Make the input-String lowercase
  for(char i=0,c;s.length()>0;         // Loop over the characters of `s`
      s=s.replace(c+"","")){           // And after every iteration, remove all occurrences of the previous iteration
    c=s.charAt(0);                     // Get the current first character
    if(!s.matches(".*"+c+".*"+c+".*")  // If it doesn't occur more than once
     &&++i>1)                          // And this was the second one we've found
      return c;                        // Return this second characters
  }                                    // End of loop
  return' ';                           // Else: return an empty character/nothing
}                                      // End of method

1

R,79字节

function(z){y=tolower(el(strsplit(z,"")));x=table(y);y[y%in%names(x[x==1])][2]}

在线尝试!

我绝对觉得这里可以打高尔夫球。但是我真的很喜欢这个挑战。

此答案将字符串拆分为一个字符向量,将它们全部更改为小写字母,然后对它们进行表(计数)。选择一次出现的字符并将其与上述向量中的字符进行比较,然后将第二个为true的值作为输出返回。空字符串或不包含重复字符的字符串将输出NA。



1

K(oK) / K4,11个字节

解:

*1_&1=#:'=_

在线尝试!

说明:

*1_&1=#:'=_ / the solution
          _ / convert input to lowercase
         =  / group alike characters
      #:'   / count (#:) each group
    1=      / 1 equal to length of the group?
   &        / where true
 1_         / drop the first
*           / take the first


0

Perl,75个字节

 my$s=<>;chomp$s;my$c;for my$i(split//,$s){my$m=@{[$s=~/$i/gi]};$m<2and++$c>=2and say$i and last}

0

Javascript(使用外部库)(107字节)

使用我编写的库将其粉碎。不知道我是否必须计算变量“ s”的声明,即所讨论的字符串。

(s)=>_.From(s).ToLookup(y=>y.toLowerCase(),z=>z).Where(g=>g.Value.Count()==1).Select(x=>x.Key).ElementAt(1)

这将处理一个空字符串输入,一个仅包含一个非重复字符的输入以及一个包含2个以上非重复字符的输入

图片1


您是否有指向相关图书馆的链接?另外,这是代码高尔夫,您必须在可以的地方拿出空白
Value Ink

嘿,是github.com/mvegh1/Enumerable。尚无文档。抱歉,我将整理此答案以减少尽可能多的空格
applejacks01 2016年

您可能应该在答案正文中提及并链接它。另外,关于字节数,共识是将其放入匿名lambda中(so s=> ...
Value Ink

好的,没问题。我不想通过链接到我的代码来冒犯任何人,但是我确实提到我使用了我的库。我将用lambda更新我的答案,谢谢您让我知道
applejacks01 '16

0

Clojure,109个字节

#(let[s(clojure.string/lower-case %)](or(second(remove(set(map(fn[[k v]](if(> v 1)k))(frequencies s)))s))""))

ug,我希望有一种更简洁的方法。

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.