제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
Programmers 알고리즘 고득점 Kit입니다.

포인트

가장 최소의 처리량 평균 시간을 구하는 문제였습니다. 요청시간이 빠른 순대로 정렬을 하면 짧은 작업시간을 가지는 일들에 대해서는 너무 오래 기다리게 되고, 짧은 작업시간 순대로 정렬을 하면 요청이 먼저 온 작업을 처리를 하지 못하게 됩니다. 

따라서 현재 시간에 따라 처리 가능한 작업을 구하고 그 중에서 요청시간이 짧은 것을 먼저 처리합니다.

소스코드

import java.util.*;

class Solution {
    
    static class Job implements Comparable<Job> {
        int requestTime, workingTime;
        
        public Job(int requestTime, int workingTime) {
            this.requestTime = requestTime;
            this.workingTime = workingTime;
        }
        
        @Override
        public int compareTo(Job j) {
            if (this.requestTime == j.requestTime) {
                return this.workingTime - j.workingTime;
            }
            return this.requestTime - j.requestTime;
        }
    }
    
    public int solution(int[][] jobs) {
        PriorityQueue<Job> disk = new PriorityQueue<>();
        int len = jobs.length;
        
        for(int[] job: jobs) {
            disk.add(new Job(job[0], job[1]));
        }
        
        int time = 0; // 현재 시간
        int ans = 0; // 처리량 평균 구하기
        List<Job> execList = new ArrayList<>();
        
        while (!disk.isEmpty() || !execList.isEmpty()) {
            // 현재 시간에 요청된 작업을 모두 execList에 추가
            while (!disk.isEmpty() && time >= disk.peek().requestTime) {
                execList.add(disk.poll());
            }

            // 작업을 소요 시간 기준으로 정렬
            if (!execList.isEmpty()) {
                Collections.sort(execList, Comparator.comparingInt(job -> job.workingTime));
                Job exec = execList.remove(0);
                if (time < exec.requestTime) {
                    time = exec.requestTime;
                }
                time += exec.workingTime;
                ans += time - exec.requestTime;
            } else if (!disk.isEmpty()) {
                time = disk.peek().requestTime;
            }
        }
        
        return ans / len;
    }
}

코드 설명

Job 클래스

  • Job 클래스는 Comparable 인터페이스를 구현하며, 작업의 요청 시간(requestTime)과 소요 시간(workingTime)을 필드로 가지고 compareTo 메서드는 Job 객체를 요청 시간 순서로 정렬합니다. 요청 시간이 동일할 경우, 소요 시간 기준으로 정렬하도록 조건을 설정할 수 있습니다.

 

  • PriorityQueue<Job> disk = new PriorityQueue<>();
    작업 요청 시간 기준으로 정렬되는 우선순위 큐를 초기화합니다. Job 객체를 담아 요청 시간이 빠른 순서대로 작업을 처리할 수 있습니다.
  • while문 내부 변수 사용부분
    • time은 현재 시각을 나타내며, ans는 작업 완료까지 걸린 총 시간을 누적합니다.
    • execList는 현재 처리 가능한 작업 목록입니다.
  • while (!disk.isEmpty() || !execList.isEmpty()) { ... }
    • disk 큐의 작업 중 현재 time에 요청된 작업을 execList로 이동합니다.
    • execList에 작업이 있으면 소요 시간 기준으로 정렬하고, 가장 짧은 작업을 선택하여 실행합니다.
    • time이 해당 작업의 요청 시간보다 작으면, time을 그 요청 시간으로 맞춥니다.
    • time을 해당 작업의 소요 시간만큼 증가시키고, 요청부터 종료까지 걸린 시간(time - requestTime)을 ans에 더합니다.
    • 만약 execList가 비어 있고 disk에 작업이 남아 있다면, time을 다음 작업의 요청 시간으로 설정하여 작업을 진행할 수 있게 합니다.

 

제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
Programmers 알고리즘 고득점 Kit입니다.

포인트

최솟값을 찾기 위해 정렬을 사용해도 되지만 가장 효율적인 자료 구조 Heap을 이용하여 스코빌 지수의 최솟값을 찾도록 코드를 구현하였습니다.

소스코드

import java.util.*;

class Solution {
    public int solution(int[] scoville, int K) {
        PriorityQueue<Integer> scovilles = new PriorityQueue<>();
        
        for (int level: scoville) {
            scovilles.add(level);
        }
        
        int mix = -1;
        int ans = 0;
        while (scovilles.peek() < K) {
            if (scovilles.size() < 2) {
                return -1;
            }
            int first = scovilles.poll();
            int second = scovilles.poll();
            mix = first + second * 2;
            scovilles.add(mix);
            ans++;
        }
        
        return ans;
    }
}

코드 설명

  • PriorityQueue<Integer> scovilles = new PriorityQueue<>();
    스코빌 지수를 저장하는 Heap을 생성합니다. 해당 힙은 최소 힙으로 구현합니다.
  • 섞은 음식의 스코빌 지수
    • while 루프는 큐의 최솟값(scovilles.peek())이 K 미만인 동안 반복됩니다.
    • 이때 큐의 크기가 2 미만이 되면, 더 이상 결합할 수 없으므로 -1을 반환하여 목표를 달성할 수 없음을 나타냅니다.
    • 최솟값 두 개를 꺼내어(poll() 메서드 사용) 결합하여 새로운 스코빌 지수(first + second * 2)를 계산합니다.
    • 새로 만든 스코빌 지수를 큐에 다시 추가하고, 결합 횟수 ans를 증가시킵니다.
  • 섞은 횟수를 반환합니다.
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
접은 글을 통해 먼저 답변을 해보시고 제가 정리한 답을 확인해보시기 바라겠습니다!!

면접 리스트

NAT 네트워크를 사용했을때의 사이드 이펙트는 없는가?

더보기

NAT 네트워크를 사용하면 사이드 이펙트가 있습니다.

 

기존 라우터는 4계층의 하드웨어로써 전송계층의 port 번호는 보지 못합니다. 하지만 NAT 도입시, 세그먼트에 해당하는 머신에 데이터를 주고 받기위해 포트번호를 라우터가 열람할 수 있게 되어 스푸핑이 일어나 중간자 공격이 일어날 수 있습니다.

 

또 NAT은 IP 주소와 포트번호를 수정하여 Transport layer의 특징인 end to end 원칙을 위배하고 문제 해결 프로세스를 복잡하게 만들 수 있습니다.

 

또한 NAT은 오버헤드를 도입하여 트래픽이 많은 네트워크에서 네트워크 성능에 영향을 미칠 수 있습니다. 주소 변환과정에서 네트워크 병목현상이 일어날 수 있습니다. NAT은 공용 IP를 보존하고 IP 주소의 확장성을 제공하지만 보안에 취약합니다.

라우팅 알고리즘은 모든 라우터에서 실행되어야 하는가?

더보기

라우팅 알고리즘네트워크 전체에서 효율적이고 안정적인 패킷 라우팅을 보장하기 위해 모든 라우터에서 실행되어야 합니다.

 

특정 라우터에서만 실행될 경우 라우팅 결정이 최적화 되지 않고 패킷 전달이 비효율적일 수 있습니다. 왜냐하면 각 라우터는 네트워크의 상황에 따라 경로가 실시간으로 변경되어 라우팅 정보를 교환하고 라우팅 테이블을 업데이트하며 네트워크 조건에 따라 새 경로를 계산할 수 있기 때문입니다. 또 모든 라우터에서 라우팅을 실행하면, 로드 밸런싱 기술을 활용할 수 있습니다. 리소스 활용률을 최적화하고 정체를 방지하기 위한 트래픽을 여러 경로로 분산시킵니다. 이를 사용하기 위해 네트워크 트래픽을 각 라우터마다 계산해야하므로 라우팅 알고리즘이 모든 라우터에서 적용되어야 합니다.

 

이러한 이유로 라우팅 알고리즘은 모든 라우터에서 실행되어야 합니다.

라우터에서의 라우팅과 포워딩의 차이를 설명해주세요.

더보기

라우팅과 포워딩은 네트워크 레이어의 역할로 패킷을 전달하는 데에 목적이 있습니다. 각각을 살펴보면

 

라우팅은 데이터 패킷이 네트워크를 통해 대상에 도달할 수 있는 최적의 경로를 결정하는 프로세스입니다. 대상 IP 주소를 기반으로 패킷을 전달해야하는 다음 홉 또는 라우터에 대한 결정을 수행합니다. OSPF나 BGP와 같은 라우팅 알고리즘은 사용가능한 경로 및 관련 메트릭에 대한 정보를 포함하는 라우팅 테이블을 관리하고 업데이트하면서 사용됩니다.

 

포워딩수신 인터페이스에서 송신 인터페이스로 전송하는 프로세스입니다. 라우팅 결정이 이루어지면 대상 IP 주소를 검사하고 각 인터페이스의 IP 주소를 검사하여 가장 길게 맞춰진 인터페이스로 패킷을 전달하여 다음 홉으로 전송합니다.

loopback address는 무엇인가? 또 어떻게 쓰일 수 있는가

더보기

loopback address로컬 장치에서 네트워크 연결을 테스트하는 특수한 IP 주소입니다. 일반적으로 IPv4의 경우 127.0.0.1을 가지고 있으며 네트워크 응용 프로그램이 루프백 주소로 데이터를 보낼 때 기본적으로 자신에게 데이터를 보내는 것입니다. 루프백 주소로 전송되는 네트워크 트래픽을 처리하는 운영체제 내의 소프트웨어 구성 요소인 루프백 드라이버에 연결됩니다.

 

loopback address는 다양한 용도로 사용됩니다.

 

루프백 드라이버를 사용하면 루프백 주소로 주소 지정된 네트워크 패킷을 장치 내에서 내부적으로 라우팅할 수 있으므로 실제 물리적 네트워크를 통해 데이터를 전송하지 않고도 네트워크 통신을 시뮬레이션할 수 있습니다. 즉, 루프백 주소로 전송되는 네트워크 트래픽은 IP, TCP 및 UDP와 같은 프로토콜을 포함하여 장치 자체의 네트워크 스택에서 처리됩니다.

 

개발자는 네트워크 연결 없이 응용 프로그램을 루프백 주소를 이용함으로써 테스트 할 수 있습니다. 트래픽을 로컬 호스트로 유도하여 통신과 서비스가 올바르게 작동하는 지 확인할 수 있습니다. 여기서 네트워크 관련 문제를 확인하며 해결할 수 있고, 외부 네트워크 연결없이 로컬 테스트 및 검증을 수행할 수 있습니다.

default gateway는 무슨 역할을 하는가?

더보기

default gateway router는 다른 네트워크에서 또는 다른 네트워크로 향하는 네트워크 트래픽의 출입구 역할을 하는 라우터입니다. 주요한 역할로 데이터 패킷의 라우팅을 용이하게 하는 것이 있습니다.

 

기본 게이트웨이는 서로 다른 네트워크 간의 네트워크 트래픽에 대한 시작 및 종료 지점 역할을 합니다. 로컬 네트워크와 외부 네트워크 간에 데이터를 라우팅하고, 연결을 제공하며, 장치가 다른 네트워크의 장치와 통신할 수 있도록 하며, 로컬 네트워크 외부의 대상으로 데이터를 전송하는 기본 경로 역할을 하며, NAT(네트워크 주소 변환)을 수행합니다, 네트워크를 보호하기 위한 방화벽 기능과 같은 보안 기능을 제공합니다.

만약 라우팅 테이블에 다음 목적지에 대한 맵핑정보가 없다면 라우터는 어떻게 동작하는가?

더보기

라우팅 테이블에 다음 대상에 대한 매핑 정보가 없으면 라우터는 패킷을 전달하기 위한 적절한 넥스트 홉을 결정할 수 없으며 구성된 경우 패킷을 폐기하거나 기본 게이트웨이로 전송합니다.

 

패킷을 삭제하고 대상에 연결할 수 없음을 나타내는 ICMP(Internet Control Message Protocol) 메시지를 소스로 보낼 수 있습니다. 또는 기본 게이트웨이가 구성된 경우 라우터는 라우팅 테이블의 특정 경로와 일치하지 않는 패킷의 기본 종료 지점 역할을 하는 기본 게이트웨이로 패킷을 전달할 수 있습니다.

'기술면접 > 네트워크' 카테고리의 다른 글

[기술면접] 네트워크 5  (3) 2024.11.14
[기술면접] 네트워크 3  (0) 2024.11.10
[기술면접] 네트워크 2  (0) 2024.11.08
[기술면접] 네트워크 1  (2) 2024.11.06
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
접은 글을 통해 먼저 답변을 해보시고 제가 정리한 답을 확인해보시기 바라겠습니다!!

면접 리스트

여러개의 프로세스가 존재할 때 트랜스포트 레이어의 동작을 설명해보세요

더보기

응용 계층과 전송 계층 사이의 인터페이스 socket을 이용하여 세그먼트를 프로세스에게 전달합니다. 각 socket에는 매핑되어 있는 port 넘버가 있고, port 넘버는 호스트에서 실행중인 프로세스를 구분합니다. 이 포트 넘버를 소켓에 바인딩하고 데이터를 보낼 때에는 트랜스포트 레이어에서 제공하는 포트 멀티플렉싱을 합니다.

 

데이터를 받을 때에는 전송계층은 세그먼트 헤더의 대상 포트넘버를 검사하여 디멀티플렉싱을 통해 포트넘버와 연관된 소켓을 찾아 데이터를 넘겨줍니다.

소켓 생성과 삭제에서 발생하는 오버헤드를 줄이는 방법은 무엇이 있을까요?

더보기

많은 소켓의 생성과 삭제에서 발생할 수 있는 오버헤드를 줄일 방법은 소켓을 풀에 유지하여 관리하는 방법입니다.

 

연결이 필요한 경우 풀에서 사용 가능한 소켓을 할당하고 연결이 닫히면 다시 풀에 반환하여 관리하면 소켓이 재사용되므로 생성 및 삭제의 오버헤드를 줄일 수 있습니다.

 

또 다른 방법으로 TCP는 소켓 재사용을 허용하므로 새 소켓을 만들 필요없이 새로운 주소와 포트로 바인딩하여 소켓을 재사용하는 방법이 있습니다. 만약 응용 프로그램에서 허용하는 경우라면 영구 연결을 사용하여 소켓의 생성 및 삭제의 오버헤드를 줄일 수 있습니다.

N+1번의 세그먼트에 대한 ACK가 도착하고 N에 대한 ACK는 도착하지 않았을 때 TCP는 어떻게 동작하는가?

더보기

Selective ack 일 때 N+1번 세그먼트에 대한 ACK가 도착했다는 것은 N에 대해서도 패킷이 도달했다는 것을 알 수 있습니다.

 

TCP는 accumulative ack로 ack를 매 패킷마다 보내지 않을 수 있고, 순서대로 마지막에 받은 패킷에 대한 ack를 보낼 수 있습니다.

 

따라서 N+1번 세그먼트에 대한 ACK가 도착했다는 것은 N번 세그먼트에 대해서도 도달했다는 것을 알 수 있고, window사이즈만큼 sliding window를 이동시켜 다음 패킷을 보낼 준비를 합니다.

네트워크 레이어의 목적은 무엇일까요?

더보기

네트워크 레이어의 목적으로는 크게 라우팅포워딩이 있습니다.

 

라우팅출발지에서부터 목적지로까지 최적의 경로를 결정합니다. 라우팅 프로토콜과 알고리즘을 사용하여 정체 및 비용과 같은 요소를 기반으로 최적의 경로를 결정합니다.

 

포워딩은 라우팅을 통해 최적의 경로가 밝혀지면 결정된 경로를 따라 해킷 헤더의 목적지 주소를 검사하여 long prefix 알고리즘을 바탕으로 다음 노드로 데이터 패킷을 전달하는 역할을 합니다.

왜 트랜스포트 레이어에 checksum이 있는데 네트워크 레이어에도 체크섬이 있는가?

더보기

전송 계층과 네트워크 계층 모두 체크섬을 사용하여 전송된 데이터의 무결성을 보장합니다. 그러나 체크섬은 다른 용도로 사용됩니다.

 

TCP 또는 UDP 체크섬과 같은 전송 계층 체크섬은 데이터가 소스 호스트와 대상 호스트 간에 오류 없이 전송되었는지 확인하는 데 사용됩니다. 체크섬은 전송 계층 헤더 및 데이터 필드의 내용을 기반으로 계산됩니다. ⇒ 데이터 포함

 

반면 IPv4 또는 IPv6 체크섬과 같은 네트워크 계층 체크섬은 데이터가 src 네트워크와 dest 네트워크 간에 오류 없이 전송되었는지 확인하는 데 사용됩니다. 체크섬은 네트워크 계층 헤더 및 데이터 필드의 내용을 기반으로 계산됩니다. ⇒ 헤더 체크

 

즉, 전송 계층 체크섬은 단일 네트워크 연결 내에서 종단 간 오류 탐지 기능을 제공하는 반면 네트워크 계층 체크섬은 여러 네트워크 연결에 걸쳐 오류 탐지 기능을 제공합니다. 이러한 이중화는 컴퓨터 네트워크에서 데이터 전송의 안정성과 무결성을 보장하는 데 도움이 됩니다.

'기술면접 > 네트워크' 카테고리의 다른 글

[기술면접] 네트워크 5  (3) 2024.11.14
[기술면접] 네트워크 4  (3) 2024.11.10
[기술면접] 네트워크 2  (0) 2024.11.08
[기술면접] 네트워크 1  (2) 2024.11.06
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
Programmers 알고리즘 고득점 Kit입니다.

포인트

다리를 큐로 표현해 각 트럭의 상태를 관리하며, 트럭이 다리를 건너는 동안의 시간과 다리의 무게 제한을 고려해 순차적으로 트럭을 다리에 올리고 내립니다. 반복문은 트럭이 모두 다리를 건널 때까지 계속됩니다.

 

 

소스코드

import java.util.*;

class Solution {
    static class Truck {
        int weight, position;

        public Truck(int weight) {
            this.weight = weight;
            this.position = 0;
        }

        public Truck(int weight, int position) {
            this.weight = weight;
            this.position = position;
        }
    }
    
    public int solution(int bridge_length, int weight, int[] truck_weights) {
        int time = 0; // 경과 시간
        int bridgeWeight = 0; // 현재 다리 위의 트럭 총 무게
        Queue<Truck> bridge = new LinkedList<>(); // 다리 위의 트럭 큐
        int idx = 0; // 대기 트럭 인덱스

        while (idx < truck_weights.length || !bridge.isEmpty()) {
            time++;

            if (!bridge.isEmpty()) {
                Truck frontTruck = bridge.peek(); // 맨 앞의 트럭
                if (time - frontTruck.position >= bridge_length) { // 다리를 다 건넜을 경우
                    bridgeWeight -= frontTruck.weight; // 다리 무게에서 제외
                    bridge.poll(); // 트럭 다리에서 내림
                }
            }

            if (idx < truck_weights.length) {
                if (bridgeWeight + truck_weights[idx] <= weight && bridge.size() < bridge_length) {
                    bridge.add(new Truck(truck_weights[idx], time)); // 트럭 다리에 올림
                    bridgeWeight += truck_weights[idx]; // 현재 다리 무게 갱신
                    idx++; // 대기 트럭 인덱스 증가
                }
            }
        }
        return time;
    }
}

코드 설명

 

  • Truck 클래스
    • weight: 트럭의 무게.
    • position: 트럭이 다리를 건너기 시작한 시점(시간).
  • 변수 초기화:
    • time: 전체 시뮬레이션의 경과 시간을 나타냅니다.
    • bridgeWeight: 현재 다리 위에 있는 트럭들의 총 무게입니다.
    • bridge: 현재 다리를 건너고 있는 트럭들을 저장하는 큐입니다.
    • idx: 대기 중인 트럭을 가리키는 인덱스입니다.
  • 메인 로직:
    • 시간 증가: 매 반복마다 time이 증가합니다. 이는 시뮬레이션의 한 단계를 의미합니다.
    • 트럭 이동:
      • bridge 큐에서 맨 앞에 있는 트럭(frontTruck)의 위치를 확인합니다.
      • time - frontTruck.position이 bridge_length보다 크거나 같다면, 트럭은 다리를 건넜으므로 bridge.poll()로 큐에서 제거하고, bridgeWeight에서 트럭의 무게를 뺍니다.
    • 새 트럭 추가:
      • 아직 다리를 건너지 않은 트럭이 있을 경우(idx < truck_weights.length), 현재 다리의 무게(bridgeWeight + truck_weights[idx])가 제한을 초과하지 않고 다리 길이 조건을 만족하면 새 트럭을 bridge에 추가합니다.
      • 새 트럭이 다리에 추가되면 bridgeWeight를 업데이트하고 idx를 증가시켜 다음 트럭을 가리킵니다.
  • 종료 조건:
    • 대기 중인 트럭이 더 이상 없고(idx >= truck_weights.length), bridge에 남아 있는 트럭도 없을 때 시뮬레이션이 종료됩니다.
  • 결과 반환:
    • 최종적으로 경과된 time을 반환합니다. 이는 모든 트럭이 다리를 건너기까지 걸린 총 시간입니다.

 

제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
Programmers 알고리즘 고득점 Kit입니다.

포인트

시간 복잡도 O(N^2)으로 잘 관리하면 문제가 패스하는 것을 확인했습니다. 하지만 시간복잡도를 줄이고 싶어 Stack을 이용하였고, O(N)의 시간 복잡도를 갖는 코드를 구현하였습니다.

소스코드

import java.util.*;

class Solution {
    public int[] solution(int[] prices) {
        int len = prices.length;
        int[] ans = new int[len];
        Stack<Integer> stack = new Stack<>();
        
        // 각 시간의 인덱스를 스택에 저장
        for (int i = 0; i < len; i++) {
            // 현재 가격이 스택의 마지막 가격보다 낮으면, 하락 시간 계산
            while (!stack.isEmpty() && prices[i] < prices[stack.peek()]) {
                int idx = stack.pop();
                ans[idx] = i - idx; // 하락 시간 계산
            }
            stack.push(i); // 현재 인덱스를 스택에 추가
        }
        
        // 남아 있는 인덱스들은 끝까지 가격이 떨어지지 않음
        while (!stack.isEmpty()) {
            int idx = stack.pop();
            ans[idx] = len - 1 - idx;
        }
        
        return ans;
    }
}

코드 설명

  • 루프를 통해 각 시점의 가격을 순회합니다.
    • 스택의 크기와 현재 가격이 마지막 주식 가격보다 낮으면
      • 스택에서 해당 인덱스를 꺼내고, 그 하락 시간을 i - idx로 계산하여 ans 배열에 저장.
    • 현재 시점 i를 스택에 추가하여 이후 가격 변화에 대해 추적.
  • 스택에 남아있는 시점들은 가격이 떨어지지 않은 것이므로 전체 크기에 대해 배열에 저장합니다.
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
Programmers 알고리즘 고득점 Kit입니다.

포인트

프로세스의 최댓값과 그 갯수를 효율적으로 관리하는게 포인트였습니다. Map으로도 관리할 수 있고, 리스트로도 관리할 수 있겠지만
저는 이 문제에서 우선순위 큐를 사용하였습니다.

소스코드

import java.util.*;

class Solution {
    
    static class Process {
        int priority, index;
        public Process(int priority, int index) {
            this.priority = priority;
            this.index = index;
        }
    }
    
    public int solution(int[] priorities, int location) {
        Queue<Process> processes = new LinkedList<>();
        PriorityQueue<Integer> remainPriority = new PriorityQueue<>(Collections.reverseOrder());
        
        int len = priorities.length;
        
        for(int i = 0; i < len; i++) {
            int priority = priorities[i];
            remainPriority.add(priority);
            processes.add(new Process(priority, i));
        }
        
        int order = 1;
        while(true) {
            Process ready = processes.poll();
            int maxPriority = remainPriority.poll();
            if (maxPriority == ready.priority) {
                if (location == ready.index) {
                    return order;
                } else {
                    order++;
                }
            } else {
                remainPriority.add(maxPriority);
                processes.add(ready);
            }
        }
    }
}

코드 설명

  • static class Process
    우선순위와 고유번호를 저장하기 위해 static class Process를 선언합니다.
  • PriorityQueue<Integer> remainPriority = new PriorityQueue<>(Collections.reverseOrder());
    priority를 저장할 우선순위 큐를 선언합니다.
    • 해당 우선순위큐는 최소 힙이 아닌 최대 힙으로 선언하기 위해 Collections.reverseOrder()을 사용합니다.
  • processes 큐에서 프로세스를 하나씩 꺼내 처리합니다.
  • remainPriority에서 가장 높은 우선순위를 가져옵니다.
  • 현재 프로세스의 우선순위가 가장 높은 우선순위와 같으면:
    • location에 있는 프로세스인지 확인합니다.
    • 맞다면 현재 순서(order)를 반환합니다.
    • 아니라면 실행 순서를 증가시킵니다.
  • 현재 프로세스의 우선순위가 가장 높지 않으면:
    • 프로세스를 다시 큐에 넣고 remainPriority에 추가하여 다음 순서를 준비합니다.
제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
Programmers 알고리즘 고득점 Kit입니다.

포인트

유명한 스택 문제입니다. ')'이 있으면 '('가 스택에 존재해야합니다. 또 마지막 스택에는 아무런 원소가 없어야합니다.

소스코드

import java.util.Stack;

class Solution {
    boolean solution(String s) {
        Stack<Character> bracketValidator = new Stack<>();
        
        int len = s.length();
        for (int i = 0; i < len; i++) {
            if (s.charAt(i) == ')') {
                if (bracketValidator.isEmpty() || bracketValidator.peek() != '(') {
                    return false;
                }
                bracketValidator.pop();
            } else {
                bracketValidator.add('(');
            }
        }
        
        return bracketValidator.isEmpty() ? true : false;
    }
}

코드 설명

  • Stack<Character> bracketValidator = new Stack<>();
    Character를 원소로 갖는 Stack을 선언합니다.
  • if (s.charAt(i) == ')') { if (bracketValidator.isEmpty() || bracketValidator.peek() != '(') { return false; } }
    • ')'가 되었을 때 Stack에 (이 없거나 empty이면 false를 리턴합니다.
    • 이후 Stack의 원소를 pop해줍니다.
  • else { bracketValidator.add('('); }
    • '(' 값을 만났을 때에는 Stack에 add 해줍니다.
  • return bracketValidator.isEmpty() ? true : false;
    • Stack의 원소가 없으면 true를 리턴 그렇지 않으면 false를 리턴합니다.

+ Recent posts