반응형

다들 각잡고 준비하면 금방들 찍으시는거 같던데 저는 약 3개월이 걸렸네요...

안좋은 공부머리 억지로 풀어가면서 꾸준히 진행해서 도달했다는거에 만족하고 더 노력해야겠습니다.

참 기분좋은날 이네요

반응형
반응형

2644번 촌수 계산

https://www.acmicpc.net/problem/2644

 

2644번: 촌수계산

사람들은 1, 2, 3, …, n (1 ≤ n ≤ 100)의 연속된 번호로 각각 표시된다. 입력 파일의 첫째 줄에는 전체 사람의 수 n이 주어지고, 둘째 줄에는 촌수를 계산해야 하는 서로 다른 두 사람의 번호가 주어

www.acmicpc.net


Comment

 DFS, BFS를  첫 입문할 때 하기 좋은 그래프 문제이다. 해당 문제는 DFS적으로 접근하면 Depth를 잘 활용할 수 있었는데, BFS를 활용해서 풀어볼 때 문제가 생겼었다. 직면했던 문제는 BFS에서는 Depth를 어떤 기준으로 체크할 수 있을까? 라는 고민을 많이 하게 한 문제였다.


hint

DFS, BFS 두가지 방법 모두 풀린다.

하지만 체감 난이도는 BFS가 더 어려웠던 것 같다.


Solution

  • DFS

재귀호출할 때 매개변수를 통해서 해당 깊이를 더해가며 풀어보니 잘 해결되었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import java.io.*;
import java.util.*;
 
public class Main {
 
    static boolean[] check;
    static ArrayList<Integer>[] al;
    static int n, m, start, target;
    static boolean flag;
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
        n = Integer.parseInt(br.readLine());
 
        StringTokenizer st = new StringTokenizer(br.readLine());
        start = Integer.parseInt(st.nextToken());
        target = Integer.parseInt(st.nextToken());
 
        m = Integer.parseInt(br.readLine());
 
        al = new ArrayList[n + 1];
        check = new boolean[n + 1];
 
        for (int i = 0; i < n + 1; i++) {
            al[i] = new ArrayList<>();
        }
 
        int x, y;
        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            x = Integer.parseInt(st.nextToken());
            y = Integer.parseInt(st.nextToken());
 
            al[x].add(y);
            al[y].add(x);
        }
        check[start] = true;
        dfs(start, 0);
        if (!flag) {
            System.out.println(-1);
        }
 
    }
 
    static void dfs(int n, int count) { //7 3
        if (n == target) { //도착하면 flag 변경 후 종료
            flag = true;
            System.out.println(count);
            return;
        } else if (flag) { //이미 찾았으면 더이상 dfs를 돌 필요 없음
            return;
        } else {
            for (int a : al[n]) {
                if (!check[a]) {
                    check[a] = true;
                    dfs(a, count + 1);
                }
            }
        }
    }
}
cs
  • BFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import java.io.*;
import java.util.*;
 
public class Main {
 
    static boolean[] check;
    static ArrayList<Integer>[] al;
    static int n, m, start, target;
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
        n = Integer.parseInt(br.readLine());
 
        StringTokenizer st = new StringTokenizer(br.readLine());
        start = Integer.parseInt(st.nextToken());
        target = Integer.parseInt(st.nextToken());
 
        m = Integer.parseInt(br.readLine());
 
        al = new ArrayList[n + 1];
        check = new boolean[n + 1];
 
        for (int i = 0; i < n + 1; i++) {
            al[i] = new ArrayList<>();
        }
 
        int x, y;
        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            x = Integer.parseInt(st.nextToken());
            y = Integer.parseInt(st.nextToken());
 
            al[x].add(y);
            al[y].add(x);
        }
 
        bfs(start, target);
 
    }
 
    static void bfs(int start, int target) { // null을 활용해서 깊이 구분자를 생성
        int count = 0;
 
        Queue<Integer> q = new LinkedList<>();
        q.add(start);
        q.add(null);
        check[start] = true;
 
        while (!q.isEmpty()) {
            Integer now = q.poll();//null을 활용하기 위해 Integer로 
 
            if(now == null) {//null을 만날 때마다 깊이가 깊어짐 count++
                if(!q.isEmpty()) {
                    q.add(null);
                    count++;
                }
            }else {
                for (int y : al[now]) {
                    if (!check[y]) {
                        check[y] = true;
                        if (y == target) { // bfs깊이에 따라서 체크 후 해당 깊이 출력
                            System.out.println(count + 1);
                            return;
                        }
                        q.add(y);
                    }
                }
            }
        }
        System.out.println(-1);
    }
}
cs

내가 만질 때는 null을 Queue에 넣어서 구분자로 생각하고 null을 만날 때마다 count가 1씩 증가하도록 구현했었는데, 좀 더 직관적인 방법이 좋았을거라 생각했고, 스터디를 진행하는 다른 사람이 푼 것을 봤을 때 distance라는 배열을 만들어서 해당 값을 누적되게 구현했는데 더 좋은 방법 같았다.

어쨌든 그래프에서 DFS, BFS를 둘 다 사용해보기에 좋은 문제였던 것 같다!

반응형
반응형

 

스프링 공부를 하면서 final키워드를 만났을 때 평소와 다른 어색한 사용방법 때문에 의문점이 생겼다.

final인데 왜 주입이 되는거지?
@Controller
public class MemberController{
		private final MemberService memberService;

		@Autowired
		public MemberController(MemberService memberService){
				this.memberService = memberService;
		}
		
}

final 선언 후 첫 값 초기화는 가능해서 그런건가? 라는 의문이 들었다.

이유는, 평소 final키워드 선언할 때는 항상 선언과 동시에 값을 초기화하기 때문이다.

이러한 부분이 모호하다 생각해서 final과 함께 서비스를 공부해보았다.

 

final


 

final 키워드는 변경이 더이상 필요없을 때 선언해줄 수 있다.

이번에 스프링부트를 사용하며 의문이 들었기에 위의 코드를 기준으로 스프링부트에서 생성자주입을 할때,

우리는 해당 객체의 메서드의 변경이 더이상 필요없다고 인지를 하고 있을 것이다.

때문에 Service객체에서 사용되는 모든 메서드들은 어디에서 사용이 되던 동일한 역할과 책임이 있다.

그러한 이유로 다른 컨트롤러든 서비스에서든 해당 Service에서 나올 기댓값은 동일하기에 클래스 추가생성을 통해 자원을 낭비할 필요가 없으니 final 선언을 하는 것이고, 이것이 싱글톤형태로 사용되고있는 이유다.

여러 클래스에서 해당 Service클래스를 여러번 선언하고 생성자주입을 한다면 싱글톤으로 돌아갈 수 없다고 생각될 수 있다.

하지만 이 부분은 스프링 빈의 특성을 통해서 해결이 가능하다 스프링 빈은 기본적으로 싱글톤 스코프로 관리되기 때문에 한번 해당 클래스가 스프링 빈으로 등록이 된다면 이후 동일한 인스턴스가 계속 동작한다

반응형

'호기심 천국 > Spring' 카테고리의 다른 글

스프링 시큐리티 1 (인증)  (0) 2023.09.26
데이터베이스 정렬 vs 자바 정렬  (0) 2023.09.12
반응형

@RequiredArgsConstructor를 처음엔

그냥 생성자를 알아서 주입해주는구나~ 생각만 가볍게 해두고 공식처럼 사용해왔다.

 

발단


그렇게 스프링부트 프로젝트를 협업을 통해 진행한지 좀 지났을 때

리팩토링을 위해 코드를 개선하다가 문제가 발생했다.

하나의 도메인에서 다른Repository를 불러오는 것이 응집도를 올린다고 생각했고, 또 Repository에 직접 접근하는 것은 막아야 한다고 생각했기에 xxxxRepository를 그대로 써오는 것에서 xxxxService로 변경해 사용하는 것으로 바꿔 생각했다.

이 과정에서 우리는 Service부분의 클래스 생성을 xxxxRepository → xxxxService로 변경, 생성자 주입을 시켰는데 문제가 발생했다..!

결론부터 말하자면 @RequiredArgsConstructor의 특성을 제대로 생각하지 못한 것이 문제였고 자세한 이유는 아래에서 다루겠다.

 

그래서


처음에 원인 파악을 할 때 해당 클래스들의 생성자 주입에서 final이 빠졌다고 인지를 아예 못 한 상황이였고, 때문에 한참을 뻘짓 한 것 같다.

그 때 당시에 코드변경 후 직접 실행해 확인하지 않고, 바로 테스트코드를 작성하고 있어서 해당 UserService 자체가 문제라고 인지하지 못했고,

테스트코드 작성도 익숙치 않은 상태라 테스트코드를 못짜서 그렇다고 판단을 했고, 테스트 환경을 좀 더 공부하는 뻘짓(?)을 했고, 해당 뻘짓을 할 때 디버그를 통해 알아낸 정보는 아래의 사진과 같았다.

Service에 있는 클래스가 모두 null로 되어있는 것… 이걸 발견하고도 한참 뻘짓하기도 하고 기초중의 기초적인 실수였지만....

그래도! 발견한 것에 의미를 두자! 라고 생각을 하기로 했다.

정리해서 말하자면 @RequiredArgsConstructor 어노테이션의 특성이 생성자 주입 시 final선언을 해줘야 자동으로 생성자 주입을 하고 스프링 빈을 생성하는데, final이 없어 생성자 주입을 하지 않았기 때문에 각 Service들이 null상태로 있었던 것이고, 이러한 문제가 발생했었던 것이다.

기존 UserService.java 생성자주입 예시

private final UserRepository userRepository;
private final UserTagRepository userTagRepository;
private final FriendRepository friendRepository;

 

xxxxService로 변경했을 때 문제가 있던 코드 필드

private final UserRepository userRepository;
private UserTagService userTagService;
private FriendService friendService;

 또 만약에 또 이런 문제가 생겼을 때 디버그를 통해 필드객체가 null로 되어있다면 final선언을 했는지 한번 더 확인할 수 있는 계기가 되었다.

반응형

'LTF(learn through failure) > Spring' 카테고리의 다른 글

SQL Injection  (0) 2023.09.30
반응형

2023번 신기한 소수

https://www.acmicpc.net/problem/2023

 

2023번: 신기한 소수

수빈이가 세상에서 가장 좋아하는 것은 소수이고, 취미는 소수를 가지고 노는 것이다. 요즘 수빈이가 가장 관심있어 하는 소수는 7331이다. 7331은 소수인데, 신기하게도 733도 소수이고, 73도 소수

www.acmicpc.net


Comment

 처음에는 소수판별이기 때문에 이전에 배워뒀던 에라토스테네스의 체를 사용하려고 했다. 하지만 이 문제는 메모리제한이 4MB에 N의 범위가 8 즉 최대 10,000,000 천만의 범위이기 때문에 자바의 데이터 최소단위 byte - boolean크기: 1byte로 지정되었을 때 에토체의 boolean배열만 어림잡아 100mb가 넘게된다 때문에 기각.

일반 소수판별 메서드를 생성해서 처리했다.


hint

DFS, 소수판별을 해야한다


Solution

 최종적으로 가지치기 등등 다양하게 하니까 속도가 좀 빨라졌다. 1,3,5,7,9가 아닌 0~10까지 돌렸을 때는 속도가 좀 느렸었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import java.io.*;
import java.util.*;
 
 
public class Main {
    static int[] firstPrime = {2357};
    static int n;
    static ArrayList<Integer> magicPrime = new ArrayList<>();//신기한 소수를 담을 리스트
 
//    static int count = 0;
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine());
//        int jari = (int)Math.pow(10, n); // 끝자리까지보기
 
        //4메가면 에토체가 가능한가?
        // 1000000 백만에 1M 4백만이면 끝나는데 안된다.
        //나중에 에토체로 구현되나만 체크해보면 재밌을듯
 
        //한자릿수는 배열을만들자 이걸 가지고 시작
        //이걸로 조합을 다하면 그건 브루트포스아닌가?
        //그래서 DFS느낌으로 가는건가?
 
        //슈도흐름을 생각해보자.
        //1. 한자릿수 prime등록 이후는 전부됨......
        //2. 두번째부터 그 수를 붙여서 prime인지 확인 (n을 입력받은 중단점까지)
        //2_1. DFS를 활용, String에 붙여서 다음 DFS로 이동
        //2_2. 백트래킹도 무조건 넣어야할듯? 한 Depth에서 같은 소수를 여러번 반복해야함
        //3. 중단점을 찾았으면 그 수를 리스트에 추가
        //4. 리스트에 추가된거 출력!
 
        for (int i = 0; i < firstPrime.length; i++) {
            dfs(String.valueOf(firstPrime[i]), 1);
        }
 
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < magicPrime.size(); i++) {
            if(i == magicPrime.size()-1){
                sb.append(magicPrime.get(i));
            }else {
                sb.append(magicPrime.get(i) + "\n");
            }
        }
        System.out.print(sb);
 
    }
 
    static void dfs(String s, int count) {
        if (count == n && isPrime(Integer.valueOf(s))) {//중단점
            magicPrime.add(Integer.valueOf(s));
        }
        if (isPrime(Integer.valueOf(s))) {
            for (int i = 1; i < 10; i += 2) {
                    dfs(s.concat(String.valueOf(i)), count + 1);
            }
        }
    }
 
    static boolean isPrime(int isPrimeNum) {
        for (int i = 2; i <= (int) Math.sqrt(isPrimeNum); i++) {
            if (isPrimeNum % i == 0) {
                return false;
            }
        }
        return true;
    }
}
cs
반응형
반응형

https://www.inflearn.com/infcon-2023/schedule/share?id=1036802&hash=tkdtn101226%40cacc4c62&name=%EC%83%81%EC%88%98

요즘 인프런을 자주 사용하는데, 때마침 인프콘이라는 컨퍼런스가 있다고해서 급하게 신청했는데 슬프게도 첫 신청은 실패했다. 

다양하게 준비되어있는 강의세션 중에서 주니어개발자를 저격하는 세션들이 매 시간마다 있어서 직접 가서 현장감을 느끼며 여러 지식을 공유받고 싶다...

반응형

'잡담' 카테고리의 다른 글

프로그래머스 2023결산!  (0) 2023.12.28
드디어 애드센스 승인되었네요!  (0) 2017.10.16
게임계정 해킹당했습니다.  (1) 2017.09.27
반응형

2583번 영역 구하기

문제 링크 : https://www.acmicpc.net/problem/2583

 

2583번: 영역 구하기

첫째 줄에 M과 N, 그리고 K가 빈칸을 사이에 두고 차례로 주어진다. M, N, K는 모두 100 이하의 자연수이다. 둘째 줄부터 K개의 줄에는 한 줄에 하나씩 직사각형의 왼쪽 아래 꼭짓점의 x, y좌표값과 오

www.acmicpc.net


 

Comment

DFS공부를 시작하면서 만나게 된 문제다. 처음 떠올랐던 아이디어는 이전에 풀었던 색종이 문제처럼 먼저 구현해둔 맵 배열에 칠하고 나머지 갈라진 부분을 DFS로 채워나가자고 생각하고 접근했다.


hint

  • Map을 칠하고 구분된 빈곳을 돌 때마다 count를 해주면 될듯?

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import java.io.*;
import java.util.*;
 
public class Main {
 
    static boolean map[][];
    static int count = 0;
 
    static int n, m, k;
 
    static int rectangleSize = 0;
    static ArrayList<Integer> rectangleSizeList = new ArrayList<>();
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        m = Integer.parseInt(st.nextToken());
        n = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());
 
        map = new boolean[m][n];
 
        for(int i = 0; i < k; i++){
            st = new StringTokenizer(br.readLine());
            drawRectangle(Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken())
                    ,Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken()));
        }
 
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(!map[i][j]){
                    count++;
                    dfs(i, j);
                    rectangleSizeList.add(rectangleSize);
                    rectangleSize = 0;
                }
            }
        }
        Collections.sort(rectangleSizeList);
        StringBuilder sb = new StringBuilder();
        sb.append(count).append("\n");
 
        for(int i = 0; i < rectangleSizeList.size(); i++){
            sb.append(rectangleSizeList.get(i) + " ");
        }
        System.out.println(sb);
    }
 
    static void dfs(int x, int y){
        if(x >= 0 && y >= 0 && x < m && y < n) {
            if (!map[x][y]) {
                map[x][y] = true;
                rectangleSize++;
                dfs(x + 1, y);
                dfs(x - 1, y);
                dfs(x, y + 1);
                dfs(x, y - 1);
            }
        }
    }
    static void drawRectangle(int x1, int y1, int x2, int y2){
        for(int i = y1; i < y2; i++) {
            Arrays.fill(map[i], x1, x2, true);
        }
    }
}
cs

 

Arrays.fill 메서드를 활용해보고 싶어서 사용했고, fill메서드를 안쓰고 각 좌표별로 true체크를 한 후에 칠했으면 조금 더 효율이 좋을 것 같다.

반응형
반응형

 

백준을 건든지는 좀 됐는데 요 최근 실력을 끌어올리고 싶어서

하루 1문제이상 풀이를 목표로 최대한 노력해왔고, 현재 연속 9주 풀이에 도달했다.

수준 낮은 문제더라도 억지로 계속 해왔더니 실력이 좀 늘었다는게 느껴져서 뿌듯하다.

 

일기는 끝이고 앞으로는 약간 재밌는 문제가 있고, 시간 여유가 있으면 다시 포스팅을 신경써서 해보려고 합니다.

공부하는 모두 파이팅!!🔥🔥🔥🔥🔥🔥🔥

반응형
반응형

인텔리제이 하단에 git 관련된 버튼이 있습니다. 단축키 : (Alt + 9)

해당 버튼을 누르면 각 브랜치별로 표시가 되어 있는데, 본인이 수정하려고 하는 브랜치에 들어가서 커밋 목록을 확인하신다면 커밋메시지 목록이 나와있습니다.

해당 커밋 메시지 우클릭 후 커밋 메시지 편집 버튼을 통해서 손쉽게 변경이 가능합니다..!

 

 

커밋 삭제 : 이전 커밋단계로 돌아가게 됩니다. 주의할 점은 커밋 하기 이전의 내용은 날아갈 수 있다는 것을 확실하게 인지 해두셔야 합니다

커밋 실행 취소 : git add까지 했던 staged까지 보내둔 상태로 변경합니다

커밋 되돌리기 : 커밋메시지를 남기며 이전 커밋상태로 변경해줍니다.

이번에 이 부분을 알게되면서 매번 깃 배시만 사용하면서 힘들었는데 이런 간단한 기능들은 ide상에서 편하게 수정할 수 있어서 참 편하네요

반응형

'공부 > IT관련' 카테고리의 다른 글

서버란 무엇인가요?  (0) 2023.02.22
인터넷은 어떻게 작동되나요?  (0) 2023.02.22
윈도우 단축키 관련  (0) 2023.02.21
반응형

11822번 Document

바로 한글변환...

https://www.acmicpc.net/problem/11822

 

11822번: Document

In the first example, the document must be signed by two officials — the first one accept documents on Mondays, Wednesdays and Fridays, and the second one — on Mondays and Thursdays. The fastest way to sign the document is one of the following: you s

www.acmicpc.net

이 문제를 처음에 이해하기로는 그냥 어느 공무원이든 모두 일처리를 한번씩만 하면 되는 것으로 착각하고 풀었는데, 접근방식이 틀렸었다.

-----

hint

3명의 공무원이 있다면 첫번째 공무원부터 부터 계단식으로 서류통과를 하는 방식이 맞는 방식이다.

입력케이스 하나를 예로 들었을 때

2
0 1 0 0 1
1 1 0 0 0

각각 배열로 선언을 했다 쳤을 때 두번째 줄 a배열, 세번째 줄 b배열로 치면

a[1] 인덱스에서 1을 발견하고 카운트, 이후 b배열로 이동해서 b[2] -> b[3] -> b[4] ->b[0] 으로 이동을 해서 1을 발견한 b[1]

자리에서 멈춘다 그렇다면 이미 한 주의 사이클이 돌았으니 5일 +2일 + 두번째 주의 1일 해서 8이 나오게 된다

-----

solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import java.util.*;
import java.io.*;
 
public class Main {
    static int count = 0;
    static int length = 0;
    //static boolean bool[] = new boolean[5];
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        int n = Integer.parseInt(br.readLine());
        int[][] al = new int[n][5];
 
 
        for (int i = 0; i < n; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            for (int j = 0; j < 5; j++) {
                al[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        length = n;
        goRepeat(al, 0);
    }
 
    static void goRepeat(int[][] a, int n) {
        if (n == length) {
            if (count % 5 == 0 && count / 5 > 0) {
                System.out.println(count + ((count / 5 - 1* 2));
                return;
            } else {
                System.out.println(count + (count / 5 * 2));//5일 지날때마다 +2
                return;
            }
        }
        go(a[n], count % 5);
        n++;
        goRepeat(a, n);
 
 
        return;
    }
 
    static void go(int a[], int index) {
        for (int i = 0; i < 5; i++) {
            count++;
 
            if (a[index] == 1) {
                return;
            }
            index = (index + 1) % 5;
        }
 
    }
 
}
cs

실행시간 76ms 

처음엔 배열로 풀려고 하다가 재귀함수를 학습하고싶은 마음에 재귀함수를 통해서 풀어봤다.

진짜 별거아닌 코드같은데 놀랍게도 이틀중 5시간은 써가면서 겨우 구현한 것 같다....

재귀 구현 너무 어렵...

반응형

+ Recent posts