코딩 테스트 연습/Programmers

[프로그래머스] 가장 가까운 같은 글자

은돌1113 2023. 8. 17. 10:18

문제 설명

문자열 s가 주어졌을 때, s의 각 위치마다 자신보다 앞에 나왔으면서, 자신과 가장 가까운 곳에 있는 같은 글자가 어디 있는지 알고 싶습니다.
예를 들어, s="banana"라고 할 때,  각 글자들을 왼쪽부터 오른쪽으로 읽어 나가면서 다음과 같이 진행할 수 있습니다.

  • b는 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.
  • a는 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.
  • n은 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.
  • a는 자신보다 두 칸 앞에 a가 있습니다. 이는 2로 표현합니다.
  • n도 자신보다 두 칸 앞에 n이 있습니다. 이는 2로 표현합니다.
  • a는 자신보다 두 칸, 네 칸 앞에 a가 있습니다. 이 중 가까운 것은 두 칸 앞이고, 이는 2로 표현합니다.

따라서 최종 결과물은 [-1, -1, -1, 2, 2, 2]가 됩니다.

문자열 s이 주어질 때, 위와 같이 정의된 연산을 수행하는 함수 solution을 완성해 주세요.


제한사항

  • 1 ≤ s의 길이 ≤ 10,000
    • s은 영어 소문자로만 이루어져 있습니다.

입출력 예

s result
"banana" [-1, -1, -1, 2, 2, 2]
"foobar" [-1, -1, 1, -,1, -1, -1]

입출력 예 설명


입출력 예 #1

  • 지문과 같습니다.

입출력 예 #2

  • 설명 생략

문제풀이

  • 나의 풀이
    • 정의
      • slice(begin, end) : slice() 연산자를 사용해서 0부터 i까지 배열을 자른다. (얕은 복사)
      • padEnd(길이, 새로운 문자) : 현재 문자열에 다른 문자열을 채워, 주어진 길이를 만족하는 새로운 문자열을 반환한다. 채워 넣기는 대상 문자열의 끝(우측)부터 적용된다.
      • lastIndexOf() : 주어진 값과 일치하는 부분을 fromIndex로부터 역순으로 탐색하여 최초로 마주치는 인덱스를 반환한다. 일치하는 부분이 없으면 -1을 반환한다.
    • 주의
      • 콘솔과 함께 제출하면 "출력 크기 초과"로 통과가 안되기 주의를 요함⭐
      • 해당 문자의 앞 부분에서 일치하는 값과, 해당 인덱스와의 거리(칸)을 찾는 문제이기 때문에 padEnd() 안써도 무방
        (글쓴이는 한번 써보고 싶기도 하고, 콘솔을 찍었을 때 직관적으로 보고 싶어서 추가한 것이기 때문에 없어도 결과값은 동일)
function solution(s) {
  var answer = [];

  answer = s.split("").reduce((acc, cur, i, arr) => {
    const padEndArr = s.slice(0, i).padEnd(arr.length, "*");
    // ! padEnd() 없어도 무방합니다.
    // 정의: s.slice(0, i) → slice(begin, end) 연산자를 사용해서 0부터 i까지 배열을 자른다. (얕은 복사)
    // 정의: padEnd(길이, 새로운 문자열) → 현재 문자열에 다른 문자열을 채워, 주어진 길이를 만족하는 새로운 문자열을 반환한다. 채워넣기는 대상 문자열의 끝(우측)부터 적용된다.
    // ex. cur: b, i: 0일 때 padEndArr는 ******, cur: a, i: 1일 때 padArr는 b***** ...가 된다.

    return [
      ...acc,
      padEndArr.lastIndexOf(cur) > -1 ? i - padEndArr.lastIndexOf(cur) : -1,
      // 정의: lastIndexOf() → 주어진 값과 일치하는 부분을 fromIndex로부터 역순으로 탐색하여 최초로 마주치는 인덱스를 반환한다. 일치하는 부분이 없으면 -1을 반환한다.
      // ex. 자신보다 앞에 있는 문자가 있을 경우 해당 문자가 자신보다 몇 칸 앞에 있는 지 반환하는 문제이기 때문에 indexOf() 대신 lastIndexOf()를 사용하여서 역순으로 탐색하게 하였다.
      // > cur: a, i: 3일 때 padArr는 ban***이고, lastIndexOf()을 사용하면 1이 반환되고, cur: n, i: 4일 때 padArr는 banan*이고 lastIndexOf()를 사용하면 4이 반환되고,
      // 몇 칸 앞에 있는 지 판단하기 위해서 lastIndexOf()의 반환값이 -1이 아닌 경우에 i에서 위 과정에서 구한 lastIndexOf()의 반환값을 빼주면 된다.
    ];
  }, []);

  return answer;
}

solution("banana");
solution("foobar");
solution("abcda");

  • 다른 분의 풀이
    • 문자열을 전개 연산자(스프레드 연산자, ...)를 사용해서 배열로 만들 수 있다는 걸 새롭게 알게 되었고,
    • Object를 사용하여서 문자의 반복문을 돌 때마다 문자(v)의 index를 hash에 대입함으로써 최신화 시킬 수 있다는 점에서 간결해서 좋았다.
function solution(s) {
  const hash = {};

  return [...s].map((v, i) => {
    let result = hash[v] !== undefined ? i - hash[v] : -1;
    // hash[v]에 값이 있으면 i(현재 index) - hash[v](겹치는 문자열의 index)를 반환, 없으면 -1

    hash[v] = i;
    // 문자의 index를 업데이트
    
    return result;
  });
}
 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr