오늘의 코딩 테스트 한줄 - 두 개 뽑아서 더하기

Edwin·2023년 5월 27일
0
post-thumbnail

프로그래머스, 두 개 뽑아서 더하기

문제 설명 : 배열의 중복값 제거

정수 배열 numbers가 주어집니다. numbers에서 서로 다른 인덱스에 있는 두 개의 수를 뽑아 더해서 만들 수 있는 모든 수를 배열에 오름차순으로 담아 return 하도록 solution 함수를 완성해주세요.

입출력의 예

let numbers = [2,1,3,4,1]

  • 문제는 주어진 배열에서 임의로 2개를 추출하여 더한 값을 반환하는 배열을 만드는 일이다.
  • 위의 배열에서 보면 배열[1]와 배열[4]는 index가 다르지만 값이 동일하다.
  • 이러한 경우에도 더하면 최소값이 2부터 출발하며, 최대값은 배열[3]+배열[4]의 결과인 7이다.

나의풀이

return : [2,2,3,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6,7,7]
반환된 값으로 위의 배열까지는 만들었다. 최대값의 경우 7이 중복된 이유는 아래와 같은 상황 때문이다.

  • 첫째, 배열[3]+배열[4]
  • 둘째, 배열[4]+배열[3]

이러한 경우, 중복값을 제거할 필요가 있었는데, 위의 반환값까지는 내가 아는 기초지식을 바탕으로 풀었다. 그러나 중복값을 제거하는 방법은 풀지 못했다. 물론 반복문을 사용하면 가능하겠지만, 그렇게 접근하고 싶지 않았다. 이미 위의 배열을 추출하기 위하여 2번의 반복문을 선언했기 때문이다. 배열 내의 중복값을 제거하는 값을 어떻게 처리할 수 있을까?

검색을 통해서 Set 객체를 알아냈고, 이를 통해서 쉽게 처리할 수 있었다.

function solution(numbers) {
    let answer = [];
    numbers.forEach((el,i1) => {
       numbers.forEach((els, i2) => i1!==i2 && answer.push(el+els)) 
    })
    return [...new Set(answer.sort((a,b)=> a-b))];
}

배열의 중복값 제거하기

참고자료

Set 객체 활용하기

MDN문서에 따르면 Set 객체는 자료형에 관계 없이 원시 값과 객체 참조 모두 유일한 값을 저장하는 객체이다. "유일한 값"이 핵심인데, Set 객체는 삽입 순서대로 요소를 순회하며, 동일한 값이 존재하는지 검사를 수행하며, 중복되지 않은 유일한 값만 담는다.

// Set 객체는 생성자를 통해서 선언되기에 new 키워드와 같이 선언하며 가능하다. 
let numbers = [2,2,3,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6,7,7];
let arr = [...new Set(numbers)]; // [2, 3, 4, 5, 6, 7]
let arr2 = new Set(numbers); // {2, 3, 4, 5, 6, 7} 

객체이기에 arr2를 보면 객체를 생성한다. 콘솔을 찍어보면, index를 가진 배열(객체)을 생성한다. 그러나 {중괄호}로 생성되기에, 내가 원하는 값으로 변경하려면, [대괄호]로 추출되어야 한다. 이를 위해서 전개구문이 사용되었다. 이러한 접근으로 위의 문제를 해결할 수 있었다.

filter(), indexOf() 활용하기

let numbers = [2,2,3,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6,7,7];
let arr = numbers.filter((el, index) => numbers.indexOf(el) === index);

위의 로직의 관건은 numbers의 배열에서 el로 선언된 요소가 처음존재하는 index(indexOf)와 numbers의 index가 일치하는 경우만을 filter를 통해서 추출하는 것이다.

여기서 사용된 Array.prototype.indexOf()는 배열에서 지정된 요소를 찾을 수 있는 첫 번째 인덱스를 반환하고, 존재하지 않으면 -1을 반환한다.

numbers[0]번지 : 2

  • 2는 numbers.indexOf(el)에서 0이 선언된다.
  • 선언된 numbers.indexOf(el)의 값이 일치되는 numbers.index가 0인 값만 반환된다.

numbers[1]번지 : 2

  • 2는 numbers.indexOf(el)에서 0이 선언된다.
  • numbers[1]는 위에서 선언된 numbers.indexOf(el)의 값인 0과 다르기에 반환되지 않는다.

numbers[2]번지 : 3

  • 3는 numbers.indexOf(el)에서 2이 선언된다.
  • 선언된 numbers.indexOf(el)의 값이 일치되는 numbers.index는 2번지 뿐이다.
  • 이외의 index는 반환되지 않는다.

이러한 결과로, 중복된 값을 제거한 값을 추출할 수 있다.

reduce() 활용하기

let numbers = [2,2,3,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6,7,7]
const arr = arr.reduce((acc, obj) => acc.includes(obj) ? acc : [...acc, obj], [])

reduce는 배열을 가공하여 하나의 값으로 추출한다.
삼항 조건부 연산자는 includes의 결과에 따라서 true인 경우와 false인 경우에 따라 값을 추출한다.
true이면, 즉 includes(obj)을 포함하면, 기존의 누산된 배열을
false이면, 누산배열에 [...acc, obj], 이와 같이 새로운 요소를 포함한다.

reduce를 활용하여 배열을 가공하는 방법을 처음으로 활용해보았다.
그렇다면 삼항 조건부 연산자의 조건을 includes 뿐 아니라, 특정조건에 부합하는 결과에 따라 가공할 수 있다는 말이다.

효율성을 따져보자.

ChatGPT에 따르면, 세 가지 접근 방식을 비교하면 Set and Spread Operator 이 가장 효울적이다. 다른 두 개의 방법은 시간복잡도에서 Set and Spread Operator과 비교했을 때 떨어지기 때문이다. 이는 filter 및 인덱스 비교 접근 방식과, reduce 콜백 내에서 includes 방법이 사용되기 때문이다. 반면에, Set 방식은 Set 데이터 구조를 사용하며, Set 데이터 구조는 중복 값을 자동으로 제거한다.

오늘의 내용에서는 배열에서 중복값을 제거하는 방법이 핵심이다. 3가지 방법을 살펴보았고, 시간복잡도를 따져보았다.

profile
신학전공자의 개발자 도전기!!

0개의 댓글