ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Programmers/Javascript] 기능개발
    카테고리 없음 2021. 7. 8. 08:50

    2021.07.08

     

    이 문제는 백준의 달팽이 문제랑 비슷한 것 같다.

     

    How to solve

     

    1. 각 기능별로 완성까지 남은 기간을 구하는 로직

     

    // 완성까지 남은 기간
    
    
    // 올림사용
    function toduedays(progress, speed) {
        
      return Math.ceil((100 - progress) / speed )
    
    }
    
    
    // 직관적으로 표현
    function toduedays(progress, speed) {
        
        let duedays = parseInt((100 - progress) / speed )
        if((100 - progress) % speed == 0) return duedays;
        else return duedays + 1;
    
    }

     

    - 발매까지 남은 기간을 구할 때, 100%가 되기까지 모자라는 부분도 하루로 쳐줘야 한다.

    예를들어, 완성까지 60%가 남았는데 30%씩 진행한다면 2일 후에야 완성이 된다.

    그렇기 때문에 소수점까지 하루로 치는 Math.ceil함수를 썼는데, 이전에도 얘기했듯이 해당 함수를 쓰는것이 과연 추후에 타인이 코드를 볼 때, 왜 해당함수를 썼는지 이해할 수 있느냐이다. 

     

    그래서 100%에 정확히 도달하면 해당 일수를 반환하고, 그렇지 않다면 해당일수에서 1을 더한 값을 반환하도록 코드를 구성했는데 둘중에 어떤 것이 좋은 코드일까?

     

     

    위에서 함수를 써서 따로 뺀 이유는, 기능을 잘게 쪼개서 사용하기에 나도 한번 밖으로 빼봤다. 

     

     

     

    2. 위 로직으로 바탕으로 실제로 각 프로세스 별로 남은 일수를 구한다.

     

    let publish = [];
    let compare = 0;
    
    while (progresses.length > 0) {
    
        let progress = progresses.shift()
        let speed = speeds.shift()
        let duedays = toduedays(progress, speed)
    
        if(compare <= duedays) {
            publish.push(duedays)
            compare = duedays
        } else publish.push(compare)    
    }
    
    console.log(publish)

     

    정말 직관적으로 구했다.

    주어진 배열에서 진행정도와 스피드의 요소를 하나씩 빼서, 위에서 만든 남은 일수를 구하는 함수에 넣었고

     

    앞의 진행단계의 발매일보다 뒤 단계의 발매일이 클 수 없으니 앞단계 발매일을 compare라는 변수에 넣어서 각 남은일수와 비교했다. 그리고 해당 결과를 publish라는 배열에 넣었다.

     

     

     

     

    3. 구해진 완성일수 별로 숫자를 카운팅한다. (key, value로 묶는다)

     

    // 완성일수별로 카운팅
    
    // forEach사용
    let hashed = []
    
    publish.forEach(entry => {
      // publish의 요소를 hashed의 키로 가져옴
      hashed[entry] = (hashed[entry] || 0 ) + 1;
    })
    
    console.log(hashed) //[7, 7, 9]
    console.log(hashed.length) //10
    
    
    // reduce사용
    let result = publish.reduce((arr,cur) => {
            arr[cur] = (arr[cur] || 0) + 1
            return arr}, hashed)
    
    console.log(result); // 위와 같음

     

     

    그리고 해당 배열의 value값만 가져와 answer에 넣는다.

     

    let answer = [];
    
    for ( let i = 0; i < hashed.length; i++) {
      answer += hashed[i]
    }
    
    console.log(answer) //왜 희소배열이 나올까?

     

     

    여기서 문제가 생겼다.

    answer에서 희소배열로 출력되는 것이다. 아니 왜지?

     

    왜 희소배열이죠..?

     

    2번에서 구한 publish (완성일수 배열)는 분명 [7, 7, 9] 이렇게 3자리수이고 디버깅모드로 돌려봐도 길이가 3이 나오는데

    해당 배열을 순회해서 key, value를 구하면 길이가 10이 나와버린다. 아니 왜지??

     

     

    메서드로 하면 디버깅할 때 중간과정없이 결과만 나와서 대체 뭐가 문제인지를 모르기때문에 중간 계산과정을 확인해보기 위해서 for문으로 만들었다. 

     

    let hashed = []
    
    for (let i = 0; i < publish2.length; i++) {
    
     if (hashed[publish2[i]] != 0) {
      hashed[publish2[i]] = hashed[i] + 1;
     } else {
      hashed[publish2[i]] = 1;
     }
    }

     

    아하.. hashed[7] 이라고 넣으니까 7번째 인덱스 위치에 값을 넣는다.

    아아. 희소배열이 나온 이유가 key가 숫자니까 해당 인덱스에 값을 넣어서 그런거였다!

     

    그럼 객체로 바꿔볼까?

    객체로 바꾸니 { '7' : 2, '9' : 1 }로 나온다. 오오

     

    그리고 해당 배열의 value값만 가져와 answer에 넣는건 메서드를 사용하면 간단하다.

    (객체의 프로퍼티 키, 값 불러오는 법)

     

     

     

    그래서 제출한 최종코드

     

    function solution(progresses, speeds) {
        
    // 완성까지 남은 기간
    function toduedays(progress, speed) {
        
        let duedays = parseInt((100 - progress) / speed )
        if((100 - progress) % speed == 0) return duedays;
        else return duedays + 1;
    
    }
    
    
    // 배열에서 하나씩 꺼내기
    // 각 기능의 완성일수
    
    let publish = [];
    let compare = 0;
    
        
    while (progresses.length > 0) {
    
        let progress = progresses.shift()
        let speed = speeds.shift()
        let duedays = toduedays(progress, speed)
    
        if(compare <= duedays) {
            publish.push(duedays)
            compare = duedays
        } else publish.push(compare)    
    }
    
    
    // 완성일수별로 카운팅해서 객체에 넣기
    
    let result = publish.reduce((arr,cur) => {
            arr[cur] = (arr[cur] || 0) + 1
            return arr}, {})
    
    // 객체의 값 불러오기
    let answer = Object.values(result)
        
    return answer;
    }

     

    눙물난다.

     

    이게 이렇게 눈물날 일이냐구.ㅠㅠ 진짜 어제 계속 뻘짓한거 생각하면 행복하다..

    다른사람 코드도 보긴 했는데 대체 내 코드가 뭐가문젠데! 내가 진짜 이거 무조건 성공시키고만다! 해서 만들어서 그런지 더 그러네..ㅠ

     

    원래는 이렇게 구구절절 짜놓고 코드리뷰하면서 정리하려고 했었는데 이렇게 짜는거 조차도 이렇게 오래걸릴일이야?ㅠ

    내 생각엔 뒤쪽에서 '희소배열'나와서 그런 듯..

    이제 다른사람들꺼 코드 확인해보러 가야지.

     

     

    다른 풀이 방법

     

    1. 첫번째 프로그램이 완성되는 일수가 다음 프로그램이 출시되는데 영향을 미치기 때문에 

    첫번째 프로그램이 완성되는 일수를 다음 프로그램 완성일수 계산 식에 넣는다.

     

    def solution(progresses, speeds):
    
        answer = []
        time = 0
        count = 0
        
        while len(progresses)> 0:
        	
            // 3) 첫번째 진행률의 time을 speed에 곱해서 진행률이 100%가 넘으면 해당 요소를 빼내고 count 1을 올린다.
            
            if (progresses[0] + time*speeds[0]) >= 100:
                progresses.pop(0)
                speeds.pop(0)
                count += 1
                
           // 4) 첫번째 진행률보다 모자라게 되면 count를 배열에 넣고 초기화 시켜준다.
           // 5) 그리고 아직 progresses가 0보다 크니까 다시 위의 if문으로 돌아간다.
           
            else:
                if count > 0:
                    answer.append(count)
                    count = 0
                    
            // 1) 첫번째 진행률이 7이 될때까지 time을 늘린다.
            // 2) 그리고 그 time은 fix되어있다.    
            
            	 time += 1
                 
        answer.append(count)
        return answer

    출처: https://huidea.tistory.com/15

     

     

    나도 위와같은 로직을 생각했었는데 이게 코드로 구현이 잘 안됐다.

    나는 첫번째 날의 일수를 다른 일수를 구하는데 넣는다는 생각을 못했다.

    그러다보니 막 FLAG를 세우고 while과 for문 안에서 헤메이는... 뫼비우스의 띠에서 벗어나질 못했다..

     

    어렴풋이 개념은 알고 있었는데 이제 알겠다아.

     

     

    Feedback

     

    1. 첫번째 작업의 일수보다 작으면 첫번째 작업이 완성될 때 까지 기다려야 한다.

     

    => 첫번째 작업일수 > 현재 작업일수

    => 현재 작업진행률 * 첫번째 작업일수 >= 100

     

     

    2. 첫번째 작업일수가 현재 작업일수보다 큰 상태동안 count를 증가시킨다.

    만약, 현재작업일수가 커지면 break한다.

     

     

    3. 나는 이런 문제가 나오면 첫번째 인덱스와 두번째 인덱스를 비교하려 한다.

    그러면 첫번째 인덱스를 고정값으로 만들어서 별도의 변수에 넣어줘야하는데 그것보다 더 효율적인게 있을 것 같다.

     

     

Designed by Tistory.