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

 

프로그래머스

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

programmers.co.kr

문제

신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다.

  • 각 유저는 한 번에 한 명의 유저를 신고할 수 있습니다.
    • 신고 횟수에 제한은 없습니다. 서로 다른 유저를 계속해서 신고할 수 있습니다.
    • 한 유저를 여러 번 신고할 수도 있지만, 동일한 유저에 대한 신고 횟수는 1회로 처리됩니다.
  • k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다.
    • 유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송합니다.

다음은 전체 유저 목록이 ["muzi", "frodo", "apeach", "neo"]이고, k = 2(즉, 2번 이상 신고당하면 이용 정지)인 경우의 예시입니다.

유저 ID유저가 신고한 ID설명
"muzi" "frodo" "muzi"가 "frodo"를 신고했습니다.
"apeach" "frodo" "apeach"가 "frodo"를 신고했습니다.
"frodo" "neo" "frodo"가 "neo"를 신고했습니다.
"muzi" "neo" "muzi"가 "neo"를 신고했습니다.
"apeach" "muzi" "apeach"가 "muzi"를 신고했습니다.

각 유저별로 신고당한 횟수는 다음과 같습니다.

유저 ID신고당한 횟수
"muzi" 1
"frodo" 2
"apeach" 0
"neo" 2

위 예시에서는 2번 이상 신고당한 "frodo"와 "neo"의 게시판 이용이 정지됩니다. 이때, 각 유저별로 신고한 아이디와 정지된 아이디를 정리하면 다음과 같습니다.

유저 ID유저가 신고한 ID정지된 ID
"muzi" ["frodo", "neo"] ["frodo", "neo"]
"frodo" ["neo"] ["neo"]
"apeach" ["muzi", "frodo"] ["frodo"]
"neo" 없음 없음

따라서 "muzi"는 처리 결과 메일을 2회, "frodo"와 "apeach"는 각각 처리 결과 메일을 1회 받게 됩니다.

이용자의 ID가 담긴 문자열 배열 id_list, 각 이용자가 신고한 이용자의 ID 정보가 담긴 문자열 배열 report, 정지 기준이 되는 신고 횟수 k가 매개변수로 주어질 때, 각 유저별로 처리 결과 메일을 받은 횟수를 배열에 담아 return 하도록 solution 함수를 완성해주세요.

 

제한사항

  • 2 ≤ id_list의 길이 ≤ 1,000
    • 1 ≤ id_list의 원소 길이 ≤ 10
    • id_list의 원소는 이용자의 id를 나타내는 문자열이며 알파벳 소문자로만 이루어져 있습니다.
    • id_list에는 같은 아이디가 중복해서 들어있지 않습니다.
  • 1 ≤ report의 길이 ≤ 200,000
    • 3 ≤ report의 원소 길이 ≤ 21
    • report의 원소는 "이용자id 신고한id"형태의 문자열입니다.
    • 예를 들어 "muzi frodo"의 경우 "muzi"가 "frodo"를 신고했다는 의미입니다.
    • id는 알파벳 소문자로만 이루어져 있습니다.
    • 이용자id와 신고한id는 공백(스페이스)하나로 구분되어 있습니다.
    • 자기 자신을 신고하는 경우는 없습니다.
  • 1 ≤ k ≤ 200, k는 자연수입니다.
  • return 하는 배열은 id_list에 담긴 id 순서대로 각 유저가 받은 결과 메일 수를 담으면 됩니다.
  • 2 ≤ id_list의 길이 ≤ 1,000
    • 1 ≤ id_list의 원소 길이 ≤ 10
    • id_list의 원소는 이용자의 id를 나타내는 문자열이며 알파벳 소문자로만 이루어져 있습니다.
    • id_list에는 같은 아이디가 중복해서 들어있지 않습니다.
  • 1 ≤ report의 길이 ≤ 200,000
    • 3 ≤ report의 원소 길이 ≤ 21
    • report의 원소는 "이용자id 신고한id"형태의 문자열입니다.
    • 예를 들어 "muzi frodo"의 경우 "muzi"가 "frodo"를 신고했다는 의미입니다.
    • id는 알파벳 소문자로만 이루어져 있습니다.
    • 이용자id와 신고한id는 공백(스페이스)하나로 구분되어 있습니다.
    • 자기 자신을 신고하는 경우는 없습니다.
  • 1 ≤ k ≤ 200, k는 자연수입니다.
  • return 하는 배열은 id_list에 담긴 id 순서대로 각 유저가 받은 결과 메일 수를 담으면 됩니다.

 

발상

신고 결과를 취합하고 -> 결과를 집계해서 정지여부를 판단하고 -> 신고한 사람들에게 피드백을 주는 문제이다.

1차 자료를 가공하고 가공된 자료를 활용하여 다시 2차 결과물을 만드는데, 약간 복잡했다.

1차원의 ID 리스트를 상관계수 표처럼 2차원을 확장하고, 확장한 y축을 신고결과를 누적하게 한 뒤, 취합하면 나중에 전체순회를 여러번 하지 않고 편하게 자료를 활용할 수 있을 것 같아서 2차원 배열로 구현하였다.

의사코드

1. 초기값 선언(2차원 배열)
2. 신고 결과 배열 마킹{
	1. 신고자 배열위치 확인(스트림 인덱스)
    2. 피신고자 배열위치 확인
    3. 보드에 마킹(0일 때만 1)
}
3. 신고 결과 취합 및 정지여부 판단
4. 정지대상과 신고자 체크 후 결과값 반환

 

코드

더보기
public int[] solution(String[] id_list, String[] report, int k) {

    /*
     * 처리결과 횟수를 배열로 받음
     * nxn 배열로 확대하고, 주어진 배열 그대로의 인덱스를 사용함
     * 신고한 결과를 나중에 스트림으로 필터링하고 리턴하면 됨
     * */
    int[] reportResult = new int[id_list.length];
    int[][] reportBoard = new int[id_list.length][id_list.length];
    for (String s : report) {
        String[] reportTicket = s.split(" ");
        int reporter = IntStream.range(0, id_list.length)
                .filter(f -> reportTicket[1].equals(id_list[f]))
                .findFirst()
                .orElse(-1);
        int reportee = IntStream.range(0, id_list.length)
                .filter(f -> reportTicket[0].equals(id_list[f]))
                .findFirst()
                .orElse(-1);
        reportBoard[reporter][reportee]=1;
    }
    for (int i = 0; i < id_list.length; i++) {
        for (int j = 0; j < id_list.length; j++) {
            reportResult[i] += (reportBoard[i][j] >= 1) ? 1 : 0;
        }
    }
    for (int[] ints : reportBoard) {
        for (int anInt : ints) {
            System.out.print(anInt + ", ");
        }
        System.out.println();
    }
    System.out.println("=================================");
    int[] answer = new int[id_list.length];
    for (int i = 0; i < reportBoard.length; i++) {
        if(Arrays.stream(reportBoard[i]).sum()>=k){
            for (int j = 0; j < reportBoard.length; j++) {
                answer[j] += reportBoard[i][j] >= 1 ? 1 : 0;
            }
        }
    }

    return answer;
}

 

개선

여러 과정을 거쳐서 자료를 가공해야 하고, 방법도 굉장히 많은 방법이 있어 보여서 고민하는데 시간이 많이 걸렸다.

하지만 가장 빠른 방법은 바로 구현할 수 있는 방법이고, 너무 많은 시간을 고민에 쓰지말고 어느정도 전략이 세워지면 구현을 해야 한다.

진행하다 보면 문제점이나 개선점이 보이게 되니 일단 구현해보는 것이 좋은 것 같다.

'IT > Algorithm' 카테고리의 다른 글

[programmers] 전화번호 목록  (0) 2022.08.18
[programmers] 기능 개발  (0) 2022.07.27
[programmers] 로또의 최고 순위와 최저 순위  (0) 2022.07.17
[programmers] [1차] 비밀지도  (0) 2022.07.17
[Algorithm] RSA 암호  (0) 2022.07.17

Vector, Hashtable 및 StringBuffer와 같은 Java API의 초기 클래스는 thread-safe하게 동기화되어 있다.

하지만 단일 스레드에서 사용하는 경우에도 동기화를 하게 되므로 성능에 큰 부정적인 영향을 끼친다.

따라서 싱글 스레드 상황에서는 동기화되지 않는 다른 대체클래스를 사용하는 것이 좋다.

  • Vector 대신 ArrayList 또는 LinkedList
  • Stack 대신 Deque
  • Hashtable 대신 HashMap
  • StringBuffer 대신 StringBuilder

 

비준수 코드 예

 

Vector cats = new Vector();

 

준수 솔루션

 

ArrayList cats = new ArrayList();

 

 

참고자료

 

SonarLint

https://sonarcloud.io/organizations/default/rules?languages=java&open=java%3AS1149&q=S1149 

 

SonarCloud

██████╗ ██╗ ██╗████████╗██████╗ █████╗ ████████╗███████╗██████╗ ██████╗ ██████╗ ██████╗ ██

sonarcloud.io

Java:S1149

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

 

프로그래머스

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

programmers.co.kr

문제

Lotto ball

로또 6/45(이하 '로또'로 표기)는 1부터 45까지의 숫자 중 6개를 찍어서 맞히는 대표적인 복권입니다. 아래는 로또의 순위를 정하는 방식입니다. 1

순위당첨 내용
1 6개 번호가 모두 일치
2 5개 번호가 일치
3 4개 번호가 일치
4 3개 번호가 일치
5 2개 번호가 일치
6(낙첨) 그 외

로또를 구매한 민우는 당첨 번호 발표일을 학수고대하고 있었습니다. 하지만, 민우의 동생이 로또에 낙서를 하여, 일부 번호를 알아볼 수 없게 되었습니다. 당첨 번호 발표 후, 민우는 자신이 구매했던 로또로 당첨이 가능했던 최고 순위와 최저 순위를 알아보고 싶어 졌습니다.
알아볼 수 없는 번호를 0으로 표기하기로 하고, 민우가 구매한 로또 번호 6개가 44, 1, 0, 0, 31 25라고 가정해보겠습니다. 당첨 번호 6개가 31, 10, 45, 1, 6, 19라면, 당첨 가능한 최고 순위와 최저 순위의 한 예는 아래와 같습니다.

당첨 번호3110451619결과
최고 순위 번호 31 0→10 44 1 0→6 25 4개 번호 일치, 3등
최저 순위 번호 31 0→11 44 1 0→7 25 2개 번호 일치, 5등
  • 순서와 상관없이, 구매한 로또에 당첨 번호와 일치하는 번호가 있으면 맞힌 걸로 인정됩니다.
  • 알아볼 수 없는 두 개의 번호를 각각 10, 6이라고 가정하면 3등에 당첨될 수 있습니다.
    • 3등을 만드는 다른 방법들도 존재합니다. 하지만, 2등 이상으로 만드는 것은 불가능합니다.
  • 알아볼 수 없는 두 개의 번호를 각각 11, 7이라고 가정하면 5등에 당첨될 수 있습니다.
    • 5등을 만드는 다른 방법들도 존재합니다. 하지만, 6등(낙첨)으로 만드는 것은 불가능합니다.

민우가 구매한 로또 번호를 담은 배열 lottos, 당첨 번호를 담은 배열 win_nums가 매개변수로 주어집니다. 이때, 당첨 가능한 최고 순위와 최저 순위를 차례대로 배열에 담아서 return 하도록 solution 함수를 완성해주세요.

제한사항

  • lottos는 길이 6인 정수 배열입니다.
  • lottos의 모든 원소는 0 이상 45 이하인 정수입니다.
    • 0은 알아볼 수 없는 숫자를 의미합니다.
    • 0을 제외한 다른 숫자들은 lottos에 2개 이상 담겨있지 않습니다.
    • lottos의 원소들은 정렬되어 있지 않을 수도 있습니다.
  • win_nums은 길이 6인 정수 배열입니다.
  • win_nums의 모든 원소는 1 이상 45 이하인 정수입니다.
    • win_nums에는 같은 숫자가 2개 이상 담겨있지 않습니다.
    • win_nums의 원소들은 정렬되어 있지 않을 수도 있습니다.

발상

요약하면 0으로 나눈 번호들을 모두 맞다고 가정한 순위와 모두 틀렸다고 가정한 순위를 구하여 반환하는 문제이다.

두 배열을 비교하여 일치한 번호를 세야 하고 0인 번호들을 세서 순위를 구해야 한다.

의사코드

1. 0인 번호 구하기
2. 일치하지 않는 번호 구하기
3. 순위를 만들어 반환

 

개선

스트림을 이용하여 나름대로 filter 안에 다시 다른 배열을 스트림으로 받아 비교하여서 읽기 쉬운 코드를 작성하였다고 생각하였다.

하지만 결국 순위를 구하는 로직이 후에 추가적으로 작성되어야 했고, 순위의 예외처리도 필요하여 코드가 복잡해졌었다.

다른사람의 풀이를 보니, 결과값을 만들 새로운 스트림을 기존의 배열이 아닌 초기선언 방식으로 선언해두고, 그 위치에 스트림을 이용하여 순위값을 만들어 넣었다.

그뒤 체이닝을 통해 순위로직을 처리하여 return 함수 한줄에 코드가 모두 정리되는 것을 확인했다.

 

스트림이 알고리즘과 코딩테스트에선 성능이슈가 큰 부분이 확실히 존재하지만, 익숙해진다면 빠르게 구현할 수 있기 때문에 여러 문제를 풀어야 하는 코딩테스트 상황에서 다른 문제에 더 시간을 집중하고, 나중에 다 푼 뒤에 최적화가 가능한 장점이 있다.

또한 코딩테스트만을 위한 최적화가 아닌 실제 업무에서는 읽기 좋은 유지보수하기 좋은 코드가 더 선호되기 때문에 성능이슈에도 불구하고 스트림을 계속 사용하는 것이 충분히 합리적이라 생각한다.

'IT > Algorithm' 카테고리의 다른 글

[programmers] 기능 개발  (0) 2022.07.27
[programmers] 신고 결과 받기  (0) 2022.07.26
[programmers] [1차] 비밀지도  (0) 2022.07.17
[Algorithm] RSA 암호  (0) 2022.07.17
[programmers] 시저암호  (0) 2022.07.14

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

 

프로그래머스

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

programmers.co.kr

문제

tresure map

네오는 평소 프로도가 비상금을 숨겨놓는 장소를 알려줄 비밀지도를 손에 넣었다. 그런데 이 비밀지도는 숫자로 암호화되어 있어 위치를 확인하기 위해서는 암호를 해독해야 한다. 다행히 지도 암호를 해독할 방법을 적어놓은 메모도 함께 발견했다.

  1. 지도는 한 변의 길이가 n인 정사각형 배열 형태로, 각 칸은 "공백"(" ") 또는 "벽"("#") 두 종류로 이루어져 있다.
  2. 전체 지도는 두 장의 지도를 겹쳐서 얻을 수 있다. 각각 "지도 1"과 "지도 2"라고 하자. 지도 1 또는 지도 2 중 어느 하나라도 벽인 부분은 전체 지도에서도 벽이다. 지도 1과 지도 2에서 모두 공백인 부분은 전체 지도에서도 공백이다.
  3. "지도 1"과 "지도 2"는 각각 정수 배열로 암호화되어 있다.
  4. 암호화된 배열은 지도의 각 가로줄에서 벽 부분을 1, 공백 부분을 0으로 부호화했을 때 얻어지는 이진수에 해당하는 값의 배열이다.

네오가 프로도의 비상금을 손에 넣을 수 있도록, 비밀지도의 암호를 해독하는 작업을 도와줄 프로그램을 작성하라.

발상

주어진 수를 2진수로 변환한 뒤에 or 연산을 하여 0과 1을 주어진 조건에 맞게 변환하는 문제이다.

이진수변환을 하면서 자리수가 다른 부분이나 형변환 같은 이슈를 처리하는 부분이 핵심이었다.

의사코드

1. 주어진 배열 이진수 변환
2. 반복문{
	1. 변환된 이진수 비교
    	1. 둘 다 0이면 0
        2. 아니면 #
}
3. 완성된 배열 반환

 

개선

주어진 배열을 따로따로 이진수 변환하고, 자리수 맞추고, 그 뒤에 변환하느라 고생하였다.

처음에는 Integer클래스의 toBinaryString으로 문자열로 바꾸고, 다시 숫자 세서 String클래스로 포매팅하고, 거기서 다시 문자를 추출해서 비교하였는데 케이스가 많아지니까 타임아웃이 발생하였다.

최적화를 위해 고민하여서 통과하긴 하였는데, 다른 사람들의 풀이를 보니 처음에 주어진 숫자값을 따로 가공하지 않고 바로 비트연산을 통해 원하는 값을 얻어서 많은 절차를 생략하였다.

 

데이터는 모두 0과 1의 조합으로 되어있다는 사실을 잊지 말고 비트단위 연산도 항상 염두에 두도록 하자.

'IT > Algorithm' 카테고리의 다른 글

[programmers] 신고 결과 받기  (0) 2022.07.26
[programmers] 로또의 최고 순위와 최저 순위  (0) 2022.07.17
[Algorithm] RSA 암호  (0) 2022.07.17
[programmers] 시저암호  (0) 2022.07.14
[programmers] 이상한 문자 만들기  (0) 2022.07.13

RSA 암호는 공개키 암호시스템의 한 종류이다.

전자서명이 가능한 최초의 알고리즘으로 알려져 있으며 전자 상거래 등에 널리 사용되고 있다.

 

방식

RSA는 두 개의 키를 사용한다.

공개키는 모두에게 알려져 있으며 메시지를 암호화 하는데 사용되며, 개인키를 가진 자만이 복호화하여 열어볼 수 있다.

 

 

암복호화에 서로 다른 종류의 키를 사용하여 같은 암호를 사용하는 방식과 구분하여 비대칭암호라고 부르기도 한다.

 

키의 생성에는 소인수 분해의 난해함을 이용하는데, 알고리즘은 다음과 같다.

 

두 수를 곱하여 N = pq 을 찾는다.
파이(N) = (p-1)(q-1) 를 구한다.
파이(N) 보단 작고, 파이(N)와 서로소인 정수 e를 찾는다.
확장된 유클리드 호제법을 이용하여 d X e를 파이 (N)로 나누었을 때 나머지가 1인 정수 d를 구한다.

알고리즘에 사용하는 파이(n) 함수는 오일러 파이함수라고 하여

n이 양의 정수일 때, n과 서로소인 1부터 n까지의 정수의 개수를 새는 함수이다.

 

 

 

참고자료

 

https://ko.wikipedia.org/wiki/RSA_%EC%95%94%ED%98%B8

 

RSA 암호 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

https://ko.wikipedia.org/wiki/%EC%98%A4%EC%9D%BC%EB%9F%AC_%ED%94%BC_%ED%95%A8%EC%88%98

 

오일러 피 함수 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

 

'IT > Algorithm' 카테고리의 다른 글

[programmers] 로또의 최고 순위와 최저 순위  (0) 2022.07.17
[programmers] [1차] 비밀지도  (0) 2022.07.17
[programmers] 시저암호  (0) 2022.07.14
[programmers] 이상한 문자 만들기  (0) 2022.07.13
[programmers] 예산  (0) 2022.07.12

증상

 

404 Not Found

Vue.js를 사용한 웹 애플리케이션 개발 중 새로고침 시 404 페이지로 리다이렉트 되는 이슈가 발생하였다.

 

원인

 

해당 이슈는 SPA 앱을 개발할 때 발생하는 이슈로 connect-history-api-fallback 현상이라 한다.

Vue.js의 경우 라우터에 등록된 Vue 컴퍼넌트들을 모듈 번들러를 통하여 Javascript로 컴파일하여 WebServer의 Document Root 폴더에 가지고 있다. 

라우터를 이용한 정상적인 페이지 요청 시에는 해당 페이지에 맞는 js 파일을 클라이언트가 요청하지만, 새로고침 시에는 도메인과 라우터 Path를 가지고 WebServer에 존재하지 않는 요청을 보내기 때문에 발생하는 이슈이다.

 

해결방법

라이브러리를 사용하는 방법도 있지만, 공식 문서에 나와있는 서버 설정방법을 사용하여 해결하였다.

https://router.vuejs.org/guide/essentials/history-mode.html

 

Different History modes | Vue Router

Different History modes The history option when creating the router instance allows us to choose among different history modes. Hash Mode The hash history mode is created with createWebHashHistory(): import { createRouter, createWebHashHistory } from 'vue-

router.vuejs.org

 

해당 방법은 WebServer에 Http 요청이 들어왔을 때, 해당 요청을 rewrite 하는 방법이다.

 

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

 

서버 설정 문법은 아파치 레퍼런스 문서를 참고하면 된다.

https://httpd.apache.org/docs/current/rewrite/flags.html

 

RewriteRule Flags - Apache HTTP Server Version 2.4

RewriteRule Flags This document discusses the flags which are available to the RewriteRule directive, providing detailed explanations and examples. A RewriteRule can have its behavior modified by one or more flags. Flags are included in square brackets at

httpd.apache.org

위 설정문을 예시로 번역하면

RewriteRule ^index\.html$ - [L]

^index\.html$ 는 정규표현식으로 

index로 시작하며(^ 접두사)  (특수문자 .) html 로 끝나지 않는($ 접미사) 요청들이 다시 쓰는 대상이며

[L] 플래그는 조건의 끝을 의미한다.

Rewirte Cond 문장의 ! -f, ! -d는 파일과 디렉토리를 의미한다.

 

결론적으로 SPA 애플리케이션의 초기진입 페이지인 index.html이 아닌 URL로 들어오는 요청들을 index.html로 다시 보내는 설정이다.

위와같은 설정을 웹서버에 적용하여, Vue.js의 새로고침 시 404 페이지 리다이렉트 이슈를 해결할 수 있다.

 

참고자료

 

https://stackoverflow.com/questions/36399319/vue-router-return-404-when-revisit-to-the-url

 

Vue Router return 404 when revisit to the url

I just enable Vue router history mode. And it work fine when I visit to vue routing via v-href or href. But, when I try to refresh that page or go directly from browser address bar, it just return ...

stackoverflow.com

 

 

문제인식

MFA 관련 개발을 하면서 Google Authentication 앱을 사용하여 QR Code 이미지를 페이지에 보여주도록 하는 일이 있었다.

문제는 생성된 QR Code 이미지가 안드로이드 폰에서는 잘 작동하는데, iOS에서는 잘못된 바코드라는 오류메시지와 함께 작동하지 않았다.

이유를 찾다보니까 QR Code 이미지를 web URL을 이용하여 생성하는데, 이때 사용되는 문자열에 URL에서 중요하게 사용되는 예약 문자가 있어서 문자열을 파싱하는데 이슈가 있었다.

 

URL Encoding

 

URL Encoding은 예약문자들을 표현하기 위하여 대체문자를 사용하는 것을 의미한다.

Percent Encoding이라고 표현하기도 하며, 관련 규약은 RFC 3986에 정의되어 있다.

 

RFC 3986 section 2.2 Reserved Characters (January 2005)

 

2.1. Percent-Encoding
A percent-encoding mechanism is used to represent a data octet in a component when that octet's corresponding character is outside the allowed set or is being used as a delimiter of, or within, the component. A percent-encoded octet is encoded as a character triplet, consisting of the percent character "%" followed by the two hexadecimal digits representing that octet's numeric value. For example, "%20" is the percent-encoding for the binary octet "00100000" (ABNF: %x20), which in US-ASCII corresponds to the space character (SP). Section 2.4 describes when percent-encoding and decoding is applied.

pct-encoded = "%" HEXDIG HEXDIG

The uppercase hexadecimal digits 'A' through 'F' are equivalent to the lowercase digits 'a' through 'f', respectively. If two URIs differ only in the case of hexadecimal digits used in percent-encoded octets, they are equivalent. For consistency, URI producers and normalizers should use uppercase hexadecimal digits for all percent- encodings.

 

위의 표에 있는 예약 문자들은 옥텟 단위로 묶어서 16진수 값으로 인코딩해야 한다.

예를들어 ? 문자는 이후에 나오는 내용이 쿼리스트링 파라미터라는 것을 의미하며, cp = 0 은 key = value 값을 의미한다.

 

이런 의미를 가지고 있는 기호들이 제대로 동작하기 위하여 의미가 아닌 문자로 쓰여야 하는 예약문자는 %인코딩으로 표현하여야 한다.

 

참고자료

 

https://ko.wikipedia.org/wiki/%ED%8D%BC%EC%84%BC%ED%8A%B8_%EC%9D%B8%EC%BD%94%EB%94%A9

 

퍼센트 인코딩 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

https://datatracker.ietf.org/doc/html/rfc3986

 

RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax

 

datatracker.ietf.org

 

 

'IT > WEB' 카테고리의 다른 글

[Nginx] Nginx Architecture  (0) 2023.04.11
[Nginx] Nginx 소개  (0) 2023.04.05
[WEB]Session이란?  (0) 2022.06.14

증상

SQL 실행 시 파라미터 인덱스 관련 에러가 발생한다.

Caused by: java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).
```
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:963)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:885)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3321)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3306)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3345)
at com.mysql.jdbc.PreparedStatement.setNull(PreparedStatement.java:3384)
at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_setNull(FilterChainImpl.java:2733)
at com.alibaba.druid.filter.FilterAdapter.preparedStatement_setNull(FilterAdapter.java:1286)
at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_setNull(FilterChainImpl.java:2730)
at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.setNull(PreparedStatementProxyImpl.java:397)
at com.alibaba.druid.pool.DruidPooledPreparedStatement.setNull(DruidPooledPreparedStatement.java:266)
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:39)
at org.apache.ibatis.executor.parameter.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:91)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:77)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:58)
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:71)
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:56)
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:141)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:105)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:101)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:95)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:355)
... 48 more

 

원인

mybatis의 sql 파일은 XML로 작성하는데, 흔히 사용하는 SQL의 주석처리 방법 --은 XML에서 사용하는 문법이 아니기 때문에 발생하였다.

 

해결방법

주석 처리를

<!-- 주석처리할 내용 --!>

문법을 사용하여 주석처리 하거나, 해당 내용을 삭제하면 해결할 수 있다.

 

 

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

 

프로그래머스

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

programmers.co.kr

문제

ASCII

어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 "AB"는 1만큼 밀면 "BC"가 되고, 3만큼 밀면 "DE"가 됩니다. "z"는 1만큼 밀면 "a"가 됩니다. 문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.

제한 조건

  • 공백은 아무리 밀어도 공백입니다.
  • s는 알파벳 소문자, 대문자, 공백으로만 이루어져 있습니다.
  • s의 길이는 8000이하입니다.
  • n은 1 이상, 25이하인 자연수입니다.

발상

컴퓨터 문자의 기본인 아스키코드를 알고, String을 char로 변환하여 다룰 수 있는지 묻는 문제였다.

대소문자 순환을 하기 위한 로직이 필요하였고, 공백처리탈출, 문자열을 n만큼 더하는 로직이 필요하였다.

의사코드

1. 변수값 선언(스트링빌더, char배열)
2. char배열만큼 반복{
	1. 공백일 경우 스트링빌더에 공백 추가
    2. 대문자일경우 (65+((문자-65+n)%26))
    3. 소문자일 경우 (97+((문자-97+n)%26))
}
3. 스트링빌더를 스트링으로 변환 후 반환

 

개선

String의 char변환같은 기본자료형을 다루는 방법들은 직접 구현하는 것도 좋지만, 이미 구현된 라이브러리를 사용하는 것이 더 좋은 것 같다.

바퀴를 다시 만들지 말라는 말처럼, 배울때 한번쯤은 로직을 파악하기 위해 구현하는 것 외엔 이미 구현된 함수를 사용하고 절약한 시간으로 문제를 한번 더 파악하고, 다른 접근방법을 찾는 것이 더 효과적이라 생각한다.

'IT > Algorithm' 카테고리의 다른 글

[programmers] [1차] 비밀지도  (0) 2022.07.17
[Algorithm] RSA 암호  (0) 2022.07.17
[programmers] 이상한 문자 만들기  (0) 2022.07.13
[programmers] 예산  (0) 2022.07.12
[programmers] 최대공약수와 최소공배수  (0) 2022.07.11

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

 

프로그래머스

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

programmers.co.kr

문제

text

문자열 s는 한 개 이상의 단어로 구성되어 있습니다. 각 단어는 하나 이상의 공백문자로 구분되어 있습니다. 각 단어의 짝수번째 알파벳은 대문자로, 홀수번째 알파벳은 소문자로 바꾼 문자열을 리턴하는 함수, solution을 완성하세요.

제한 사항
  • 문자열 전체의 짝/홀수 인덱스가 아니라, 단어(공백을 기준)별로 짝/홀수 인덱스를 판단해야합니다.
  • 첫 번째 글자는 0번째 인덱스로 보아 짝수번째 알파벳으로 처리해야 합니다.

발상

일반적인 문장을 공백으로 잘라내고, 가공하는 문제인 줄 알았다.

그런데 코드를 작성하고 테스트케이스를 돌려보니 문제가 명확하지 않아 답이 맞지 않았다.

실패한 테스트케이스를 프로그래머스에선 입출력 확인도 안되어 고민하다 시간만 날리다가 결국 다른 사람들의 사례를 검색하여 이슈를 확인하고 해결하였다.

 

의사코드

1. 문자열을 1글자씩 자르기
2. 잘라진 문자열 수만큼 반복{
	1. 내부 순환을 위한 카운트 설정, 공백이면 카운트 초기화
    2. 카운트가 짝수면 대문자, 홀수면 소문자 변환
}
3. 변환된 값 반환

 

개선

문제점은 하나 이상의 공백이라는 점, 그리고 출력값도 하나 이상의 공백이 그대로 들어가야 한다는 점과

제시문이 대문자도 나올 수 있다는 점을 예시에서 보여주지 않았다는 점이다.

그때문에 소문자로 된 공백 하나로 구분된 문장이 들어오겠구나 생각하였지만 실제로 테스트케이스를 돌리니 주어진 예제케이스 말고 대부분 실패하는 상황이 발생하였다.

 

알고리즘의 정의중 하나인 `입력' 부분에서 입력이 제대로 정의되지 않아서 발생한 문제이긴 하지만

현실에서 프로그램을 통해 해결하는 문제들 대부분이 제대로 정의되지 않았다는 점에서 생각할 거리를 주는 문제이다.

내가 문제를 쉽게 해결해서 안좋은 문제가 아니라, 나의 접근과 분석방법, 예외를 생각하는 케이스가 아직 부족하다는 점을 깨달을 수 있었던 문제였다.

https://ko.wikipedia.org/wiki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98

 

'IT > Algorithm' 카테고리의 다른 글

[Algorithm] RSA 암호  (0) 2022.07.17
[programmers] 시저암호  (0) 2022.07.14
[programmers] 예산  (0) 2022.07.12
[programmers] 최대공약수와 최소공배수  (0) 2022.07.11
[programmers] 3진법 뒤집기  (0) 2022.07.10

+ Recent posts