C # : 반복되는 문자열

Aug 20 2020

HackerRank "반복 문자열"도전에서 :

Lilah는 문자열을 가지고 \$s\$, 그녀가 무한히 여러 번 반복 한 소문자 영문.

정수가 주어지면 \$n\$, 첫 번째 \ 에서 문자 a의 수를 찾아 인쇄하십시오.$n\$ Lilah의 무한 문자열의 글자.

예를 들어, 문자열 \$s=abcac\$\$n=10\$, 우리가 고려하는 하위 문자열은 \$abcacabcac\$, 첫 번째 \$10\$그녀의 무한한 문자열의 문자. 있다 \$4\$ 하위 문자열에서 a의 발생.

테스트 사례 1 :

        string input = "aba";
        long n = 10;

테스트 사례 2 :

        string input = "a";
        long n = 1000000000000;

내 솔루션 :

        string input = "aba";
        long n = 10;
        long numAs = input.Count(c => c.Equals('a'));

        if (input.Length == 0)
        {
            return 0;
        }

        long rem = n % input.Length;
        long reps = (n - rem) / input.Length;
        long count = reps * numAs;

        string sRem = input.Substring(0, (int)rem);

        if (rem != 0)
        {
            count += sRem.Count(c => c.Equals('a'));
        }

결과는 7과 1000000000000이어야합니다.이 솔루션은 HackerRank의 모든 테스트 사례를 통과했습니다. 다른 솔루션, 특히 내가 찬성 한 솔루션을 기반으로합니다.

답변

4 MartinVerjans Aug 20 2020 at 21:46
  1. 입력의 유효성을 검사해야합니까?

그렇다면 모든 사례를 테스트해야합니다.

  • 입력은 null 일 수 있습니다.
  • 입력은 빈 문자열 일 수 있습니다.
  • n은 음수 또는 0 일 수 있습니다.
  1. 변수 이름

변수 이름은 중요하며 코드를 더 잘 이해하는 데 도움이됩니다. 가능한 한 작게 만들 필요는 없습니다. 특히 VisualStudio와 같은 IDE가 있으면 InteliSense에서 적절한 IDE를 선택하는 데 도움이됩니다.

  • numAs-> aCount
  • rem-> 나머지
  • 반복-> 반복
  • sRem-> 나머지 문자열
  1. 빠른 실패

일반적으로 "가능한 한 빨리"메소드를 남겨 두는 것이 좋습니다. 따라서 작업을 수행하기 전에 입력 유효성 검사를 수행하고 유효성 검사가되지 않으면 메서드를 종료하려고합니다. 같은 방식으로 나머지가 0이면 즉시 결과를 반환 할 수 있습니다.

  1. 정수 나누기

반복을 계산하려면 n에서 나머지를 뺍니다. C #에서 정수 나눗셈 을 확인하면 다음 을 수행 할 필요가 없습니다.

long repetitions = n / input.length;
  1. Linq 사용

tinstaafl 솔루션에 따라 Linq를 사용하여 변수와 줄을 저장할 수 있습니다.

count += remainderString.Take((int)remainder).Count(c => c.Equals('a'));

따라서 전체적으로 다음과 같은 결과를 얻을 수 있습니다.

long aCount = input.Count(c => c.Equals('a'));

if (input == null || input.Length == 0 || n <= 0)
{
    return 0;
}

long repetitions = n / input.Length;
long remainder = n % input.Length;
long count = repetitions * aCount;

if (remainder == 0)
{
    return count;
}

return count + remainderString.Take((int)remainder).Count(c => c.Equals('a'));
2 tinstaafl Aug 20 2020 at 05:06

개선 할 점이 많지 않습니다. 그러나 몇 가지를 알아 차 렸습니다.

바로 가기 조건 :

if (input.Length == 0)
{
    return 0;
}

코드에서 가장 먼저 input

유사하게 :

string sRem = input.Substring(0, (int)rem);

if (rem != 0)
{
    count += sRem.Count(c => c.Equals('a'));
}

rem> 0이 아니면 해당 문자열이 필요하지 않으므로 조건 블록에 포함하십시오. 더 좋은 점은 LINQ 확장을 사용하고 Take하나의 문으로 모든 작업을 수행하는 것입니다.

if (rem != 0)
{
    count += sRem.Take((int)rem).Count(c => c.Equals('a'));
}
2 iSR5 Aug 21 2020 at 07:25

다른 답변과 같은 점이지만 이것에 대한 더 간단한 해결책이 있습니다. A빈 문자열로 간단히 바꾸고 두 문자열의 길이를 비교하면 A의 수를 얻을 수 있습니다.

다음은 예입니다.

public static long RepeatedString(string s, long n)
{
    if (string.IsNullOrWhiteSpace(s) || n <= 0) { return 0; }
    
    // Local function that would return the number of A's 
    long CountA(string input) => input.Length - input.Replace("a", "").Length;
    
    var aCount = CountA(s);
    
    var reminder = n % s.Length; 
    
    var repetition = (n - reminder) / s.Length;
    
    var count = repetition * aCount;

    var reminderStr = s.Substring(0, (int)reminder);
    
    var result = count + CountA(reminderStr);
    
    return result;
}
1 Noname Aug 22 2020 at 01:50

성능에 관한 것 외에는 이미 작성된 내용에 많은 것을 추가 할 수 없습니다. Linq ( long numAs = input.Count(c => c.Equals('a'));)가 더 전통적인 for또는 while루프에 비해 다소 느리다 는 것을 종종 발견 할 것 입니다. 그러나 Linq를 고집하면 다음과 같이 올 수 있습니다.

long CountChars(string data, long length, char c = 'a')
{
  if (string.IsNullOrEmpty(data) || length <= 0) return 0;

  long repetitions = length / data.Length;
  long remSize = length % data.Length;

  return data
    .Select((ch, i) => (ch, i))
    .Where(chi => chi.ch == c)
    .Sum(chi => chi.i < remSize ? repetitions + 1 : repetitions);
}

여기서 과부하 사용 Select()그게 의해 필터 수있는 값 터플에 매핑하는 각각의 요소와 함께 인덱스를 제공 'a'인덱스 알림의 크기보다 작은 경우 다음 : 마지막 반복 횟수를 합산 repetitions + 1되어야 그렇지 않으면 발견 된 각 반복 만 합산됩니다 'a'.


while루프를 사용하는 전통적인 접근 방식 -본질적으로 위와 동일한 접근 방식을 사용하는 것은 다음과 같습니다.

long CountChars(string data, long length, char c = 'a')
{
  if (string.IsNullOrEmpty(data) || length <= 0) return 0;

  long count = 0;
  long repetitions = length / data.Length + 1; // + 1 for the possible extra 'a' in the reminder
  long remSize = length % data.Length;

  int i = 0;

  while (i < remSize)
  {
    if (data[i++] == c)
      count += repetitions;
  }

  repetitions--;
  while (i < data.Length)
  {
    if (data[i++] == c)
      count += repetitions;
  }

  return count;
}

이 방법을 사용하면 문자열 s( data)이 한 번만 구문 분석됩니다.