프로그래머스 JS 완주하지못한선수

이명진·2022년 4월 8일
0

코드카타

목록 보기
21/69

완주하지 못한선수

이번 문제는 답안을 제출했을때 효율성 테스트 까지 있었던 문제이다. 답은 맞출수 있지만 효율성으로 통과되는것이 많이 어려웠다. 대신에 이 문제에서 많은 것을 배울수 있었다.

마라톤에 참가한 선수 명단이 주어지고 마라톤에서 완주한 사람들의 명단이 주어진다.
둘다 배열이고 모든 경기에서 단 한명의 선수를 제외하고 모든 선수가 마라톤을 완주한다.
이때 마라톤에 완주하지 못한 사람의 이름을 도출하면 된다.
단 동명이인이 있을수 있다.

내가 첫번째로 푼 로직이다

function solution(participant, completion) {
  completion.map( x => {
       participant.filter((y,i)=>{
         if(x == y){
            participant.splice(i,1)
         }
       })
     })
  return participant[0]
}

간단하게 풀었는데 효율성 테스트 까지 있었을 줄이야 ..
효율성 테스트에 다 통과 못하고 정답도 일부 틀린 로직이다.
완주 명단을 map돌린다음에 모든 명단과 비교하여 일치한 사람들을 하나씩 제거한다.
그러면 한명만 남아 있을텐데 그 선수를 도출하는 방법을 생각했다.
하나씩 제거 한다는 점에서 효율성에 통과하지 못한것 같다.

답은 맞는것 같은데 효율성에 왜 통과하지 못할까 생각하다가 해시를 통해서 문제를 풀도록 생각하게 되었고 두번째 로직을 작성하게 되었다.

function solution(participant, completion) {

const obj = completion.reduce((a,b)=> (a[b]='',a),{});
  for(let key in obj){
  obj[key]=true
  }
  let a = participant.filter(x=>{
      obj[x] = !obj[x]
    return obj[x] !== false
  })

  return a[0]
}

각각 객체로 만들어서 객체의 키값으로 이름을 주고 그의 값들을 true, false로 주고 완주 명단, 모든 선수의 명단을 비교 한다. 비교해서 true,false를 바꺼준다.
비교했을때 true에서 false로 바뀌지 못한 선수가 도출하게 된다.
문제를 풀다가 이 로직이 훨씬 더 복잡하다고 생각들었는데 의외로 효율성 테스트 몇개는 통과했다.

몇번 더 생각해보다가 결국 답을 보게 되었다.

function solution(participant, completion) {
    participant.sort()
    completion.sort()

    for(const i in completion){
        if(participant[i] != completion[i])
            return participant[i];
    }
  console.log(participant,1)

    return participant[participant.length-1]
}

답은 그냥 정렬한다음에 비교 하는 것. 생각보다 단순했다. 복잡하게 생각했는데 그게 아니었다.

해시에 대해서 몰랐는데 해시에 대해서 알수 있었다. 노마드 코드에서 강의로 봤었는데 마침 관련 문제를 풀게 되었다. 해시가 찾고자 하는 값들을 키값으로 정해두면 더빨리 찾을수 있다는 점이었다.
순서대로 비교하는 것보다 이름값으로 바로 접근하면 더빨리 찾을수 있다는 것

그래서 object 로 풀려고 생각했는데 다른 사람의 풀이에서 새로운것을 배울수 있었다.

아래는 다른사람의 풀이중 첫번째 많은 인기를 얻은 답이다.

var solution=(_,$)=>_.find(_=>!$[_]--,$.map(_=>$[_]=($[_]|0)+1))

매개 변수를 _ , $ 이렇게 주었는데 이렇게 짧게 작성하면 더 빠를지 의문이다. 고수들은 이렇게 쓴다던데 이렇게 쓰면 성능이 더 좋은걸까 가산점을 주는 걸까 ?
내가 봤을때는 코드를 분석하기에는 더 어려운것 같다.
다행히도 아래 어느 고수분이 댓글로 이 코드를 해석해주었는데 많은 도움이 되었다.

내가 알게 된점이다.
1. 배열로도 객체처럼 작성이 가능하다 배열 값 에 '이름': 0 이렇게 넣을수 있다.
즉 예시로 보면 [ 'stanko', 'ana', 'mislav', stanko: 1, ana: 1, mislav: 1 ] 이런식으로 넣을수 있다는 점이다. 배열의 타입이 객체 라는점도 알게 되었다.
근데 직접 작성하여 변수에 할당하면 runJS에서는 오류가 난다.
또한 이를 접근할때 인덱스로 접근할수 없다. 위의 예시에서 stanko:1에 접근하려면
arr[3] 값으로 접근하면 안된다. 찾을수 없다는 에러가 나온다.
arr['stanko'] 이렇게 접근하면 1이 나온다.
객체처럼 stanko를 키 1을 키 값으로 생각하고 객체와 같이 도출이 된다.
2. find함수에서 두번째 매개변수는 첫번째 보다 먼저 실행이 된다는 점 .
이부분에서는 find함수에 대해서 정확하게 알아야 하는 것 같다. 두번째는 함수가 실행되고 this값으로 선택이 되는것인데 위에 작성한 로직에서 두번째 인자로서 map을 사용해서 this를 계속 바꿔주었다.
역시 고수는 고수인것 같다.

두번째 풀이

아이디를 합치는 과정에서 프로그래머스 이전 레벨 1 부분 풀었던 부분이 다 날라갔다.
다시 한번 회고 하는 편으로서 레벨 2 해시 문제를 풀다가 관련된 문제인 레벨 1문제를 다시 풀어보게 되었다.

처음으로는 map을 돌려서 배열의 값에 만약에 완주한 선수가 있다면 그 선수 자리를 0으로 바꿔주고 0이 아닌 값을 리턴 하는 형식으로 풀었다. 답은 다 맞는데
효율성에서 시간초과로 나왔다.

해시 방법으로 다시 풀어보자 생각해서 아래와 같은 로직으로 풀었다

function solution(participant, completion) {
let list = {}
completion.map(x=>{
  list[x]= list[x]+1 || 1
})
  participant.map(x=>{
    if(list[x]){
      list[x]=list[x]-1
    }else{
      list[x]=1
    }
  })
  let answer ='';
  for(let item in list){
    if(list[item]){
      answer = item
    }
  }
  
  return answer

}

solution(	["leo", "kiki", "eden"], ["eden", "kiki"])

통과했다. 벨로그에 정리하기 위해 이전에 풀었던 내용을 봤는데 이런 방식이 고수의 답에 있었다.
그때 공부해서 안까먹은걸까 ?
그래도 이번에는 답을 안풀고 문제를 풀수 있었음에 성장했음을 느꼈다.

풀이

객체에 사람 이름별로 저장을 해두고 사람 이름마다 숫자를 카운트 해준다.
숫자 카운트된 객체에서 이번에는 완주한 선수 목록을 돌면서 키값이 있다면 -1 해준다.

객체에 0이 아닌 값이 있다면 리턴 하도록 하였다.

성장했군..

profile
프론트엔드 개발자 초보에서 고수까지!

0개의 댓글