프로그래머스

프로그래머스 JS 해시 [4/5]

sakuraop 2023. 9. 3. 10:32

폰켓몬 Level 1 문제보기 (5)

function solution(nums) {
  const set = new Set(nums); // 다양한 포켓몬을 가지는게 목표 => 중복된 포켓몬 제외
  const maxLength = nums.length / 2
  return maxLength < set.size ? maxLength : set.size; // 최대한 많이 데려가기
}

완주하지 못한 선수 Level 1 문제보기 (5)

function solution(participant, completion) {
  // 배열을 문자열 순으로 정렬하여 일치하지 않는 지점을 반환하면 된다.
  const sortedParticipant = participant.sort();
  const sortedCompletion = completion.sort();

  for (let i = 0; i < participant.length; i++) {
    if (sortedParticipant[i] !== sortedCompletion[i]) {
      return sortedParticipant[i]; // 참가자와 완주자의 이름이 다른 경우
    }
  }
}

해시로 해도, 해시로 하지 않아도 시간상 큰 차이가 없는 문제들이므로 간단한 방식으로 풉니다.


전화번호 목록 Level 2 문제보기 (15)

문제 포인트

- 원소 하나하나 배열의 모든 요소에 대해 includes() 메서드로 판별을 하면 효율성에서 떨어지겠구나 생각할 수 있다.

  따라서 Map을 이용하여 전화번호의 앞부분이 존재하는지 탐색하면 된다.

 

- 길이가 큰 문자열은 길이가 작은 문자열의 접두어가 될 수 없다. sort()로 길이가 큰 문자열을 앞으로 옮긴다.

  ["123", "12"] 를 예시로

 

  "123"이 이미 삽입되어 있는 상태에서 "1"과 "12"를 탐색하여도 존재하지 않지만,

  정렬을 한 뒤에는 "12"가 이미 삽입 된 상태로 등록된 접두 번호를 찾아낼 수 있게 된다.

 

- 모든 접두어를 생성한다.

 

문제 풀이

1. "119"로 생성할 수 있는 접두어는 "1", "11", "119" 이다.

=>  for 문과 slice(0,i)를 이용하여 map에 접두어를 저장한다.

 

2. 접두어를 발견했다면 바로 false를 return한다. 

 모든 경우에 접두어가 없다는 것을 확인했다면 true를 반환한다. 

 

function solution(phone_book) {
  // 길이가 큰 문자열이 길이가 작은 문자열의 접두어가 될 수 없으므로,
  const sortedBook = phone_book.sort((a, b) => b - a); // 길이가 큰 문자열 앞으로
  const phones = new Map();

  for (let phone of sortedBook) {
    if (phones.has(phone)) return phones.get(phone); // 접두어가 존재할 경우 false 반환

    // 번호로 만들 수 있는 모든 접두어 만들기
    for (let i = 0; i < phone.length; i++) {
      phones.set(phone.slice(0, i), false); // ex) 119 => "1", "11","119"
    }
  }

  return true; // 접두어인 경우가 없으면 true 반환
}

의상 Level 2 문제 보기

 


베스트앨범 Level 3 문제 보기 (50)

문제 포인트 

- 장르별로 재생 횟수를 구분합니다.
- 문제에서 요구하는 순서대로 구현합니다.

 

풀이 순서

1. 장르별로 재생 횟수를 구분하기 위해 map으로 만들어 줍니다. 이 때 고유 index를 배열로 함께 매핑해줍니다. 

Map(2) {
  'classic' => [ [ 0, 500 ], [ 2, 150 ], [ 3, 800 ] ],
  'pop' => [ [ 1, 600 ], [ 4, 2500 ] ]
}

 

2. 장르별로 재생 횟수를 합산한 뒤, 높은 순서대로 정렬합니다.

 

3. 장르 내에서 재생 횟수가 높은 순서대로 정렬하고, 최대 2개만 남깁니다.

 

4. 장르 내에서 동일한 재생 횟수의 노래가 있다면 고유번호가 낮은 앨범을 앞에 둡니다. 

 

function solution(genres, plays) {
  const songMap = new Map(); // map() { 장르: [재생횟수1,재생횟수1] }

  genres.forEach((genre, index) => {
    const genrePlays = songMap.get(genre); // 장르
    const play = plays[index]; // 재생 횟수
    songMap.set(genre, genrePlays ? [...genrePlays, [index, play]] : [[index, play]]);
  });

  // 속한 노래가 많이 재생된 장르를 먼저 수록합니다. 
  const genreHighSorted = Array.from(songMap)
    .map((item) => item[1])
    // 장르 재생 횟수 합산 정렬 
    .sort(
      (a, b) =>
        // 장르 재생 횟수 합산
        b.reduce((total, [_, curScore]) => total + curScore, 0) -
        a.reduce((total, [_, curScore]) => total + curScore, 0)
    );

  // 장르 내에서 많이 재생된 노래를 먼저 수록합니다. 재생 횟수로 정렬을 한 뒤, 최대 2개만 남기기
  const playsHighSorted = genreHighSorted.map((info) => info.sort((a, b) => b[1] - a[1]).slice(0, 2)); 

  // 장르 내에서 재생 횟수가 같은 노래 중에서는 고유 번호가 낮은 노래를 먼저 수록합니다.
  const indexLowSorted = playsHighSorted.map((item) =>
    item.sort((a, b) => (a[1] === b[1] ? a[0] - b[0] : 0)) // 재생 횟수가 같다면 고유 번호가 낮은 노래를 앞으로
  );

  // 인덱스 순서를 반환합니다.
  return indexLowSorted.flat().map((index) => index[0]); 
}