📄문제




✏️풀이
재영
오답 과정
오답 과정
이렇게 했더니 효율성에서 꽝이 나와씁니다...
hash
로 다 저장을 한다! 이때key
의 이름을 그냥 다 붙인 걸로 만든다. 마치 다음처럼 말이다.infos = { javabackendjuniorpizza: [150] }
- 그 다음에,
score
을 분리하고query
의 경우 정규표현식으로 해당되는 옵션들만 빼내준다. 마치 다음처럼 말이다.query = [backend, senior]
score = 150
- 결과적으로 쿼리를 모두 포함하는 키들을 찾아서, 점수에 맞는 애들을 필터해서 나온 배열 길이를 더해준다.
생략해도 됩니다! 틀렸으니까유 😂
const getInfos = (info) => { const infos = {}; info.forEach(str => { const arr = str.split(" "); const score = parseInt(arr.pop()); const key = arr.join(""); if (infos[key]) infos[key].push(score) else infos[key] = [score]; }); return infos; } const solution = (info, query) => { let answer = []; const infos = getInfos(info); const infosKey = Object.keys(infos); const splitedQuery = query.map(q => q.split(/ and | |-/i)); splitedQuery.forEach(query => { const score = query.pop(); const filteredKey = infosKey.filter(key => query.every(v => key.includes(v))) const result = filteredKey.reduce((acc, key) => acc + infos[key].filter(cnt => cnt >= score).length, 0); answer.push(result) }) return answer; }

와우~ 대단하죠?! 👏👏
정답 과정
getInfos
에서 다음과 같이 처리를 해줄 거에요.{ javabackendjuniorpizza: [150] }
- 그럼 우리는, 이제 앞으로
hash
를 통해 손쉽게 해당 쿼리에 해당하는 사람들의 점수를 갖고 올 수 있어요.
- 분리하고,
query
조건을 필터링해줄 거에요. 다음과 같이 말이죠.+ - and backend and senior and - 150
→[ backend, senior, 150 ]
왜
-
까지도 없애죠?!
왜 -을 뺐냐면, 결국에는 특정 조건들만 key
값에 들어가 있는지만 체크하면 되니까요!- 이제 이렇게 쿼리 친구들을
forEach
로 돌려줍시다. - 먼저
score
을 분리해줘야겠죠? 분리해줍니다. - 그러면 이제 필요한 쿼리들이 모두 존재하는 키를 찾아야 해요.
이는
getResult
함수에서 수행해줍시다.
getResult
에서는 말이죠, 다음을 처리해줘요.- 먼저
object
자료구조에서 키들을 다 뽑아내요.Object.keys(infos)
- 전체 키들을 뽑아낸 배열에 대해, 필터링을 해줍니다. 그럼 조건에 맞는 결과 값을 담은 배열이 반환되겠죠?
- 모든 조건이 맞을 때
true
를 뱉는Array.every
내장 메서드를 써줍시다. 그러면 모든 조건을 만족하는 키만 나와요. - 이를
reduce
를 통해 모두 더해주는 거에요. - 쭉 더해줄 때마다
key
쪽에서 정렬된 점수 배열이 나올 거에요. 이분 탐색을 해주어,infos[key]
의 길이 -infos[key]
배열 중score
의 위치 인덱스 값을 하면, 결국 해당 쿼리의 조건을 만족하며, 점수가 같거나 더 높은 애들만 나오겠죠? - 결국 숫자 타입의 결과 값을 반환하는 겁니다.
- 반환된
getResult
의 값을 이제answer
에push
해줍니다.
// 이분 탐색입니다. 해당 값이 어느 인덱스에 있을지를 탐색하여 결과를 반환합니다. const binarySearch = (arr, target) => { let left = 0; let right = arr.length - 1; let mid = Math.floor((left + right) / 2); while(left <= right) { if (arr[mid] === target) return mid; if (arr[mid] < target) left = mid + 1; else right = mid - 1; mid = Math.floor((left + right) / 2); } // 항상 기준이 되는 점수의 인덱스는 이 값보다 1 클 수밖에 없습니다. return mid + 1; } const getInfos = (info) => { const infos = {}; // 해시 테이블 생성해줄 거에요. info.forEach(str => { // 이제 해시 테이블에 `info`를 처리해줘야겠죠?! const arr = str.split(" "); // 먼저 " " 기준으로 string을 분리해줍시다. const score = parseInt(arr.pop()); // 정수로 바꿔줄 거에요. const key = arr.join(""); // key를 javabackendjuniorpizza와 같은 형태로 해줄 거에요. if (infos[key]) infos[key].push(score) else infos[key] = [score]; // [150]의 형태로 배열에 점수를 넣어줘요. }); for (const key in infos) { // 다 처리된 이후에는 각 키의 점수 배열을 정렬해줍니다. // 이건 이분탐색을 위한 거에요. infos[key].sort((a, b) => a - b); } return infos; } const getResult = (infos, query, score) => { // 키들을 배열 형태로 갖고 옵시다. const infosKey = Object.keys(infos); // 여기서 이제 키들에 대해 쿼리 조건을 만족하는 것들을 필터링해서 배열로 반환하고 (filter) // reduce로 전체 점수 배열의 길이값 - 이분 탐색 결과 인덱스 값을 해줍니다. // 그러면 결국 값이 같거나 큰 애들의 수만큼 값이 나오겠죠? (정렬되어 있으니까요) // 이를 누산해줍니다. return infosKey .filter(key => query.every(v => key.includes(v))) .reduce((acc, key) => acc + infos[key].length - binarySearch(infos[key], score), 0); } const solution = (info, query) => { let answer = []; const infos = getInfos(info); // solution query .map(q => q .split(/ and | |-/i) //' and '와 ' '와 '-'이 들어가 있는 친구들 기준으로 split 처리해줘요. .filter(v => v !== "") // `split`에 의해 값이 "" 처리가 된 친구들을 없애줍니다. ) // 쿼리 조건들을 필터링해줄 거에요. .forEach(query => { const score = query.pop(); const result = getResult(infos, query, score); answer.push(result) // getResult로 인해 누산된 결과값을, answer에 넣어줍시다. }) return answer; }

결과가 나왔네요. 이게 레벨 2라니...
열심히 달리신 여러분... 광광 울어줍시다😂😂😂
은찬
const solution = (info, query) => { const answer = []; const infoParsingData = new Map(); const queryParsingData = []; // info 데이터 파싱 for(let i = 0; i < info.length; i++){ const data = info[i].split(" "); const string = Array.from({length: 4}, () => Array(2).fill("-")); const score = parseInt(data.splice(4)); for(let j = 0; j < 4; j++){ string[j][0] = data[j]; } for(const lang of string[0]){ for(const position of string[1]){ for(const career of string[2]){ for(const food of string[3]){ const key = lang + position + career + food; const value = infoParsingData.has(key) ? infoParsingData.get(key) : []; value.push(score); infoParsingData.set(key, value); } } } } } // infoParsingData 정렬 for(const [_, value] of infoParsingData){ value.sort((a, b) => b - a); } // query 데이터 파싱 및 답 찾기 for(let i = 0; i < query.length; i++){ const data = query[i].split(/\sand\s/).join("").split(" "); const score = parseInt(data.splice(1)); const condition = data.join(""); const correctData = infoParsingData.has(condition) ? infoParsingData.get(condition) : []; let front = 0; let back = correctData.length - 1; while(front <= back){ const mid = Math.floor((front + back) / 2); if(correctData[mid] >= score){ front = mid + 1; } else{ back = mid - 1; } } answer.push(front); } return answer; }
효성
const LANG = { all : 0b111000000, java : 0b100000000, python : 0b10000000, cpp : 0b1000000, }; const POS = { all : 0b110000, backend : 0b100000, frontend : 0b10000, }; const CAREER = { all : 0b1100, junior : 0b1000, senior : 0b100, }; const FOOD = { all : 0b11, pizza : 0b10, chicken : 0b1, } function lowerBound(array, value) { let low = 0; let high = array.length; while (low < high) { const mid = low + ((high - low) >> 1); if (value <= array[mid]) { high = mid; } else { low = mid + 1; } } return low; } function solution(info, query) { const hashMap = new Map(); info.map(eachInfo => eachInfo.split(" ")) .sort((a,b) => a[a.length-1] - b[b.length-1]) .forEach(eachInfo => { const [lang, pos, career, food, score] = eachInfo; const languages = [LANG.all, LANG[lang]]; const positions = [POS.all, POS[pos]]; const careers = [CAREER.all, CAREER[career]]; const foods = [FOOD.all, FOOD[food]]; for(const l of languages) { for(const p of positions) { for(const c of careers) { for(const f of foods) { const condition = l | p | c | f; if(!hashMap.has(condition)) { hashMap.set(condition, []); } const scores = hashMap.get(condition); scores.push(+score); } } } } }); return query.map(eachQuery => { const [lang, pos, career, food, score] = eachQuery.split(/ and | /).map(q => q === '-' ? 'all' : q); const condition = LANG[lang] | POS[pos] | CAREER[career] | FOOD[food]; if(!hashMap.has(condition)) { return 0; } const scores = hashMap.get(condition); const idx = lowerBound(scores, score) return scores.length - idx; }); }