DEVELOP
article thumbnail

디스크 컨트롤러 #42627

https://school.programmers.co.kr/learn/courses/30/lessons/42627

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

더보기

문제 설명

하드디스크는 한 번에 하나의 작업만 수행할 수 있습니다. 디스크 컨트롤러를 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 요청이 들어온 순서대로 처리하는 것입니다.

예를들어

- 0ms 시점에 3ms가 소요되는 A작업 요청
- 1ms 시점에 9ms가 소요되는 B작업 요청
- 2ms 시점에 6ms가 소요되는 C작업 요청

와 같은 요청이 들어왔습니다. 이를 그림으로 표현하면 아래와 같습니다.

한 번에 하나의 요청만을 수행할 수 있기 때문에 각각의 작업을 요청받은 순서대로 처리하면 다음과 같이 처리 됩니다.

- A: 3ms 시점에 작업 완료 (요청에서 종료까지 : 3ms)
- B: 1ms부터 대기하다가, 3ms 시점에 작업을 시작해서 12ms 시점에 작업 완료(요청에서 종료까지 : 11ms)
- C: 2ms부터 대기하다가, 12ms 시점에 작업을 시작해서 18ms 시점에 작업 완료(요청에서 종료까지 : 16ms)

이 때 각 작업의 요청부터 종료까지 걸린 시간의 평균은 10ms(= (3 + 11 + 16) / 3)가 됩니다.

하지만 A → C → B 순서대로 처리하면

- A: 3ms 시점에 작업 완료(요청에서 종료까지 : 3ms)
- C: 2ms부터 대기하다가, 3ms 시점에 작업을 시작해서 9ms 시점에 작업 완료(요청에서 종료까지 : 7ms)
- B: 1ms부터 대기하다가, 9ms 시점에 작업을 시작해서 18ms 시점에 작업 완료(요청에서 종료까지 : 17ms)

이렇게 A → C → B의 순서로 처리하면 각 작업의 요청부터 종료까지 걸린 시간의 평균은 9ms(= (3 + 7 + 17) / 3)가 됩니다.

각 작업에 대해 [작업이 요청되는 시점, 작업의 소요시간]을 담은 2차원 배열 jobs가 매개변수로 주어질 때, 작업의 요청부터 종료까지 걸린 시간의 평균을 가장 줄이는 방법으로 처리하면 평균이 얼마가 되는지 return 하도록 solution 함수를 작성해주세요. (단, 소수점 이하의 수는 버립니다)

제한 사항
  • jobs의 길이는 1 이상 500 이하입니다.
  • jobs의 각 행은 하나의 작업에 대한 [작업이 요청되는 시점, 작업의 소요시간] 입니다.
  • 각 작업에 대해 작업이 요청되는 시간은 0 이상 1,000 이하입니다.
  • 각 작업에 대해 작업의 소요시간은 1 이상 1,000 이하입니다.
  • 하드디스크가 작업을 수행하고 있지 않을 때에는 먼저 요청이 들어온 작업부터 처리합니다.
입출력 예jobsreturn
[[0, 3], [1, 9], [2, 6]] 9
입출력 예 설명

문제에 주어진 예와 같습니다.

  • 0ms 시점에 3ms 걸리는 작업 요청이 들어옵니다.
  • 1ms 시점에 9ms 걸리는 작업 요청이 들어옵니다.
  • 2ms 시점에 6ms 걸리는 작업 요청이 들어옵니다.
문제가 잘 안풀린다면😢

힌트가 필요한가요? [코딩테스트 연습 힌트 모음집]으로 오세요! → 클릭

나의 풀이

function solution(jobs) {
  let sum = 0; // 걸린시간 더하는 변수
  let sec = 0; // 현재 시간(ms)
  const size = jobs.length; // 작업의 갯수

  while (jobs.length > 0) {
    if (!jobs.some((j) => j[0] <= sec)) {
      sec++;
      continue;
    }

    const target = jobs
      .filter((j) => j[0] <= sec)
      .sort((a, b) => a[1] - b[1])[0];

    sec += target[1];
    sum = sum + (sec - target[0]);
    jobs.splice(jobs.indexOf(target), 1);
  }

  return Math.floor(sum / size);
}
  • 평균 시간을 구하기 위해 걸린 시간을 더하는 변수 sum을 0으로 초기화 
  • 현재 시간(ms)을 뜻하는 변수 sec을 0으로 초기화
  • 평균 시간을 구하기 위해 작업의 갯수인 size를 최초 jobs 변수의 크기로 대입

 

  • jobs 배열의 사이즈가 0 이상 (하나라도 작업이 있으면)이면 while문 안을 반복한다.
    • 만약 현재 jobs 배열에 현재 시각 기준 도착한 작업이 없으면 sec를 1 증가시키고, continue한다. 
    • 실행하고자 하는 작업을 target 변수에 대입시키는데,
      • 현재 jobs 배열 중에서 현재 시각에 도착한 작업들만 필터링한 후,
      • 작업 시간이 짧은 순으로 정렬한 배열의 
      • 첫번째 요소가 target이 된다. 
    • 현재 시각에 실행한 작업의 실행시간만큼 더해준다.
    • sum 변수에 현재 시각에서 작업이 요청된 시간을 빼서 더해준다. 
    • indexOf 함수를 통해 target의 인덱스값을 찾고, splice로 해당 요소를 제거한다. 
  • sum을 size로 나눈 값을 Math.floor 함수로 소수점을 버려주고 리턴한다. 

다른 풀이 (waiting 배열 따로 사용) 

function solution(jobs) {
  jobs.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
  const waiting = []; // 대기 중인 작업들
  const count = jobs.length; // 전체 작업의 갯수

  let sum = 0; // 걸린시간 더하는 변수
  let time = 0; // 현재 시각

  while (jobs.length + waiting.length) {
    let target; // 현재 작업
    while (jobs.length && jobs[0][0] <= time) {
      waiting.push(jobs[0] && jobs.shift());
    }
    if (waiting.length) {
      target = waiting.sort((a, b) => a[1] - b[1] || a[0] - b[0]).shift();
    } else {
      target = jobs.shift();
      time = target[0];
    }

    time += target[1];
    sum += time - target[0];
  }
  return Math.floor(sum / count);
}
  • 초기 jobs 배열을 정렬한다. 
    • 요청시간이 빠른 순으로 정렬 
    • 요청시간이 같으면 걸리는 시간이 적은 순으로 정렬
  • 대기중인 작업들이 들어갈 배열 waiting을 빈 배열로 초기화
  • 전체 작업의 갯수를 count에 대입
  • 걸린시간을 더하는 변수 sum을 0으로 초기화
  • 현재 시각을 나타내는 변수 sec을 0으로 초기화
  • jobs의 길이와 waiting의 길이의 합이 0이상일때 (모두 빈 배열이 아닐 때) 아래를 반복한다.
    • 현재 작업을 나타내는 변수 target을 선언한다. (null)
    • jobs의 길이가 0이상이고, 첫번째 요소의 요청시간이 현재 시각보다 작거나 같으면 (요청이 도착한 상태이면) 아래를 반복
      • jobs의 첫번째 요소를 waiting배열에 push한다. (jobs shift하여 첫번째 요소 제거)
    • waiting에 대기 중인 작업이 있으면,
      • waiting 배열을 걸리는 시간이 적은 순, 걸리는 시간이 같으면 요청시간 순으로 정렬한 후, 첫번째 요소를 꺼내 target으로 대입한다.
    • waiting에 대기 중인 작업이 없으면,
      • jobs에서 첫번째 요소를 꺼내어 target으로 선정하고,
      • 현재 시각을 타겟의 요청 시간으로 대입한다. ( target이 요청된 시각으로 jump )
    • 현재 시각에 target이 걸리는 시간을 더한다. 
    • 현재시간에서 target이 요청된 시간을 뺀 값을 sum에 더한다. 
  • sum을 count로 나눈 값을 내림하여 리턴한다. 

나의 풀이와 다른 풀이의 비교

profile

DEVELOP

@JUNGY00N