local PC에서 Oracle DB 공부를 위해 Docker로 환경을 구축하였다.

 

<환경>

  • window
  • Docker Desktop 설치

 

1. jaspeen/oracle-xe-11g 이미지를 받아 Run한다.

 

run할때 port를 아래와 같이 세팅해준다.

아래와 같이 설정하지 않으면 외부에서 port를 제대로 찾지 못해 Database connection 시에 에러가 발생한다.

 

2. Cli 창에서 로그인을 한다.

 

초기 user-name과 password는 system / oracle 이다.

sqlplus / as sysdba

 

 

아래와 같이 user를 생성해준다. 

test 라는 계정이 생성되었고, resource, connect, dba 권한을 부여한다.

 

3. Dbeaver에서 해당 Database와 connection해준다.

 

oracle 11g 버전은 내가 기존에 설정해둔 jdbc driver와 버전이 맞지 않아 ojdbc6.jar을 직접 다운받아 설정해주었다.

만약 connection 시에 undefined error가 발생한다면 드라이버 버전이 맞지 않아서 발생하는 게 아닌지 확인해야 한다.

 

 

 

위와 같이 세팅 후에 Dbeaver에서 docker image로 pull 받은 Database에 정상적으로 연결이 되었다.

'Database' 카테고리의 다른 글

[MYSQL] mysqldump로 DB 백업/복원 하기  (0) 2023.05.12
 

프로그래머스

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

programmers.co.kr

 


풀이1

이렇게 푸니까 일단 통과는 하지만 테스트케이스 10번에서 시간이 오래 걸렸다.

  • 일단 k개를 제외하고 number.length() - k 개수만큼 숫자를 골라야 한다. => 반복문
  • 그리고 두번째 반복문에서는 각 회차에서 가장 큰 수(max)를 골라줘야 한다. 그런데 이 가장 큰 수를 고를 때 주의해야할 점이 있다. 바로 어디까지 중에서 (몇번째 인덱스까지) 가장 큰 수를 고를 것인가? 이다.
    • 1924, k=2라면 max를 고를 때 192 중에서 골라야한다. 왜냐면 두개의 수를 골라야 하기 때문에 (k=2이므로 2개 숫자 제거) 예를 들어, 1879라고 생각해보면 무작정 9를 고르면 그건 가장 큰 수가 되지 못하기 때문이다. 
    • 그래서 아래 그림과 같이 생각을 하면서 규칙을 찾아 k + i 인덱스까지 중에서 회차마다 가장 큰 수를 골라서 append해준다.

class Solution {
    public String solution(String number, int k) {
        StringBuffer sb = new StringBuffer();
        int index = 0;
        // 우리는 number.length() - k 개수를 숫자를 뽑을것이다
        for (int i = 0; i < number.length() - k; i++) {
            int max = 0;
            //큰수를 만들기 위해 뒤 숫자들 중 가장 큰수를 뽑아서 붙여줘야 한다
            for (int j = i; j <= i+k ; j++) {
                if (number.charAt(j) - '0' > max) {
                    max = number.charAt(i) - '0';
                    index = j + 1; // 다음 숫자부터 골라야하므로
                }
            }
            sb.append(max);
        }

        return sb.toString();
    }
}

반복문을 두번돌아 테스트10에서 속도가 매우 느리다는 것을 알 수 있다.


풀이2

다른분들의 풀이를 보니 스택을 이용해서 푼 풀이도 있었다. 

 

  • 스택에 들어있는 문자(stack.peek()) 가 현재 i번째 문자(charAt(i))보다 작으면 꺼낸다.
  • 문제는 k개의 숫자를 제거하는 것이므로, pop할때 k-- 로 k를 줄여준다. 
  • k개의 숫자가 pop되면(제거되면) 종료 후 스택에 있는 값을 꺼내준다. 

이런식으로 풀면 왼쪽에서부터 (앞에서부터) k개의 작은 수를 차례로 제거할 수 있다.

import java.util.Stack;
class Solution {
    public String solution(String number, int k) {
        char[] result = new char[number.length() - k];
        Stack<Character> stack = new Stack<>();

        for (int i=0; i<number.length(); i++) {
            char c = number.charAt(i);
            while (!stack.isEmpty() && stack.peek() < c && k-- > 0) {
                stack.pop();
            }
            stack.push(c);
        }
        for (int i=0; i<result.length; i++) {
            result[i] = stack.get(i);
        }
        return new String(result);
    }
}

- 문제 분류 : Stack

- 문제 출처 : https://programmers.co.kr/learn/courses/30/lessons/12909

 

코딩테스트 연습 - 올바른 괄호

괄호가 바르게 짝지어졌다는 것은 '(' 문자로 열렸으면 반드시 짝지어서 ')' 문자로 닫혀야 한다는 뜻입니다. 예를 들어 "()()" 또는 "(())()" 는 올바른 괄호입니다. ")()(" 또는 "(()(" 는 올바르지 않은

programmers.co.kr

 

스택에 각 char값을 넣으면서 만약 두 괄호가 만났을 때 짝을 이루면 pop한다.

각 char을 넣는 것을 진행한 뒤, stack에 값이 남아있으면 '짝을 이루지 않는다(false)'를 반환한다.

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
import java.util.*;
 
class Solution {
    boolean solution(String s) {
        
        Stack<Character> stack = new Stack<>();
        char[] arr = s.toCharArray();
        
        if(arr.length < 2) {
            return false;
        }
        
        stack.push(arr[0]);
        char top = stack.peek();
        
        for(int i = 1; i<arr.length; i++) {
            stack.push(arr[i]);
            
            if(stack.size() == 1) {
                continue;
            }
            
            if(top == '(' && arr[i] == ')') {
                stack.pop();
                stack.pop();
            } 
        }
       
        if(!stack.empty()) {
            return false;
        } else {
            return true;
        }
    }
}
cs

- 분류 : DFS/BFS

 

- 문제 : https://www.acmicpc.net/problem/2606

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
74
75
76
77
78
79
80
81
82
83
84
85
 
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
 
class Computer {
    int num;//컴퓨터 번호
    boolean marked;//방문 여부
    LinkedList<Computer> adjacent;
 
    Computer(int num) {
        this.num = num;
        this.marked = false;
        this.adjacent = new LinkedList<>();
    }
}
 
class Graph {
    Computer[] computers;
    int count; //바이러스에 감염된 컴퓨터 수
 
    Graph(int size) {
        this.computers = new Computer[size];
        for (int i = 0; i < size; i++) {
            computers[i] = new Computer(i + 1);
        }
        count = 0;
    }
 
    void addEdge(int i1, int i2) {
        Computer c1 = computers[i1 - 1];
        Computer c2 = computers[i2 - 1];
        if (!c1.adjacent.contains(c2)) {
            c1.adjacent.add(c2);
        }
        if (!c2.adjacent.contains(c1)) {
            c2.adjacent.add(c1);
        }
    }
 
    void bfs() {
        Queue<Computer> queue = new LinkedList<>();
        Computer root = computers[0];
        root.marked = true;
        queue.add(root);
 
        while (!queue.isEmpty()) {
            Computer computer = queue.poll();
            for (Computer c : computer.adjacent) {
                if (c.marked == false) {
                    c.marked = true;
                    queue.add(c);
                }
            }
            visit(computer);
        }
    }
 
    void visit(Computer computer) {
        if (computer.num != 1) {
            count += 1;
        }
    }
}
 
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int size = sc.nextInt();
        sc.nextLine();
        int edges = sc.nextInt();
        sc.nextLine();
        Graph g = new Graph(size);
        for (int i = 0; i < edges; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            g.addEdge(a, b);
            sc.nextLine();
        }
 
        g.bfs();
        System.out.print(g.count);
    }
}
 
cs

'알고리즘 > 백준' 카테고리의 다른 글

[백준1012/java] 유기농 배추  (0) 2023.05.12
[백준2606/java] 바이러스  (0) 2023.05.12
[백준/java] 1260번 - DFS와 BFS  (1) 2023.05.12
[백준/java] 18259번 - 큐2  (0) 2023.05.12
[백준/java] 2164번 - 카드2  (0) 2023.05.12

문제

 

코딩테스트 연습 - 2주차

[[100,90,98,88,65],[50,45,99,85,77],[47,88,95,80,67],[61,57,100,80,65],[24,90,94,75,65]] "FBABD" [[70,49,90],[68,50,38],[73,31,100]] "CFD"

programmers.co.kr

 

풀이

Map의 getOrDefault 메소드를 이용하여 같은 점수가 여러개 존재하는지 알아냈고, TreeMap을 이용하여 최고점과 최저점을 알아냈다. TreeMap은 key값이 자동정렬되기 때문에 key를 점수로 설정하면 firstKey()와 lastKey()로 최저점과 최고점을 알아낼 수 있었기 때문이다. 

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
import java.util.*;
 
class Solution {
    public String solution(int[][] scores) {
       StringBuilder answer = new StringBuilder();
 
        for(int i = 0; i<scores[0].length; i++) {
            int total = 0
            int person = scores[0].length;
            TreeMap<Integer, Integer> hm = new TreeMap<>();
 
            for(int j = 0; j<scores[i].length; j++) {
                hm.put(scores[j][i], hm.getOrDefault(scores[j][i], 0+ 1);
                total += scores[j][i];
            }
 
            if(scores[i][i] == hm.firstKey() && hm.get(hm.firstKey()) < 2) {
                total -= hm.firstKey();
                person -= 1;
            }
 
            if(scores[i][i] == hm.lastKey() && hm.get(hm.lastKey()) < 2) {
                total -= hm.lastKey();
                person -= 1;
            }
 
            answer.append(getGrade(total/person));
        }
 
        return answer.toString();
    }
 
    public String getGrade(double avg) {
        if(avg >= 90) {
            return "A";
        }
 
        else if(avg >= 80) {
            return "B";
        }
 
        else if(avg >= 70) {
            return "C";
        }
        else if(avg >= 50) {
            return "D";
        }
        else
            return "F";
    }
}
cs

 

 

 

아래는 좋아요를 가장 많이 받은 다른 사람의 풀이이다.

본인이 자기자신에게 매긴 점수를 제외하고 최고점과 최저점을 구했고, 구한 최저점과 최고점이 본인이 매긴 점수와 일치할 시에 제외하였다.

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
class Solution {
    public String solution(int[][] scores) {
        StringBuilder builder = new StringBuilder();
        for(int i=0; i<scores.length; i++) {
            int max = 0;
            int min = 101;
            int sum = 0;
            int divide = scores.length;
            for(int j=0; j<scores.length; j++) {
                int score = scores[j][i];
                if(i != j) {
                    if(score < min) {
                        min = score;
                    }
                    if(score > max) {
                        max = score;
                    }
                }
                sum += score;
            }
            if(scores[i][i] < min || scores[i][i] > max) {
                sum -= scores[i][i];
                divide--;
            }
            double score = (double) sum / divide;
            builder.append(score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : score >= 50 ? "D" : "F" );
        }
        return builder.toString();
    }
}
cs

'알고리즘 > 프로그래머스' 카테고리의 다른 글

[프로그래머스/java] 큰수 만들기  (0) 2023.07.14

인터페이스를 상수 클래스로 사용하다가 궁금해서 찾아보니 이러한 패턴은 안티패턴(anti-pattern)이라고 하여 이에 대해 찾아보게 되었다.

 

이러한 패턴을 "constant interface"라고 하고, 위키피디아에 이에 대해 등록되어있다.

- 위키피디아 글 : https://en.wikipedia.org/wiki/Constant_interface

 

자바 프로그래밍에서 상수 인터페이스 패턴(constant interface pattern)은 인터페이스를 오직 상수를 선언하기 위해 사용하는 것인터페이스를 implements한 클래스들이 해당 상수들에 접근할 수 있도록 하는 것을 말한다.

그러나 상수들은 그저 구현세부사항이고, 클래스들에 의해 구현된 인터페이스들은 노출되는 API의 일부이기 때문에 이런 식으로 쓰는 건 API에  구현세부사항을 넣는 것으로 부적절하게 여겨진다. 일반적으로 행위와 별개로 시스템 상수들만을 클래스에 모아두는 건 좋지 못한 객체지향 디자인이다. 왜냐하면 낮은 응집도(cohesion)을 갖기 때문이다. 이러한 이유들로 constant interface는 anti-pattern으로 여겨진다.


이러한 패턴을 사용하면 아래와 같이 몇가지 단점이 있다.
1. 사용되지 않는 read-only 변수들로 class namespace를 오염시킬 수 있다.
2. 컴파일 시점에 전략적인 유틸리티로 쓰이는 것과 달리, 런타임에는 실용적이지 않다.
(marker interface는 메서드는 없지만, 컴파일시에 유용하다)
3. 만약 다음 릴리즈 때 해당 상수가 필요 없어도 이전 버전과 호환성을 유지하려면 해당 상수는 영원히 인터페이스에 남아있어야 한다.
4. 해당 상수가 어디에서 오는지를 쉽게 보여주는 IDE가 없다면 해당 상수를 찾기 위해 많은 시간을 소모할 수 있다.
5. 인스턴스를 나타내는 인터페이스 변수는 인터페이스 이름 자체보다 유용하지 않다. (메서드가 없으므로)
6. 개발자가 클래스에 상수를 추가할 때 구현된 인터페이스를 확인하지 않으면 상수의 값이 변할 수 있다.


6번 내용은 아래 코드 참고.
public interface Constants {

	public static final int	CONSTANT = 1;
}

public class Class1 implements Constants {

	public static final int CONSTANT = 2;	// *

	public static void main(String args[]) throws Exception {
		System.out.println(CONSTANT);
	}
}​



 

이러한 이유들로 인해 constant interface를 쓰기보다는 final 클래스를 쓰는 것을 더욱 추천하는 것 같다.

public final class Constants {

	private Constants() {
		// restrict instantiation
	}

	public static final double PI = 3.14159;
	public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

 

관련 스택오버플로우 링크 : https://stackoverflow.com/questions/29382728/constant-interface-anti-pattern-clarification

 

Constant Interface Anti-Pattern Clarification

I just read somewhere that having an interface with common project constants is bad practice and also known as the Constant Interface Anti-Pattern. If I understood this correctly, the reason provid...

stackoverflow.com

 

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

- 알고리즘 분류 : dfs/bfs

 

나는 DFS로 풀었다. 

 

  • input = 배추의 위치 좌표가 주어진 배열이 주어진다.
  • output = 필요한 배추흰지렁이의 개수
  • DFS 사용 ⇒ 한 방향으로 갈 수 있는 곳까지 계속 탐색하고, 막다른 곳에 들어가면 거기에서 다시 안으로 쭉 들어간다. 막다른 곳에 도달할 때마다 배추지렁이의 개수를 늘리면 될듯하다.

 

다 풀고나서 계속 25%에서 틀려서 디버깅해보니까 continue를 써야하는 시점에 break를 써놔서 상하좌우를 전부 체크하지 않고 반복문을 빠져나갔기 때문이었다;;; 너무 황당한 실수...

import java.util.*;

 class CabbageField {
    int count; //배추 개수
    int cabbageMap[][]; //배추 위치 좌표
    boolean visited[][]; 
    int width;
    int height;
    int result;
    
    private int dx[] = {1,-1,0,0};
    private int dy[] = {0,0,1,-1};
   
    
    public CabbageField(int w, int h, int c) {
        this.width = w;
        this.height = h;
        this.count = c;
        this.cabbageMap = new int[w][h];
        this.visited = new boolean[w][h];
    }   
 
    
    public void dfs(int x, int y) {
        this.visited[x][y] = true;
        checkAdjacent(x,y);
    }
    
    private void checkAdjacent(int x, int y) {
        //상하좌우 4군데 체크
        for(int i = 0; i<4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            
            if(nx >= width || nx < 0 || ny >= height || ny < 0) {
                continue;
            }
            
            //재귀
            if(visited[nx][ny] == false && cabbageMap[nx][ny] == 1) {
                dfs(nx, ny);
            }
        }
        
    }
}




public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int total = sc.nextInt(); // case 개수
        CabbageField[] cabbageFields = new CabbageField[total];
        for(int i = 0; i<total; i++) {
            cabbageFields[i] = new CabbageField(sc.nextInt(), sc.nextInt(), sc.nextInt());
            
            //배추 좌표 입력
            for(int j = 0; j<cabbageFields[i].count; j++) {
                int x = sc.nextInt();
                int y = sc.nextInt();
                cabbageFields[i].cabbageMap[x][y] = 1;
            }
            
            for(int w = 0; w<cabbageFields[i].width; w++) {
                for(int h = 0; h<cabbageFields[i].height; h++) {
                    if(cabbageFields[i].cabbageMap[w][h] == 1 
                        && cabbageFields[i].visited[w][h] == false) {
                            cabbageFields[i].dfs(w,h);
                            cabbageFields[i].result++;
                        }
                }
            }
            
           
            System.out.println(cabbageFields[i].result);
            
        }
       
    }
}

 

추가적으로 찾아본 반례를 첨부하면 아래와 같다.

 

<배추밭 모양>

0000

0101

0111

1
4 3 5
1 1
3 1
1 2
2 2
3 2

answer : 1

'알고리즘 > 백준' 카테고리의 다른 글

[백준/java] 2606번 - 바이러스  (0) 2023.05.12
[백준2606/java] 바이러스  (0) 2023.05.12
[백준/java] 1260번 - DFS와 BFS  (1) 2023.05.12
[백준/java] 18259번 - 큐2  (0) 2023.05.12
[백준/java] 2164번 - 카드2  (0) 2023.05.12

- 알고리즘 분류 : DFS/BFS

 

나는 BFS를 이용해서 풀었다.

 

  • 1번 컴퓨터가 바이러스에 걸렸을 때 감염된 컴퓨터 수를 구하라.
  • DFS, BFS 둘다 사용 가능하지만, 일단 인접한 컴퓨터를 기준으로 먼저 탐색할 것이기 때문에 나는 BFS를 이용해서 풀었다.
  • 1번 컴퓨터(root)를 시작으로 인접한 컴퓨터들부터 순차적으로 방문한다. 방문한 컴퓨터들은 연결되어있다는 뜻이므로 “감염된 컴퓨터의 수 = 방문한 컴퓨터의 수”가 된다.

 

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

class Computer {
    int num;//컴퓨터 번호
    boolean marked;//방문 여부
    LinkedList<Computer> adjacent; // 인접한 컴퓨터들

    Computer(int num) {
        this.num = num;
        this.marked = false;
        this.adjacent = new LinkedList<>();
    }
}

class Graph {
    Computer[] computers;
    int count; //바이러스에 감염된 컴퓨터 수

    Graph(int size) {
        this.computers = new Computer[size];
				// 컴퓨터 번호 매기기 
        for (int i = 0; i < size; i++) {
            computers[i] = new Computer(i + 1);
        }
        count = 0;
    }

    void addEdge(int i1, int i2) {
        Computer c1 = computers[i1 - 1];
        Computer c2 = computers[i2 - 1];
        if (!c1.adjacent.contains(c2)) {
            c1.adjacent.add(c2);
        }
        if (!c2.adjacent.contains(c1)) {
            c2.adjacent.add(c1);
        }
    }

    void bfs() {
        Queue<Computer> queue = new LinkedList<>();
        Computer root = computers[0]; // 1번 컴퓨터
        root.marked = true;
        queue.add(root);

        while (!queue.isEmpty()) {
						//queue에 들어있는 컴퓨터 꺼내서 방문
            Computer computer = queue.poll();
						// 인접한 컴퓨터가 있으면 큐에 담아준다
            for (Computer c : computer.adjacent) {
                if (c.marked == false) {
                    c.marked = true;
                    queue.add(c);
                }
            }
            visit(computer);
        }
    }

    void visit(Computer computer) {
				// 1번컴퓨터 제외
        if (computer.num != 1) {
            count += 1;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int size = sc.nextInt();
        sc.nextLine();
        int edges = sc.nextInt();
        sc.nextLine();
        Graph g = new Graph(size);
        for (int i = 0; i < edges; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            g.addEdge(a, b);
            sc.nextLine();
        }

        g.bfs();
        System.out.print(g.count);
    }
}

'알고리즘 > 백준' 카테고리의 다른 글

[백준/java] 2606번 - 바이러스  (0) 2023.05.12
[백준1012/java] 유기농 배추  (0) 2023.05.12
[백준/java] 1260번 - DFS와 BFS  (1) 2023.05.12
[백준/java] 18259번 - 큐2  (0) 2023.05.12
[백준/java] 2164번 - 카드2  (0) 2023.05.12

+ Recent posts