삽입정렬과 선택정렬 O(n2)의 정렬은 버블정렬, 삽입정렬, 선택정렬이 있다. 삽입정렬과 선택정렬은 유사하지만 다르다. 이 두 개의 차이를 설명하고, 삽입 정렬에 대해 정리하고자 한다. 선택정렬은 최소값을 삽입할 인덱스를 두고, 검색할 값들 중에 최소값의 위치를 구한다음, 두 위치의 값을 교환하는 방식이다. 삽입정렬은 위치를 이동시킬 값을 선택하고, 그 값보다 작은 값의 바로 뒤로 옮기는 형태이다. 예를 들면 [1,7,5,4]가 있고 인덱스 0인 값 1까지 정렬이 끝났다고 가정한다. 선택정렬의 경우 인덱스 1의 위치에 넣을 값을 탐색하며 그 값의 위치는 인덱스 3(값은 4)에 있다. 인덱스 1(7)과 인덱스 3(4)를 교환하는 방식이다. 삽입정렬의 경우 자신의 값(7)을 기준으로 하며, 자신의 앞에 있는 값을 순차적으로 비교하는 방식이다. 7의 앞은 1이며, 1은...
각 회원 별 가장 많이 구매한 물건은?
https://leetcode.com/problems/the-most-frequently-ordered-products-for-each-customer/
회원이 있다. 각 회원이 구매한 상품이 있다.
각 회원이 가장 많이 구매한 물품을 구한다.
연속된 숫자를 그룹핑하여 그룹간 첫 번째와 마지막을 구하기 1285. Find the Start and End Number of Continuous Ranges
https://leetcode.com/problems/find-the-start-and-end-number-of-continuous-ranges/
칼럼이 하나(log_id)인 테이블이 있다. 레코드가 늘어나면 칼럼의 값은 이전의 레코드보다 크다. 값이 1씩 증가하는 레코드 묶음을 하나의 그룹으로 만든다. 그리고 해당 그룹의 처음 값과 마지막 값을 구한다.
조건에 맞는 값을 합친다. sum 과 case
select 절에서 sum과 case를 활용하여 데이터를 유용하게 조작할 수 있다.
대체로 데이터를 단순화한다. sum은 하나의 숫자로 반환하고 case는 몇 가지 상태값으로 변환한다.
group by를 활용하여 그룹별 조회로 활용할 수 있다.
문제, Median Employee Salary
https://leetcode.com/problems/median-employee-salary/
한 테이블에 직원, 회사, 임금이 있고, 각 회사마다 가운데 순위의 임금을 받는 레코드를 출력하는 것이 목표이다. 만약 한 회사에 6명이 있다면, 3-4위 2명을 출력한다.
들어가며
단방향, 양방향 암호화는 익숙하게 사용했다. 비밀번호를 암호화할 때 bcrypt를 사용하고 양방향 암호화 때 aes256을 사용하는 것은 일종의 기본 소양과도 같았다.
하지만 AES를 사용할 때, iv가 무엇인지 모른채 사용하였고, ‘AES/CBC/PKCS5Padding’가 무엇인지 모른채 사용해왔다.
이러한 양방향, 단방향의 아주 기초적인 수준을 정리하는 글이며, 구체적인 내용은 참조한 링크를 참고하기를 바란다.
ExceptionHandler와 예외처리
Controller의 경우 보통 몇 가지의 view 탬플릿을 만들고, 해당 view로 전달하면 된다.
RestController의 경우 예외를 처리하는 다양한 방식이 있지만 가장 단순하고 빠른 방법은 ExceptionHandler와 RestControllerAdvice을 활용하는 방식이다.
기본적인 스프링의 예외처리는 다음과 같다. 발생한 예외가 WAS까지 전파 된 후, WAS가 해당 예외에 대한 처리를 컨트롤러에게 요청하고, 컨트롤러에서 그 내용을 수행하는 방식이다.
ExceptionHandler은 예외의 전파를 최소화 하는 방식이다. Dispatcher Servlet는 예외에 대하여 자신의 하위 기능인 ExceptionResolver을 통해 처리한다.
아래의 코드를 통하여 properties, 인터셉터, 필터, modelAndView 등 어떤 곳에서도 설정을 필요로 하지 않는다. 매우 단순하고 깔끔한 처리가 가능하다.
junit assertJ를 활용한 동등성 비교
동등성 비교를 할 때, 우리는 두 가지 상황을 상상할 수 있다.
주소만 다르고 값은 완전 일치
필드 일부분(수정일 등)만 차리를 가지며 나머지는 동일
이러한 상황에서 사용하는 junit 메서드가 usingRecursiveComparison() 이다.
select의 결과를 insert의 값으로 사용한다
특정 데이터를 거의 대부분 복사하되 몇 가지 부분만 수정해야 할 일이 생겼다.
이때 사용하면 좋은 쿼리가 insert into…. select…. 패턴이다.
아래의 쿼리를 사용할 경우 kim을 이름으로 가진 레코드가 복사되며 주소의 값은 ‘서울시 서울구 서울동’이 된다.
다른 테이블의 데이터를 select 할 수 있다.
크롬에서만 특정 세션이 풀린다.
자꾸 특정 세션만 풀렸다. 분명 세션은 들어갔는데 어느 순간 해당 세션이 휘발된다.
이 문제의 원인은 /favicon.ico에 대한 url 요청 때문이었다. 이를 인터셉터에 처리하지않고 무시하자 해소할 수 있었다.
.excludePathPatterns("/favicon.ico")
크로미움 기반의 브라우저에서 발생하는 문제로 보이는데, 이 버그가 왜 발생하는지는 잘 모르겠다. 더하여 이 문제는 단순한 스프링 문제가 아니었다. 2010년에 올라온 php와 관련한 질문(https://stackoverflow.com/questions/2953536/randomly-losing-session-variables-only-in-google-chrome-url-rewriting) 에도 올라온 것으로 보아, 버그가 아닌 어떤 특징이 아닌가 싶다.
왜 이 문제가 발생하는지는 잘 모르겠다. 유사한 문제가 발생할 경우 도움이 되기를 바란다.
들어가며
Scanner나 BufferedReader 등 콘솔을 활용한 개발을 웹 개발 과정에서 사용할 일은 솔직히 없다.
Poi나 File api를 통해 파일로 데이타를 추출하기는 작고, 그렇다고 String data =””; 값을 로직에 넣기에는 가변적이고 양이 많은 경우가 있다. 이 때 console로 데이타를 삽입하면 매우 좋다.
특히 나의 경우 콘솔로 삽입한 값을 리스트로 생성하고, 한 줄을 하나의 DTO 객체로 주입하는 경우가 많다. 그러므로 보통 나는 console의 값을 리스트로 만든다.
콘솔의 값을 리스트로 간단하게 구현하였다.
자주 까먹는다. 하지만 키워드는 기억이 난다.
개발자는 정신 없는 직종 중 하나라 생각한다. 왜냐하면 하나의 어플리케이션에 둘러싼 수많은 기술들을 간단하게라도 이해해야하기 때문이다.
개발자는 하나의 문제해결 이후 다른 문제 해결을 위하여 바로 집중의 대상이 전환된다. 그러므로 해당 문제해결을 위한 노력이 정리되지 않고 쉽사리 휘발되는 문제가 있다.
하지만 문제해결에 대한 키워드는 기억에 남는다. 예전에 이렇게 했었지, 라면서 예전에 작성한 소스코드를 읽거나, 아니면 인터넷에 해당 키워드를 검색한다. 이미 이전에 읽은 블로그 글이기 때문에 보라색으로 링크가 변해 있었던 적이 자주 있다.
배열과 리스트를 다루는 다양한 방법
자바에는 배열(array)과 리스트(list, collection)이 있다.
배열은 단순하고 본연의 기능에 충실하다. 하지만 인자의 갯수가 고정이고 기능이 단순한다. 리스트는 배열에 대비하여 인자의 갯수를 동적으로 할당할 수 있고 다양한 기능을 제공하고 stream api를 사용할 수 있다는 장점이 있다.
이번 블로그는 배열 및 리스트의 기본적인 초기화 방법이나 사용 방법, 컬렉션의 주요 기능을 간단하게 정리하고자 한다.
들어가며
보통 코딩테스트나 소스를 동작할 때, main 메서드를 사용한다.
main을 사용하면 하나의 클래스에 다양한 테스트를 할 때 너무 복잡해지는 경향이 있다. 이로 인하여 @Test를 main 메서드보다 선호한다.
junit의 스코프를 test에 한정하지 않는 것에 또 하나의 장점은 구현한 클래스 내부에서 테스트를 바로 수행할 수 있다. 간단한 툴로서 빠르게 만들고 적용하는 클래스를 제작할 때 매우 편하다.
들어가며
칼럼에 address와 address_detail이 있다.
‘홍은동’으로 검색하거나 ‘현대아파트’로 검색할 경우 address like #{adress} or address_detail #{addressDetail} 로 검색하면 된다.
하지만 ‘홍은동 현대아파트’라고 검색하면 위의 방법으로 동작하지 않는다. 문자열을 자르는 기준을 마련하는 것도 어렵다.
클라이언트에게 address와 address_detail을 분리하여 검색하도록 유도하는 것이다. 만약 이것이 불가능 할 경우 어떻게 할까?
이를 해소하는 방법은 아래와 같다.
들어가며 순차탐색은 처음부터 끝까지 인덱스를 조사한다. n 만큼의 시간이 필요하다. 이진탐색은 정렬이 되었다는 전제한다. 리스트를 반으로 나누고 그 가운데의 값이 찾는 값보다 크면 그 다음 검색은 중간부터 마지막까지로 한다. 이렇게 검색을 계속 하면 n 의 루트인 log n 만큼의 시간이 소비된다. 함께 테스트를 할 수 있는 내용을 포함한다. 테스트를 같이 해본 결과, 정렬 자체가 이미 시간을 소비하기 때문에, 정렬 한 다음 이진탐색은 더 느리다. 이진탐색 사용 자체가 제한적이다. 코드를 구현할 때 이하인지 미만인지 0을 포함하는지 아닌지의 세세함이 중요한 것처럼 여기서도 범위를 구현할 때 세세하게 따져야 한다. 범위를 반절로 나눌 때 중간에서 +1 이나 -1을 해야하는데, 왜냐하면 99, 100 사이의 중간값은...
예외처리
테스트 코드 중 발생하는 예외에 대해서도 테스트를 할 수 있다. 이때 assertJ의 assertThatThrownBy를 사용한다.
람다를 사용하여 예외가 발생할 것으로 기대하는 코드를 작성한다.
isInstanceOf로 예외가 발생할 타입을 작성한다.
cause, message 등 스트림을 활용하여 구체적으로 평가할 수 있다.
들어가며
프로그래머스의 sql 문제 중 해결이 어려웠던 문제가 있었다 : 입양 시각 구하기(2)
이 문제가 어려운 이유는 비어있는 칼럼 때문이다. 제공된 테이블의 레코드에는 8시부터 19시까지 밖에 없다. 하지만 0시부터 23시까지의 레코드로 결과를 만들어야 했다. right join을 하면 쉽게 해결될 문제였지만 테이블에 없는 데이터를 시간을 넣어야 하는 문제가 있었다.
여러 블로그를 참고하였지만 mysql의 경우 SET @HOUR 등의 mysql에 의존적인 유저 변수 문법을 사용하였다.
고민과 삽질 끝에 with 절을 배웠고 이를 통해 문제를 해소할 수 있었다.
테이블 자기 자신과 조인?
leetcode에서 sql 문제 중 자기 자신과 join하는 문제를 묶었다.
업무를 할 때 보통 서로 다른 테이블 간 join을 하였다. 자기 자신과 조인을 하는 경우는 거의 없다. 하지만 리트코드가 제공하는 문제 중 테이블 자신과 join을 하는 경우가 많았다. 이 방식으로 쉽게 해결할 수 있는 문제가 많았다. 새로운 시야를 얻었다. 문제를 풀고 해소한 내용을 정리한다.
들어가며 이벤트는 버블링이 된다. 그러니까 노드의 최하단을 클릭했을 경우, 그것은 동시에 그것의 부모 노드를 동시에 클릭한 것과 같다. li -> ul -> div -> body -> html. 이를 이벤트 버블링이라 하며 이벤트의 전파라 한다. 이러한 전파 덕분에 부모는 특정 자식에 대한 일괄적인 이벤트를 할 수 있다. click을 하고 그것을 처리하는 노드가 부모라 하더라도, 클릭이란 이벤트 자체는 최하단부터 전파되기 때문에, 최하단의 노드가 무엇인지 부모는 알 수 있다. someNode.onclick = function(e){} 과 같은 이벤트가 있다고 가정하면, 해당 클릭 이벤트를 발생한 최하단의 노드를 e.target 를 통해 접근할 수 있다. 이벤트 버블링의 장점은 중복되는 명령을 단 하나의 명령으로 끝낼 수 있다. 단점은 영향력이 크기...
들어가며
dom, node를 통해 노드를 생성하고 복제하고 조작한다.
element node를 생성하는 방법은 대략 다음과 같다.
innerHtml 을 통해 html 형태로 된 문자열을 삽입한다.
createElement, createTextNode 를 통해 노드를 생성한다.
cloneNode를 통해 이전의 노드를 복사하여 활용한다.
importNode를 통해 탬플릿을 복사하여 활용한다.
구체적인 구현은 아래의 코드와 같다.