[프로그래머스] 배열 관련 문제들(feat. 결과 통계 계산기)

Chaejung·2023년 6월 13일
0

알고리즘_JavaScript

목록 보기
7/12
post-thumbnail

1. 배열의 원소만큼 추가하기

코드 1

function solution(arr) {
    let answer = [];
    arr.forEach((ele) => {
        for (let i = 0;i<ele;i++){
            answer.push(ele)
        }
    })
    return answer;
}

반복문을 조금 더 줄이고 예쁘게 구성할 수 있는 방법이 없을까.
짜잔!

코드 2

function solution(arr) {
    let answer = [];
    arr.forEach((ele) => {
        answer.push(...Array(ele).fill(ele))
    })
    return answer;
}

python의 List comprehension처럼
특정 원소로 초기화하는 배열을 만들 때, Array(_갯수).fill(_채우고 싶은 수)로 쓰면 될 것 같다.

코드 3

function solution(arr) {
    let answer = [];
    arr.forEach((ele) => {
        answer.push(...Array.from({length: ele}, _ => ele))
    })
    return answer;
}

시간, 메모리 비교하기

코드1코드2코드3
평균 시간0.207ms0.118ms0.359ms
평균 메모리34.925MB35.031MB34.931MB
최고 시간0.91ms0.31ms1.11ms
최저 시간0.04ms0.04ms0.07ms
최고 메모리37.4MB37.8MB37.5MB
최저 메모리33.5MB33.5MB33.5MB
시간 표준 편차0.1880.0340.280
메모리 표준 편차19.34521.05720.462

결과적으로 코드2가 시간 효율성이 가장 높다.
즉, 배열 초기화에서 더 효율적인 것은 Array.from() 메서드보다 Array.fill()이다.

재미삼아 만들어본 프로그래머스 시간, 공간 통계 계산기

const text = `테스트 결과 copy and paste`
const testCount = text.split('테스트').length-1

let time = []
let memory = []

text.split('통과 (').forEach((ele, idx) => {
    if(idx == 0) return
    let value = ele.split(')')[0].split(', ')
    time.push(parseFloat(value[0].slice(0, 4)))
    memory.push(parseFloat(value[1].slice(0, 4)))
})
const getAverage = (data) => (data.reduce((a, b) => a+b)/testCount).toFixed(3)
const averageTime = getAverage(time)
const averageMemory = getAverage(memory)
const getStandardDeviation = (data, average) => ((data.reduce((a, b) => a + (b-average)**2))/testCount**(1/2)).toFixed(3)
const SDT = getStandardDeviation(time, averageTime)
const SDM = getStandardDeviation(memory, averageMemory)

console.log(`평균 시간: ${averageTime}ms`)
console.log(`평균 메모리: ${averageMemory}MB`)
console.log(`최고 시간: ${Math.max(...time)}ms`)
console.log(`최저 시간: ${Math.min(...time)}ms`)
console.log(`최고 메모리: ${Math.max(...memory)}MB`)
console.log(`최저 메모리: ${Math.min(...memory)}MB`)
console.log(`시간 표준 편차: ${SDT}`)
console.log(`메모리 표준 편차: ${SDM}`)

사용 방법 예시
text에 프로그래머스 코드 실행 결과를 그대로 드래그에서 복사한 것을 붙여넣기 하면 된다!

2. 배열의 길이에 따라 다른 연산하기

코드

function solution(arr, n) {
    arrLength = arr.length
    let answer = arr.map((ele, idx) => {
        if (arrLength % 2 == 0 ){
            if (idx % 2 == 1){
                return ele += n
            }
        } else {
            if (idx % 2 == 0) {
                return ele += n
            }
        }
        return ele
    });
    return answer;
}

조건문의 가독성을 조금 더 올리고 코드를 줄일 수 있는 방법이 없을까

function solution(arr, n) {
    arrLength = arr.length
    let answer = arr.map((ele, idx) => {
        if (arrLength % 2 == 0 & idx % 2 == 1) return ele += n
        if (arrLength % 2 == 1 & idx % 2 == 0) return ele += n
        return ele
    });
    return answer;
}

흠... 아직도 마음에 썩 들진 않는다...

3. 배열 만들기2

코드(틀렸습니다)

function solution(l, r) {
    var answer = [];
    let start = l.toString().length;
    let end = r.toString().length;
    let possibleNum = Array(7).fill([])
    possibleNum[0] =  []
    possibleNum[1] = [0, 5]
    for (let i = start;i<=end;i++){
        if (possibleNum[i].length > 0) continue
        let result5 = possibleNum[i-1].map((ele) => parseInt('5'+ele.toString())) 
        let result50 = possibleNum[i-2].map((ele) => parseInt('50'+ele.toString()))
        possibleNum[i] = result5.concat(result50)
    }
    let allNum =  [].concat.apply([], possibleNum).sort((a, b) => a-b)
    let filteredNum = allNum.filter((v) => l<=v & v<=r)
    answer = filteredNum.length > 0 ? filteredNum : [-1]
    
    return answer
}

유사 DP로 풀려고 했으나 틀렸다.
곰곰히 생각해 보니 이 코드는 50005인 경우, 즉 메모이제이션으로 참고하는 앞 수가 5일 때 000...05으로 조합되지 않아서 커버가 되지 않는다.

그래서 갈아엎고 다른 방법으로 도전했다.

코드

function solution(l, r) {
    var answer = [];
    let possible = []
    let end = r.toString().length
    for (let i = 1;i<2**end;i++){
        possible.push(i.toString(2))
    }
    fiveOrZero = possible.map((ele)=> ele*5)
    answer = fiveOrZero.filter((ele) => l<=ele & ele<=r)
    answer = answer.length > 0 ? answer: [-1]
    return answer
}

Lv.0인데 거의 1시간을 잡았다... 허어...
결국 0과 5만 쓰이는 숫자를 만드는 것이니 이진법으로 키워드를 돌려 접근했더니 정답!
오늘 스터디로 푼 문제인데, 완전탐색 + 정규표현식으로 풀이한 결과와 비교해본다.

시간, 메모리 비교하기

이진법완전탐색 + 정규표현식
평균 시간3.502ms14.742ms
평균 메모리33.650MB37.850MB
최고 시간4.27ms94.6ms
최저 시간3.16ms0.18ms
최고 메모리33.8MB52.7MB
최저 메모리33.6MB33.5MB
시간 표준 편차1.0052708.405
메모리 표준 편차7.188111.008

확실히... 완전탐색으로 하면 극단적인 데이터에서 굉장한 결과가 갑자기 나온다.

여기서 드는 의문!
과연 시간과 메모리의 편차가 크지 않은 것이 좋은 알고리즘인가?
즉, 시간 표준 편차와 메모리 표준 편차가 작을 수록 좋은 알고리즘인가?

4. 배열 조각하기

코드

function solution(arr, query) {
    let answer = arr
    query.forEach((queryIdx, idx) => {
        if (idx % 2 == 0){
            answer = answer.slice(0, queryIdx+1)
        } else {
            answer = answer.slice(-(answer.length-queryIdx))
        }
    })
    
    return answer;
}

코딩 기초 트레이닝 중에서 정답률이 2번째로 낮은 친구여서 긴장했지만
별거 없었던 문제였다.

function solution(arr, query) {
    let answer = arr
    query.forEach((queryIdx, idx) => {
        let start = idx % 2 == 0 ? 0: queryIdx
        let end = idx % 2 == 0 ? queryIdx+1:answer.length
        answer = answer.slice(start, end)
    })
    
    return answer;
}

시간을 따졌을 때 개선 코드가 조금 더 빠른 경우가 있었는데, 아주 미미한 차이라 비교하는 것이 무의미할 정도이다.

조건문이 살짝 가독성이 떨어져서 삼항 연산자로 한 번 더 수정하여 개선시켰다.

profile
프론트엔드 기술 학습 및 공유를 활발하게 하기 위해 노력합니다.

0개의 댓글