여러 설정들을 봐도 간단하고 쉽게 해결방안을 찾지 못했다.
어쩔 수 없이 노가다 전략으로 해당 문제를 해결했다.
북마크 폴더
에서 마우스 오른쪽 버튼 -> 북마크 관리자
를 클릭한다.모두 열기
/ 새 창에서 모두 열기
/ 시크릿 창에서 모두 열기
중 원하는 것을 클릭한다.[3] 새로고침을 하고 나면, 이제는 북마크에 있는 파비콘이 제대로 보이게 된다. (guest-book-homepage
는 파비콘이 원래부터 없었기 때문에 기본 상태로 같다)
이 방법보다 더 좋은 방법이 있으면 추가적으로 업로드를 하자.
메모리: 78.8 MB, 시간: 0.67 ms
코딩테스트 연습 > 2019 KAKAO BLIND RECRUITMENT
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Solution {
public int[] solution(int N, int[] lastStages) {
int nPlayers = lastStages.length;
int[] nStagePlayers = new int[N + 2];
for (int stage : lastStages) {
nStagePlayers[stage] += 1;
}
int remainingPlayers = nPlayers;
List<Stage> stages = new ArrayList<>();
for (int id = 1 ; id <= N; id++) {
double failure = (double) nStagePlayers[id] / remainingPlayers;
remainingPlayers -= nStagePlayers[id];
Stage s = new Stage(id, failure);
stages.add(s);
}
Collections.sort(stages, Collections.reverseOrder());
int[] answer = new int[N];
for (int i = 0; i < N; i++) {
answer[i] = stages.get(i).id;
}
return answer;
}
class Stage implements Comparable<Stage> {
public int id;
public double failure;
public Stage(int id_, double failure_) {
id = id_;
failure = failure_;
}
@Override
public int compareTo(Stage o) {
if (failure < o.failure ) {
return -1;
}
if (failure > o.failure ) {
return 1;
}
return 0;
}
}
}
실패율이 높은 stage부터 내림차순으로 stage의 번호가 담겨있는 배열을 출력하는 문제이다.
실패율 = stage에 도달했으나 아직 클리어하지 못한 플레이어의 수
/ stage에 도달한 플레이어 수
실패율을 구한 다음 내림차순으로 정렬하여 반환하는 것이 목표다.
흐름 구성
각 스테이지에 머무르고 있는 사람의 수를 카운팅한다.
각 스테이지를 플레이한 사람의 수를 카운팅한다.
각 (스테이지에 머무르고 있는 사람 / 각 스테이지를 플레이 한 사람) * 100으로 실패율을 계산한다.
실패율 순으로 정렬하여 스테이지의 번호를 반환한다.
중요한 조건
실패율이 같을 경우 스테이지가 작은 번호가 우선
스테이지에 도달한 유저가 없는 경우 해당 스테이지의 실패율은 0
이 글의 코드와 정보들은 강의를 들으며 정리한 내용을 토대로 작성하였습니다.
캐시가 없을 때 요청을 하는 경우
데이터가 변경되지 않아도 네트워크를 통해 계속 데이터를 다운로드 받아야 한다. -> 인터넷 네트워크는 매우 느리고 비싸다.
브라우저 로딩 속도가 느리다. + 느린 사용자 경험
캐시를 적용할 경우
cache-control: max-age=60
: 캐시가 유효한 시간(초)
캐시 가능 시간 동안 네트워크를 사용하지 않아도 된다 -> 비싼 네트워크 사용량을 줄일 수 있다.
브라우저 로딩 속도가 빠르다. + 빠른 사용자 경험
만약 캐시 유효 시간이 초과되면, 서버를 통해 데이터를 다시 조회하고 캐시를 갱신한다.
이때 다시 네트워크 다운로드가 발생한다.
캐시 유효 시간이 초과해서 서버에 다시 요청하면 두 가지 상황이 발생한다.
서버에서 기존 데이터를 변경함
서버에서 기존 데이터를 변경하지 않음
캐시 유효 시간이 초과해도 서버의 데이터를 변경(갱신)하지 않는다. -> 저장해두었던 캐시를 재사용 할 수 있다.
예) 캐시 시간이 초과되는 경우(순서: 1 -> 2 -> 3 -> 4)
브라우저에 있는 캐시를 재사용할 수 있다.
결과적으로 네트워크 다운로드가 발생하지만 용량이 적은 헤더 정보만 다운로드된다.
검증 헤더
란 캐시 데이터와 서버 데이터가 같은지를 검증하는 데이터이다.
종류에는 Last-Modified
, ETag
가 있다.
Last-Modified
와 ETag
를 활용해서 클라이언트에서 서버로 요청을 할 때 조건부 요청 헤더
를 만들어서 보내면 된다.
조건부 요청 헤더
는 검증 헤더로 조건에 따른 분기를 의미한다.
If-Modified-Since
는 Last Modified를 사용하고, If-None-Match
는 ETag를 사용한다.
조건이 만족하면 200 OK
가 나오고, 만족하지 않으면 304 Not Modified
가 나오게 된다.
예) If-Modified-Since: 이후에 데이터가 수정되었을 경우
데이터 미변경 예시
캐시 : 2023년 1월 1일 12:30:00 vs 서버 : 2023년 1월 1일 12:30:00
304 Not Modified, 헤더 데이터만 전송(BODY 미포함)
전송 용량 0.1M(헤더 0.1M, 바디 1.0M)
데이터 변경 예시
캐시 : 2023년 1월 1일 12:30:00 vs 서버 : 2033년 1월 1일 12:30:00
200 OK, 모든 데이터 전송(BODY 포함)
전송 용량 1.1M (헤더 0.1M, 바디 1.0M)
ETag
(Entity Tag)란 캐시용 데이터에 임의의 고유한 버전 이름을 달아둔다.
데이터가 변경되면 이름을 바꾸어서 변경하는데, 이때 Hash를 다시 생성한다.
정리)
클라이언트가 ETag만 서버에 보내서 같으면 유지하고, 다르면 다시 받는ㄴ다.
캐시 제어 로직을 서버에서 완전히 관리한다.
클라이언트는 단순히 이 값을 서버에 제공한다.(클라이언트는 캐시 메커니즘을 모른다)
캐시 제어 헤더
Cache-Control
: 캐시 지시어
Pragma
: 캐시 제어(하위 호환)
Expires
: 캐시 유효 기간(하위 호환)
캐시 지시어
Cache-Control: max-age
: 캐시 유효 시간, 초 단위
Cache-Control: no-cache
: 데이터는 캐시해도 되지만, 항상 origin 서버에 검증하고 사용한다.
Cache-Control: no-store
: 데이터에 민감한 정보가 있으면 저장하면 안된다. (메모리에서 사용하고 최대한 빨리 삭제해야 한다)
프록시는 클라이언트와 서버 사이에 대리로 통신을 수행하는 것을 말하며, 중계 기능을 하는 서버를 프록시 서버라고 한다.
클라이언트에서 저장하는 캐시를 private 캐시
라고 하며 프록시 캐시 서버는 public 캐시
라고 한다.
Cache-Control: no-cache
: 데이터는 캐시해도 되지만, 항상 origin 서버에 검증하고 사용한다.
Cache-Control: no-store
: 데이터에 민감한 정보가 있으면 저장하면 안된다. (메모리에서 사용하고 최대한 빨리 삭제해야 한다)
Cache-Control: must-revalidate
: 캐시가 만료된 이후에 최초 조회시 원(origin) 서버에 검증을 해야한다.
no-cache
경우 원 서버에 접근할 수 없는 경우 캐시 서버 설정에 따라 캐시 데이터를 반환할 수 있다.
Error or 200 OK
반면에, must-revalidate
경우 원 서버에 접근할 수 없는 경우 항상 오류가 발생하게 된다.
504 Gateway Timeout
이 글의 코드와 정보들은 강의를 들으며 정리한 내용을 토대로 작성하였습니다.
이 글의 코드와 정보들은 [스프링 핵심원리 기본편] 강의를 들으며 정리한 내용을 토대로 작성하였습니다.