아니 근데 아무생각 없이 Bubble Sort를 이용해서 문제를 풀었더니 시간초과가 발생했다. 아 ㅋㅋ 부끄럽다 ㅋㅋ
아니 근데 ㅋㅋㅋ QuickSort를 했을 때도 시간초과가 발생했다. 이게 무슨일이고!
Merge Sort는 정상적으로 정답이 나오는 것 보니, QuickSort의 최악의 경우가 n^2이라 그런 것 같다. 아마 테스트케이스에 정렬이 거의 다 되어있는 녀석이 있는거겠지.. 휴
문제풀이
여튼! 본론으로 돌아가서 문제풀이를 해 보자.
문제의 내용은 똑같으니, 앞 글에서 확인해주길 바라며 이 글에서는 본의아니게 Merge Sort에 대해 다루겠다
MergeSort, Divideand Conquer
MergeSort, 병합정렬은 쪼개고 합치는 행위로 수행된다.
정렬하고자 하는 배열 혹은 리스트가 주어지면, 더 이상 쪼갤 수 없을 때 까지 쪼갠다. 그리고 나서 다시 합쳐야 하는데, 이 때 더 이상 쪼갤 수 없는 단위까지 쪼갰기 때문에 두 수만 비교하여 정렬하면서 다시 배열을 만들면 된다.
2개를 넘어가는 수에서 합칠때 비교 방법은 다음과 같다.
M번째 요소: 좌측 혹은 우측에서 증가한 자리. 예를 들어, 좌측에서 1번째 요소를 이미 썼다면 M번째 요소는 2번째. 우측도 마찬가지. 이 때, 좌측과 우측의 M번째는 각각 독립적이다.
1. 좌측 배열의 인덱스가 마지막 까지 갔다면, 우측 배열의 M번째 요소를 선택한다. 2. 우측 배열의 인덱스가 마지막 까지 갔다면, 좌측 배열의 M번째 요소를 선택한다. 3. 좌측 배열의 값이 우측 배열의 값보다 작다면 좌측 배열의 M번째 요소를 선택한다. 4. 우측 배열의 값이 좌측 배열의 값보다 작다면 우측 배열의 M번째 요소를 선택한다.
코드를 보면 알겠지만, 각각의 요소를 모두 비교하여 선택하는 방식이다.
이 때, Merge Sort의 복잡도는 O(n logn)이 된다. 이 때, O(n)은 배열 전체에 대한 시간이고, O(log n)은 전체에 대하여 절반으로 나누었기 때문이다.
이번엔 백준 10818번 문제를 풀려한다. 이 문제는 굳이 [배열]에 분류되었어야 하나 싶은 문제다.
따라서 배열을 쓰지 않고 푸는 방법, 배열을 쓰고 푸는 방법 총 두 가지로 풀 예정이다.
우선 지금은 배열을 쓰지 않고 풀 것이다. 테스트 케이스가 몇 개인지 주어졌기 때문에, 해당 횟수만큼 숫자를 입력받고, 최대 최소를 결정하면 된다.
최솟값은 1000001, 최댓값은 -1000001로 초기화시킨다. 그 이유는 이 값들은 입력될 범위보다 크거나 작기 때문에, 어떤 수도 1000001보다 작고, -1000001보다 크기 때문이다.
위처럼 최소, 최댓값을 초기화 시키고, 앞으로 들어오는 수에 대하여 최소보다 작다면 최솟값을 갱신시킨다. 마찬가지로 최대보다 크다면 최댓값을 갱신시킨다.
이를 통해 배열에 굳이 숫자를 집어넣지 않고도 계산이 가능하다.
최종 코드
import java.util.Scanner;
public class Number10818 {
public static void main(String args[]){
Scanner scan = new Scanner(System.in);
int N = scan.nextInt();
int min = 1000001, max = -1000001;
for(int i = 0; i < N; i++){
int cur = scan.nextInt();
min = (Math.min(cur, min));
max = (Math.max(cur, max));
}
System.out.println(min + " " + max);
}
}
오늘은 백준 1110번 문제를 풀이하려한다. 사실 코딩 자체는 쉬운데 말이 어려워서..(일부러 어렵게 낸건가..)
그래서 주어진 문제를 내가 조금 정리해봤다.
1. 정수 base가 주어진다. (0 <= base <= 99) 2. base가 10보다 작다면, 앞에 0을 붙여 두 자리 수로 만들고,각 자리의 숫자를 더한다. 3. base의 일의 자리 숫자와 앞에서 구한 합의 가장 오른쪽 수를 이어 붙여 새로운 수 calc를 만든다. 4. base와 calc가 같다면 프로세스를 종료시킨다.
이 때, 2번의 앞 내용을 빨간줄로 그어 놓은 이유는 다음과 같다.
한 자리 숫자 1은 01로 쓸 수 있다. 한 자리 숫자 2는 02로 쓸 수 있다. ... 한 자리 숫자 n은 0n으로 쓸 수 있다.
이제 base에 대하여 일의 자리 수와 십의 자리 수를 구할 것인데, 이는 나머지 연산으로 쉽게 구할 수 있다. 본문에 가장 오른쪽 자리 수(일의 자리 수)가 먼저 나왔기 때문에, A를 일의 자리 수, B를 십의 자리 수를 표현하는 데 사용할 것이다.
따라서 A와 B는 다음과 같다.
A = base % 10; B = base / 10;
이제 이 A와 B를 가지고 새로운 calc를 구할 것인데, 3번을 보면 "일의 자리 숫자와 앞에서 구한 합"을 구해야 한다.
일의 자리 숫자는 A이고, "앞에서 구한 합"은 2번을 보면, "각 자리의 숫자를 더한다"기 때문에, A+B가 된다. 여기에 대하여, 가장 오른쪽 수 즉 일의 자리 수이고, 따라서 calc는 다음과 같다.
calc = A + ( (A+B)%10 );
이 calc를 base와 비교하여 종료하면 된다.
최종 코드
import java.util.Scanner;
public class Number1110 {
public static void main(String args[]){
Scanner scan = new Scanner(System.in);
int base = scan.nextInt();
int calc = base;
int A = 0, B = 0;
int repeat = 0;
do{
A = calc % 10;
B = calc / 10;
calc = (A*10)+((A+B)%10);
repeat++;
}while(base != calc);
System.out.println(repeat);
}
}
MkWeb 프레임워크에 로그인과 관련된 Authorization 기능을 제공하기 위해 JWT를 사용하려고 결정했다.
MkWeb의 특징 때문에, Controller마다 다른 Authorize 인증과 관련하여 어떻게 하면 좋을까 고민했다.
생각해 보니 큰 고민이 아니었던게, MkWeb의 Controller들에 각 인증관련 기능을 추가해주면 됐다.
첫 번째, Page Controllers
앞선 글에서 말한것 처럼, 페이지에 크게 "Authorize"와 관련된 속성을 추가해 줄 것이고, 그 값은 다음과 같다.
1. no: 이 페이지는 누구나 볼 수 있다. 2. part: 이 페이지에 종속된 컨트롤러 중 권한이 필요한 것이 있다. 3. yes: 이 페이지를 보려면 반드시 권한이 인증되어야 한다.
페이지 컨트롤러로 접속시켜주는 녀석은 결국 MkDispatcher기 때문에, MkDispatcher의 제일 마지막 부분에 ConnectionChecker를 이용한 getPageAuthorization을 통해 권한 인증 여부를 확인했다. 해당 함수는 0, 1, 2 (각각 no, part, yes에 대응된다.)의 값을 리턴해주고, 2가 아니라면, 페이지를 보여주면 된다.
두 번째, SQL Controllers
SQL Controller가 제일 필요한 곳은 바로 MkWeb의 Custom Tag인 tagSEL다.
tagSEL의 최상단에 HttpServletRequest 객체를 이용하여 authorization이 설정되었는지 보고, 설정되어 있지 않다면 Unauthorized 401을 반환해주면 끝이다.
세 번째, API Controllers
SQL Controller와 마찬가지로, API Controllers는 최초에 Authorization을 확인한 뒤, 검증되지 않았다면 취소시키면 된다. 와! API를 만들 때 가장 코드를 많이 먹던 녀석이 바로 parameter중 어딘가에 포함되어있을 key를 찾는 것이었는데, authorization을 확인함으로써 정말 간단해졌다! 오예!
음... 사실 지난주 까지 쉬기로 했는데 이번주에 작은누나가 휴가라..ㅋㅋ이번주까지 널널하게 할거다!
오늘 m1 맥북 에어에 사용할 외장 ssd를 샀다. 맥북 ssd 용량이 256밖에 안됐고, 무엇보다 윈도우<->맥 간의 파일 이동이 생각보다 귀찮아서 ssd를 마련했다. 근데,, 가격이,,ㅠㅠ,,과거에 누나가 동일제품 살 때는 10만원이었는데,, 50%나 올랐다..15만원.......휴...
더 최신 제품인 T7도 있는데, T5를 선택한 이유는 다음과 같다.
1. 가격이 비싸다. T7제품은 20만원이고, T5는 15만원이다. 2. 내가 사용중인 벨킨 USB 허브가 3.1밖에 지원하지 않는다. 3. T7의 속도를 모두 사용할 만큼 큰 용량의 파일을 사용하지 않는다.
다음 맥은 포트가 늘어날 예정이라는데, 해당 제품에 C to C로 사용하면 어떨까 생각 해봤지만, 해당 내용은 애플이 공식적으로 얘기한 게 아니라서,, 그냥 T5로 샀다.
제품의 박스와 구성품은 위 사진과 같다. 검정색 제품으로 구매 했는데, 파란색과 금색은 맥북과 너무 안어울릴 것 같아서....
일단 2.5인치 SSD인 만큼 굉장히 작고 가볍다. 제품의 이론상 속도는 USB 3.1포트를 이용했을 때 Up to 540MB/s라는데, 사실 이론은 실제 사용환경과 다르기 때문에 딱히 기대하진 않는다.
SSD 유틸리티 설치
일단 T5를 맥북에 꽂으면 이렇게 생긴 아이가 생기고, 클릭하면 설치파일이 동봉되어 있다.
우리는 가운데 .pkg로 끝나는 파일을 설치하여야 한다. 이 때!! M1 유저(>=OS BigSur)는 다른 설치파일을 받아야 한다.
위 링크를 들어가서 Portable SSD Software for T5를 찾은 뒤, (The macOS Big Sur user's only)라고 표시된 설치파일을 받아주면 된다.
설치파일이 시키는대로 다 해도, 포터블 SSD가 인식 안될것이다. 이 때, [시스템 환경설정 -> 보안 및 개인정보 보호]로 이동하여, 아래 사진처럼 자물쇠를 눌러주고, 시스템 확장 프로그램 활성화를 눌러주면 된다.
이 때, 시동 보안 정책이 완전 보안으로 되어있을 경우, 이를 수정하라는 문구가 뜨는데, 시키는대로 하면 된다. (해당 부분은 스크린샷을 찍을수가 없어서 생략하겠다..ㅠㅠ)
그러고 나면 인식이 완료된다!
속도 측정
디스크를 사면 속도측정은 반드시 해줘야 하는 법! 어.. 그런데 결과가 생각보다..안좋다. 400MB/s 정도는 기대했는데, 훨씬 못미치는 쓰기 330MB/s & 읽기 310~330MB/s 나온다. 혹시 허브가 문제인가 해서 맥북 단자에 직접 꽂아봤지만, 읽기 속도가 380MB/s로 오른것이 전부. 아래 사진의 왼쪽이 허브에 연결, 오른쪽이 맥북에 직접 연결한 속도다.
음..ㅋㅋ 뭐..ㅋㅋ 그냥 써야지...
약 두달 간 제품을 꾸준하게 썼고, 느낀점은 다음과 같다.
1. 발열은 없다. 뭐,, 좋다!
2. 넣고 다닐게 필요하다. 전용 파우치가 없어서, 제품만 노트북 파우치에 함께 들고 다니는데, 맥북에 기스갈까봐 무섭다. 그래서 따로 파우치를 사던가 해야 할듯...
3. 속도 빠르다. 당연한 얘기지만, 330MB/s 는 결코 느린 속도가 아니다. 전혀 사용하면서 지장이 없었다. 간혹 프로젝트 발표와 같은 영상도 넣고 다녔는데(보통 500메가, 크면 1.5기가 정도), 느리다는 느낌이 전혀 없다.