코딩기록

replace) 문자열 바꿔서 찾기 / 문자열 바꿔서 다른 문자열 포함되어 있으면 1 없으면 0 반환, 삼항연산자에서 문자열을 이어붙여 반환하는 방법(식별자 += 삼항연산자), includes, indexOf, match 본문

프론트/JS)코딩테스트

replace) 문자열 바꿔서 찾기 / 문자열 바꿔서 다른 문자열 포함되어 있으면 1 없으면 0 반환, 삼항연산자에서 문자열을 이어붙여 반환하는 방법(식별자 += 삼항연산자), includes, indexOf, match

뽀짝코딩 2024. 9. 25. 21:28
728x90

문제 설명

문자 "A"와 "B"로 이루어진 문자열 str과 part가 주어집니다. str의 "A"를 "B"로, "B"를 "A"로 바꾼 문자열의 연속하는 부분 문자열 중 part이 있으면 1을 아니면 0을 return 하는 solution 함수를 완성하세요.


제한사항

  • 1 ≤ str의 길이 ≤ 100
  • 1 ≤ part의 길이 ≤ 10
    • str과 part는 문자 "A"와 "B"로만 이루어진 문자열입니다.

입출력 예

str part result

"ABBAA" "AABB" 1
"ABAB" "ABAB" 0

입출력 예 설명

입출력 예 #1

  • "ABBAA"에서 "A"와 "B"를 서로 바꾸면 "BAABB"입니다. 여기에는 부분문자열 "AABB"가 있기 때문에 1을 return 합니다.

입출력 예 #2

  • "ABAB"에서 "A"와 "B"를 서로 바꾸면 "BABA"입니다. 여기에는 부분문자열 "BABA"가 없기 때문에 0을 return 합니다.
const solution = (str, part) => {
	// do something
};

console.log(solution('ABBAA', 'AABB')); // 1
console.log(solution('ABAB', 'ABAB')); // 0

풀이

filter 메서드는 요소를 선택하는 데 사용되며, 각 요소의 값을 변환하는 데는 적합하지 않다. 따라서 A와 B를 서로 반전시키는 작업은 filter로는 수행할 수 없다.

 

1번 풀이 for문

삼항연산자로 풀 때 조건에 따라 빈배열이나 빈문자열에 값을 추가하는 방법은 두 가지가 있다.

1. oppositeStr += str[i] === 'A' ? 'B' : 'A'

2. str[i] === 'A' ? oppositeStr += 'B' : oppositeStr += 'A'

보통 2번 방법을 많이 썼는데 oppositieStr이라는 식별자를 중복해서 두 번 쓰는 것을 줄이는 방법이 1번이다.

상세히 살펴보면

 

1️⃣.  oppositeStr += str[i] === 'A'? 'B' : 'A'

 

  1. 삼항 연산자 전체가 하나의 표현식으로 처리됨.
  2. 먼저 str[i] === 'A'의 조건을 확인하고, 그 결과로 'B' 또는 'A' 중 하나가 반환됨.
  3. 그 후, 반환된 값이 oppositeStr에 추가됨.

2️⃣. str[i] === 'A' ? oppositeStr += 'B' : oppositeStr += 'A'

 

  1. 조건에 따라 각각 다른 명령어가 실행됨.
  2. str[i] === 'A'이면 직접 'B'를 oppositeStr에 추가하고, 아니면 'A'를 추가함.
  3. 동작은 동일하지만, 조건에 따라 서로 다른 대입문이 실행됨.

 

 

const solution = (str, part) => {
  let oppositeStr = '';
  for (let i = 0; i < str.length; i++) {
    // str[i] === 'A'이면 직접 'B'를 oppositeStr에 추가하고, 아니면 'A'를 추가함.
    // 즉, 동작은 동일하지만, 조건에 따라 서로 다른 대입문이 실행됨.
    str[i] === 'A' ? oppositeStr += 'B' : oppositeStr += 'A'  // 'A', 'B' 만 고려한 코드
    // oppositeStr += str[i] === 'A' ? 'B' : 'A'  // 위 코드를 아래 처럼 고칠수도 있다. 삼항 연산자 전체가 하나의 표현식으로 처리
    // 결론적으로 결과는 동일하나 첫번째 방식은 삼항 연산자 자체가 결과를 반환한 후에 한 번만 +=이 실행되며,
    // 두 번째 방식에서는 조건에 따라 서로 다른 명령이 실행된다.

    // oppositeStr += str[i] === 'A' ? 'B' : (str[i] === 'B' ? 'A' : str[i]);  // 'A', 'B' 외의 다른 코드까지 만 고려한 코드
  }
  return oppositeStr.includes(part) ? 1 : 0;
};
console.log(solution('ABBAA', 'AABB')); // 1
console.log(solution('ABAB', 'ABAB')); // 0

여기서 좀더 발전시켜 'A', 'B' 이외 다른 문자또한 변환하지 않는 코드를 추가했다

oppositeStr += str[i] === 'A' ? 'B' : (str[i] === 'B' ? 'A' : str[i]);

  • oppositeStr +=  
    • 문자열을 계속 이어 붙인다.
  • (str[i] === 'B' ? 'A' : str[i]);
    • () 소괄호 안, 두번째 삼항연산자에서 str[i]가 'B' 이면  'A'를 반환하고 아니면 str[i]를 그대로 반환하는 코드를 추가해서 이외의 다른 문자가 왔을때 'A', 'B' 로 변환하지 않게 했다.

 

2번 풀이 for...of

삼항연산자와 if else if 로 풀었다.

// 2번 풀이 for...of
const solution2 = (str, part) => {
  let oppositeStr = '';
  for (const c of str) {
    if (c === 'A') {
      oppositeStr += 'B'
    } else if (c === 'B') {
      oppositeStr += 'A'
    }

    // 간단하게 삼항연산자로 변경
    // oppositeStr += c === 'A' ? 'B' : 'A';
  }
  return oppositeStr.includes(part) ? 1 : 0;
};
console.log(solution2('ABBAA', 'AABB')); // 1
console.log(solution2('ABAB', 'ABAB')); // 0

 

 

3번 풀이  forEach

문자열에 문자열이 들어가 있는자 확인할때 3가지 방법을 썼다.

1. includes : includes 문자열에서 특정 문자열이 포함되어 있는지 확인. true 또는 false 값을 반환.

2. indexOf : indexOf는 문자열의 첫 번째 위치(인덱스)를 반환하고, 찾지 못하면 -1을 반환.

3. match : match: 정규식을 사용해 찾은 결과를 배열로 반환하고, 없으면 null을 반환.

 

indexOf는 부정을 부정해서 1과 0으로 결과를 반환하게 했다.

ex) 요소가 존재하지 않는게 아니면 1 맞으면 0. 즉, 요소가 존재한다 1, 존재하지 않는다 0.

// 3번 풀이 forEach - includes, indexOf, match
const solution = (str, part) => {
  let oppositeStr = '';
  [...str].forEach(c => oppositeStr += c === 'A' ? 'B' : 'A');
  // return oppositeStr.includes(part) ? 1 : 0;
  // return oppositeStr.indexOf(part) !== -1 ? 1 : 0; // 요소가 존재하지않는게 아니면-1 맞으면-0. 즉, 부정을부정.
  return oppositeStr.match(part) ? 1 : 0 
};
console.log(solution('ABBAA', 'AABB')); // 1
console.log(solution('ABAB', 'ABAB')); // 0

 

 

4번 풀이 정규표현식 regExp + replace

indexOf메서드는 찾지못하면 -1을 반환하기 때문에 삼항연산자를 같이 쓸때 조건을 꼭 정해야한다.

무조건 참이면1이지 하고    change.indexOf(part) ? 1 : 0;    ←이렇게 썼다가 조금 헤맸다.

 

조건문 (? :)change.indexOf(part) ? 1 : 0; 

  • 이 부분은 삼항 연산자로, indexOf의 결과를 평가한다.
  • indexOf가 반환하는 값이 0보다 크면 (즉, part가 문자열의 시작이 아닌 곳에 존재하면) 그 값은 true로 평가되어 1이 반환된다.
  • indexOf가 -1이면 (즉, part가 문자열에 포함되지 않으면) 그 값은 false로 평가되어 0이 반환된다.
  • 하지만, indexOf가 0을 반환하는 경우(즉, part가 문자열의 시작 부분에 위치하는 경우)는 0으로 평가되므로, 이 경우 0이 반환된다.
// 4번 풀이 정규표현식 리터럴, indexOf
const solution4 = (str, part) => {
  const regExp = /[AB]/g;
  const change = str.replace(regExp, match => (match === 'A' ? 'B' : 'A'));

  // XX오류
  // return change.indexOf(part) ? 1 : 0;
  // indexOf가 반환하는 값이 0보다 크면 (즉, part가 문자열의 시작이 아닌 곳에 존재하면)
  // 그 값은 true로 평가되어 1이 반환됨. 


  // indexOf가 -1일 경우 part가 포함되지 않은 것이므로 0 반환,
  // 문자열 내에 part가 포함된 경우에만 1, 포함되지 않으면 0
  return change.indexOf(part) !== -1 ? 1 : 0;
};
console.log(solution4('ABBAA', 'AABB')); // 1
console.log(solution4('ABAB', 'ABAB')); // 0

 

 

5번 풀이  map

 map은 배열에서만 사용가능한 메서드라 스프레드문법으로 문자열을 문자배열로 변경한 후 map으로 돌리고 마지막에 

join('')으로 다시 문자열로 만들어 반환했다.

// 5번 풀이 map
const solution5 = (str, part) => {
  const oppositeStr = [...str].map(c => c === 'A' ? 'B' : 'A').join('');
  return oppositeStr.match(part) ? 1 : 0;
};
console.log(solution5('ABBAA', 'AABB')); // 1
console.log(solution5('ABAB', 'ABAB')); // 0

 

 

6번 풀이 reduce 

reduce

// 6번 풀이 reduce
const solution = (str, part) => {
  const oppositeStr = [...str].reduce((acc, cur) => cur === 'A' ? acc + 'B' : acc + 'A', '');
  return oppositeStr.includes(part) ? 1 : 0;

};
console.log(solution('ABBAA', 'AABB')); // 1
console.log(solution('ABAB', 'ABAB')); // 0

 

 

참고

나, 쳇지피티

 

 

반응형
Comments