문제

https://programmers.co.kr/learn/courses/30/lessons/17679


코드

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
private static final int ASCII = 32;
private static final char EMPTY = ' ';

public int solution(int m, int n, String[] board) {
int answer = 0;
char[][] charBoard = convertStringArrayToCharArray(m, n, board);

while (true) {
boolean isEnd = box(charBoard);

if (isEnd) {
break;
}

answer += delete(charBoard);
}

return answer;
}

public char[][] convertStringArrayToCharArray(int m, int n, String[] board) {
char[][] charBoard = new char[m][n];

int i = 0;
for (String str : board) {
char[] toChar = str.toCharArray();
charBoard[i] = toChar;
++i;
}

return charBoard;
}

public char toLowerCase(char value) {
return (char) ((value >= 65 && value <= 90) ? (value + ASCII) : value);
}

public boolean box(char[][] charBoard) {
boolean isEnd = true;

for (int i = 0; i < charBoard.length; i++) {
for (int j = 0; j < charBoard[i].length; j++) {
if (validation(i, j, charBoard)) {
char value = toLowerCase(charBoard[i][j]);
charBoard[i][j] = value;
charBoard[i][j+1] = value;
charBoard[i+1][j] = value;
charBoard[i+1][j+1] = value;

isEnd = false;
}
}
}

return isEnd;
}

private boolean validation(int i, int j, char[][] charBoard) {
if ((i + 1) == charBoard.length || (j + 1) == charBoard[0].length) {
return false;
}
char position = toLowerCase(charBoard[i][j]);

if (position == EMPTY) {
return false;
}

char moveX = toLowerCase(charBoard[i][j+1]);
char moveY = toLowerCase(charBoard[i+1][j]);
char moveXY = toLowerCase(charBoard[i+1][j+1]);

if (position != moveX) {
return false;
}

if (position != moveY) {
return false;
}

if (position != moveXY) {
return false;
}

return true;
}

private int delete(char[][] charBoard) {
int answer = 0;

for (int i = 0; i < charBoard.length; i++) {
for (int j = 0; j < charBoard[i].length; j++) {
if (charBoard[i][j] == EMPTY) {
continue;
}

if (charBoard[i][j] >= 97 && charBoard[i][j] <= 122) {
if (i != 0) {
for (int k = i; k > 0; k--) {
charBoard[k][j] = charBoard[k-1][j];
charBoard[k-1][j] = EMPTY;
}
} else {
charBoard[i][j] = EMPTY;
}

++answer;
}
}
}

return answer;
}

흐름

  1. String array로 넘어온 board를 2차원 array로 만든다.
  2. 무한루프를 돌면서 char로 만든 board array의 element들을 모두 꺼내면서
  3. 제약조건을 확인하여 모두 통과할 때만 true를 return 한다.
    1. 현재 element가 있는 위치가 맨 끝인지
    2. 현재 element가 빈 값인지
    3. 현재 element의 오른쪽 element와 값이 같지 않은지
    4. 현재 element의 아래쪽 element와 값이 같지 않은지
    5. 현재 element의 우하(右下)쪽 element와 값이 같지 않은지
  4. 제약조건을 통과하면 현재 위치에서 오른쪽, 아래쪽, 우하(右下)쪽 element들을 소문자로 만들고 삭제 할 블록이 남았으므로, false를 return 한다.
  5. 다시 board array를 반복하면서 element가 소문자인 경우
  6. 현재 높이가 0이라면 위에서 내려올 블록이 없으므로 바로 빈 값을 저장하고
  7. 0이 아니라면 현재 위치부터 값을 1씩 빼면서 위에 블록을 현재 위치에 저장 시키고 위 블록은 빈 값으로 저장한다.
  8. 블록을 제거 할 때 마다 제거시킨 블록 개수를 저장하는 변수를 증가시킨다.
  9. 삭제 할 블록이 없을 때 까지 2번부터 8번까지 반복하고 삭제 할 블록이 없으면 루프를 빠져 나오고 삭제한 블록의 개수를 return 한다.

결과

번호 속도
테스트 1 통과 (0.07ms, 52.3MB)
테스트 2 통과 (0.09ms, 51.7MB)
테스트 3 통과 (0.04ms, 51.9MB)
테스트 4 통과 (1.08ms, 52.5MB)
테스트 5 통과 (14.40ms, 52.6MB)
테스트 6 통과 (3.08ms, 52.3MB)
테스트 7 통과 (0.81ms, 52.3MB)
테스트 8 통과 (1.81ms, 53.7MB)
테스트 9 통과 (0.07ms, 53.4MB)
테스트 10 통과 (0.59ms, 51.7MB)
테스트 11 통과 (1.38ms, 52.7MB)

테스트 케이스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
assertEquals(14, test.solution(4,5, new String[] {"CCBDE", "AAADE", "AAABF", "CCBBF"}));
assertEquals(15, test.solution(6,6, new String[] {"TTTANT", "RRFACC", "RRRFCC", "TRRRAA", "TTMMMF", "TMMTTJ"}));
assertEquals(14, test.solution(4,5, new String[] {"AAAAA","AUUUA","AUUAA","AAAAA"}));
assertEquals(4, test.solution(2,2, new String[] {"AA","AA"}));
assertEquals(0, test.solution(2,2, new String[] {"AA","AB"}));
assertEquals(4, test.solution(3,2, new String[] {"AA","AA", "AB"}));
assertEquals(8, test.solution(4,2, new String[] {"CC","AA", "AA", "CC"}));
assertEquals(12, test.solution(6,2, new String[] {"DD", "CC", "AA", "AA", "CC", "DD"}));
assertEquals(8, test.solution(8,2, new String[] {"FF", "AA", "CC", "AA", "AA", "CC", "DD", "FF"}));
assertEquals(8, test.solution(6,2, new String[] {"AA", "AA", "CC", "AA", "AA", "DD"}));
assertEquals(8, test.solution(4,4, new String[] {"ABCD", "BACE", "BCDD", "BCDD"}));
assertEquals(27, test.solution(8,9, new String[] {"ABCDADFDA", "ABDFQWERF", "WKDNFNRIT", "AKAKWODCJ", "AKAKWODCJ", "KKKKKKKKK", "KKKKKKKKK", "KKKKKKKKK"}));
assertEquals(15, test.solution(4,5, new String[] {"AAAAA", "AAAAU", "AAAUU", "UUUUU"}));
assertEquals(24, test.solution(5,6, new String[] {"AAAAAA", "BBAATB", "BBAATB", "JJJTAA", "JJJTAA"}));
assertEquals(32, test.solution(6,6, new String[] {"AABBEE", "AAAEEE", "VAAEEV", "AABBEE", "AACCEE", "VVCCEE"}));

댓글 공유

서론

Spring boot + Vue를 활용해 토이 프로젝트 진행하고 있는데 헷갈리는 부분을 차후 또 Vue로 개발 할 일이 있을 경우 참고하기 위해 글로 남겨 놓는다.

개발 순서

  • Vue는 설치되어 있다고 가정한다.
  1. root 디렉토리에 vue.config.js 생성하고 필요한 설정 추가

vue.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const path = require("path");

module.exports = {
assetsDir: "static",
outputDir: path.resolve(__dirname, "../backend/src/main/resources/static"),
devServer: {
proxy: {
"/": {
target: "http://localhost:9312",
ws: true,
changeOrigin: true
}
}
},
chainWebpack: config => {
const svgRule = config.module.rule("svg");
svgRule.uses.clear();
svgRule.use("vue-svg-loader").loader("vue-svg-loader");
}
};
  1. views/ 에 화면이 될 vue 파일 생성
  2. src/ 에 api 폴더 생성
  3. api/ 에 화면 별로 필요한 js 파일 생성
    1. 이 js 파일들엔 각 컴포넌트 별로 필요한 api 주소를 호출 할 수 있는 js 코드를 작성한다.
  4. api 호출 시 공통으로 들어갈 header를 포함하는 common.js 생성

common.js

1
2
3
4
5
6
7
8
9
import axios from "axios";

const AXIOS = axios.create({
headers: {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json; charset = utf-8"
},
timeout: 1000
});
  1. components/ 에 2번에서 만든 화면에 출력 될 component vue 파일 생성
  2. router/index.js 에 추가한 vue path 추가
    • rotuer에 추가하지 않으면 화면이 나오지 않음

router/index.js

1
2
3
4
5
6
7
...
{
path: "/main",
name: "Main",
component: () => import("../views/Main")
}
...

댓글 공유

결론

JPQL의 return 값으로 Inner class를 지정하면 class를 찾을 수 없다는 에러가 발생 하므로 Inner class 말고 따로 class를 생성하고 그 class를 return class로 지정해줘야 한다.


발견

아래 처럼 DTO를 생성하고 view별로 inner class로 DTO를 만들고 jpql의 return class로 지정해주었는데 클래스를 찾을 수 없다는 에러가 발생하였다.

DTO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ChannelDTO {

@NoArgsConstructor
@Getter
public static class SubChannelList {
private Integer subChannel;
private KillTime killTime;

@Builder
public SubChannelList(Integer subChannel, KillTime killTime) {
this.subChannel = subChannel;
this.killTime = killTime;
}
}

...
}

JPQL 호출 메서드

1
2
3
4
5
6
7
8
9
10
11
public List<SubChannelList> findSubChannelList(Integer dungeonId, Integer mainChannel) {
return em.createQuery(
"select new com.jungguji.windbossgentimer.web.dto.channel.ChannelDTO.SubChannelList" +
"(c.subChannel, k)" +
" FROM Channel c left join c.killTimes k" +
" WHERE c.dungeon.id = :dungeonId AND c.mainChannel = :mainChannel" +
"", SubChannelList.class)
.setParameter("dungeonId", dungeonId)
.setParameter("mainChannel", mainChannel)
.getResultList();
}

발생한 에러

1
2
3
4
5
6
7
8
9
10
11
12
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate class [com.jungguji.windbossgentimer.web.dto.channel.ChannelDTO.SubChannelList] [select new com.jungguji.windbossgentimer.web.dto.channel.ChannelDTO.SubChannelList(c.subChannel, k) FROM com.jungguji.windbossgentimer.domain.channel.Channel c left join c.killTimes k WHERE c.dungeon.id = :dungeonId AND c.mainChannel = :mainChannel]
at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:74)
at org.hibernate.hql.internal.ast.ErrorTracker.throwQueryException(ErrorTracker.java:93)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:282)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162)
at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:604)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:716)
... 73 more

해결

Inner class로 되어있던 DTO를 class로 생성한다.

따로 생성한 DTO

1
2
3
4
5
6
7
8
9
10
11
12
@NoArgsConstructor
@Getter
public class SubChannelListResponseDTO {
private Integer subChannel;
private KillTime killTime;

@Builder
public SubChannelListResponseDTO(Integer subChannel, KillTime killTime) {
this.subChannel = subChannel;
this.killTime = killTime;
}
}

결과

Junit Test 통과한 모습


P.S

  • 일반적으로 class명과 table명을 헷갈려 대소문자 때문에 발생하는 에러 이므로 대소문자도 잘 확인 하여야 한다.

댓글 공유

문제

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


코드

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
public class 마인크래프트 {
public static void main(String[] args) throws IOException {
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
int[] nmb = convertStringArrayToIntegerArray(br.readLine().split(" "));

int n = nmb[0];
int m = nmb[1];

int[][] ground = initGround(br, n, m);
int[] minAndMax = getMinAndMax(ground);

int[] timeAndHigh = getMinimumConstructionTime(ground, nmb[2], minAndMax[0], minAndMax[1]);

System.out.println(timeAndHigh[0] + " " + timeAndHigh[1]);
}
}

private static int[] convertStringArrayToIntegerArray(String[] args) {
int[] array = new int[args.length];
int i = 0;
for (String str : args) {
array[i++] = Integer.parseInt(str);
}

return array;
}

private static int[][] initGround(BufferedReader br, int n, int m) throws IOException {
int[][] ground = new int[n][m];
for (int i = 0; i < n; i++) {
ground[i] = convertStringArrayToIntegerArray(br.readLine().split(" "));
}

return ground;
}

private static int[] getMinAndMax(int[][] ground) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;

for (int[] i : ground) {
for (int j : i) {
min = min > j ? j : min;
max = max < j ? j : max;
}
}

return new int[] {min, max};
}

private static int[] getMinimumConstructionTime(int[][] ground, int inventory, int min, int max) {
int answerTime = Integer.MAX_VALUE;
int answerHigh = 0;

for (int currentHigh = min; currentHigh <= max; currentHigh++) {
int up = 0;
int down = 0;

for (int i = 0; i < ground.length; i++) {
for (int j = 0; j < ground[0].length; j++) {
int high = ground[i][j] - currentHigh;

if (high > 0) {
down += high;
} else if (high < 0) {
up -= high;
}
}
}

if (down + inventory >= up) {
int time = (down * 2) + up;

if (answerTime >= time) {
answerTime = time;
answerHigh = currentHigh;
}
}
}

return new int[]{answerTime, answerHigh};
}
}


흐름

  1. n * m 크기의 2차원 배열을 만들어서 저장한다.
  2. 땅 높이를 저장한 2차원 배열을 돌면서 가장 작은 높이와 가장 큰 높이를 구한다.
  3. 우선, 가장 낮은 높이부터 가장 높은 높이 까지 반복하면서
  4. 3번에 해당하는 높이를 기준으로 2차원 배열을 2중 루프 돌면서 모든 땅에서 현재 땅 높이를 뺀다. (int high = ground[i][j] - currentHigh;)
  5. 그 높이가 0보다 크면 기준이 되는 땅보다 높은 것 이므로 땅을 깎아서 기준이 되는 높이와 맞추기 위해 down 변수에 높이를 더한다.
  6. 반대로 0 보다 작으면 기준이 되는 땅 보다 낮은 것이므로 땅을 높여서 기준이 되는 높이와 맞추기 위해 up 변수에 높이를 더해야 하는데 high가 0보다 작으면 - 이므로 up에 높이를 - 해서 더한다.
  7. 그렇게 2차원 배열을 전부 반복했으면 땅을 깎으면서 구한 블록과 원래 인벤토리에 있던 블록의 갯수가 쌓아야되는 블록의 갯수보다 크거나 같아야 높이를 맞출 수 있으므로 크거나 같은지 비교해서
  8. 땅을 깎는건 2초가 걸리므로 down * 2 한 값에 쌓아야 되는 높이 만큼 더한다.
  9. 그렇게 구한 걸리는 시간이 이전에 구한 최소 시간 보다 작으면 최소 시간을 지금 구한 time으로 변경하고
  10. 걸리는 시간이 같은 경우엔 가장 높은 높이로 구해야 하므로
  11. 높이도 현재 높이로 바꿔준다.
    • 높이는 제일 작은 높이부터 제일 큰 높이로 순차적으로 올라가고 있으므로 나중에 구한 높이가 이전에 구한 높이 보다 무조건 높다.
  12. 끝.

결과

결과


P.S 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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package algorithm.baekjoon.class2.bruteforce;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class 마인크래프트 {
public static void main(String[] args) throws IOException {
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
int[] nmb = convertStringArrayToIntegerArray(br.readLine().split(" "));

int n = nmb[0];
int m = nmb[1];

int[][] ground = initGround(br, n, m);
boolean[][] isPassed = new boolean[n][m];

List<Block> blockList = getBlockList(n, m, ground, isPassed);

int[] timeAndHigh = getMinimumConstructionTime(blockList, nmb[2]);

System.out.println(timeAndHigh[0] + " " + timeAndHigh[1]);
}
}

private static int[] convertStringArrayToIntegerArray(String[] args) {
int[] array = new int[args.length];
int i = 0;
for (String str : args) {
array[i++] = Integer.parseInt(str);
}

return array;
}

private static int[][] initGround(BufferedReader br, int n, int m) throws IOException {
int[][] ground = new int[n][m];
for (int i = 0; i < n; i++) {
ground[i]= convertStringArrayToIntegerArray(br.readLine().split(" "));
}

return ground;
}

private static List<Block> getBlockList(int n, int m, int[][] ground, boolean[][] isPassed) {
List<Block> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (isPassed[i][j]) {
continue;
}

int count = breadthFirstSearch(i, j, ground, isPassed);

list.add(new Block(ground[i][j], count));
}
}

return list;
}

private static int breadthFirstSearch(int x, int y, int[][] picture, boolean[][] isPassed) {
final int[] xAround = new int[]{1, -1, 0, 0};
final int[] yAround = new int[]{0, 0, 1, -1};

int areaRange = 1;

Queue<Position> queue = new LinkedList<>();

setPassedArea(isPassed, queue, x, y);

while (!queue.isEmpty()) {
Position currentPosition = queue.poll();

for (int i = 0; i < xAround.length; i++) {
int moveX = xAround[i] + currentPosition.x;
int moveY = yAround[i] + currentPosition.y;

if (!isSameAreaValidation(moveX, moveY, picture, isPassed, currentPosition)) {
continue;
}

setPassedArea(isPassed, queue, moveX, moveY);
++areaRange;
}
}

return areaRange;
}

private static void setPassedArea(boolean[][] isPassed, Queue<Position> queue, int x, int y) {
isPassed[x][y] = true;
queue.offer(new Position(x, y));
}

private static boolean isSameAreaValidation(int moveX, int moveY, int[][] picture, boolean[][] isPassed, Position currentPosition) {
if (isOutOfPicture(moveX, moveY, picture)) {
return false;
}

if (isPassed[moveX][moveY]) {
return false;
}

if (picture[currentPosition.x][currentPosition.y] != picture[moveX][moveY]) {
return false;
}

return true;
}

private static boolean isOutOfPicture(int moveX, int moveY, int[][] picture) {
if (moveX < 0 || moveY < 0) {
return true;
}

if (picture.length <= moveX || picture[0].length <= moveY) {
return true;
}

return false;
}

private static int[] getMinimumConstructionTime(List<Block> blockList, int inventory) {
int answerTime = Integer.MAX_VALUE;
int answerHigh = 0;

for (Block currentBlock : blockList) {
int currentHigh = currentBlock.high;

int up = 0;
int down = 0;

for (Block loopBlock : blockList) {
int loopHigh = loopBlock.high;
int loopCount = loopBlock.count;

if (currentHigh > loopHigh) {
up += (currentHigh - loopHigh) * loopCount;
} else if (currentHigh < loopHigh) {
down += (loopHigh - currentHigh) * loopCount;
}
}

if (down + inventory >= up) {
int time = (down * 2) + up;

if (answerTime > time) {
answerTime = time;
answerHigh = currentBlock.high;
}
}
}

return new int[]{answerTime, answerHigh};
}

static class Block {
private Integer high;
private Integer count;

public Block(Integer high, Integer count) {
this.high = high;
this.count = count;
}
}

static class Position {
private int x;
private int y;

public Position(int x, int y) {
this.x = x;
this.y = y;
}
}
}
  • BFS로 높이 별 갯수를 구한 후 높이 별로 sorting 하여 처리 하려고 했는데 시간 초과로 실패

댓글 공유

문제

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


코드

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
public class 나무_자르기 {
public static void main(String[] args) throws IOException {
try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
long[] nm = convertStringArrayToLongArray(br.readLine().split(" "));

long m = nm[1];

long[] trees = convertStringArrayToLongArray(br.readLine().split(" "));

long answer = solution(trees, m);

System.out.println(answer);
}
}

private static long[] convertStringArrayToLongArray(String[] args) {
long[] array = new long[args.length];
int i = 0;
for (String str : args) {
array[i++] = Integer.parseInt(str);
}

return array;
}

public static long solution(long[] trees, long m) {
Arrays.sort(trees);

long low = 0;
long high = trees[trees.length - 1];

long answer = 0;

while (low <= high) {
long mid = (low + high) >>> 1;
long sum = getTrees(trees, mid);

if (sum < m) {
high = mid - 1;
} else {
answer = Math.max(answer, mid);
low = mid + 1;
}
}

return answer;
}

private static long getTrees(long[] trees, long mid) {
long sum = 0;
for (int i = 0; i < trees.length; i++) {
sum += trees[i] > mid ? trees[i] - mid : 0;
}

return sum;
}
}

흐름

  1. 나무들을 크기가 큰 순서로 정렬한다.
  2. 0부터 높이가 제일 큰 나무까지 탐색하기 위해 low와 high 변수를 지정한다.
  3. low와 high의 중간 값을 구한다.
  4. 나무들을 반복하면서 중간 값 보다 크면 나무 길이와 중간 값을 뺀 값을 더한다.
  5. 그렇게 벌목한 나무를 전부 더한 값이 필요한 나무 길이인 m 보다 작으면,
  6. 벌복한 나무의 길이가 m보다 크거나 같으면, 벌목한 나무가 남는 것 이므로, 나무를 낭비하지 않기 위해 이전에 구한 중간 값(answer) 와 현재 중간 값 중 큰 값을 저장하고 중간 값 + 1 해서 최소 값을 올린다.
  7. 반대로 벌목한 나무의 길이가 m 보다 작은 경우 더 크게 자르기 위해 중간 값 - 1을 high에 저장해서 다음 루프 때 (low + high) >>> 1 에서 더 크게 잘릴 수 있도록 한다.
  8. low와 high가 같아질 때 까지 반복한다.

결과

결과


테스트 케이스

1
2
3
4
5
6
7
8
9
10
11
assertEquals(15, test.solution(new long[] {20, 15, 10, 17}, 7));
assertEquals(3, test.solution(new long[] {6, 6}, 5));
assertEquals(4, test.solution(new long[] {6, 6, 6, 6}, 6));
assertEquals(500000000, test.solution(new long[] {900000000, 900000000, 900000000, 900000000, 900000000}, 2000000000));
assertEquals(19, test.solution(new long[] {20, 15, 10, 17}, 1));
assertEquals(0, test.solution(new long[] {2, 2}, 3));
assertEquals(21, test.solution(new long[] {13, 23, 21, 32}, 12));
assertEquals(2, test.solution(new long[] {1,4,5,7}, 10));
assertEquals(1, test.solution(new long[] {51, 1}, 50));
assertEquals(999999999, test.solution(new long[] {1000000000}, 1));
assertEquals(0, test.solution(new long[] {2, 2,2,2}, 8));

댓글 공유

문제

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


코드

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
public static void main(String[] args) throws IOException {
try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
br.readLine();
int[] array1 = convertStringArrayToIntegerArray(br.readLine().split(" "));

br.readLine();
int[] array2 = convertStringArrayToIntegerArray(br.readLine().split(" "));

int[] answer = solution(array1, array2);

for (int i : answer) {
System.out.println(i);
}
}
}

private static int[] convertStringArrayToIntegerArray(String[] args) {
int[] array = new int[args.length];
int i = 0;
for (String str : args) {
array[i++] = Integer.parseInt(str);
}

return array;
}

public static int[] solution(int[] array1, int[] array2) {
Arrays.sort(array1);

int[] answer = new int[array2.length];

int index = 0;
for (int i : array2) {
answer[index++] = Arrays.binarySearch(array1, i) < 0 ? 0 : 1;
}

return answer;
}

흐름

  1. 이진 탐색(Binary Search)을 위해 검색 할 array를 우선 정렬한다.
  2. array에 value가 존재하면 1, 없으면 0으로 저장하기 위한 answer array를 생성한다.
  3. array에 value가 존재하는 지 확인하기 위해 array2를 돌면서 element를 꺼낸다.
  4. 꺼낸 element를 이진 탐색으로 array안에서 검색해서 존재하면 1, 아니면 0을 저장한다.
  5. 결과를 return 한다.
  6. 끝.

Arrays.binarySearch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static int binarySearch(int[] a, int key) {
return binarySearch0(a, 0, a.length, key);
}

// Like public version, but without range checks.
private static int binarySearch0(int[] a, int fromIndex, int toIndex,
int key) {
int low = fromIndex;
int high = toIndex - 1;

while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = a[mid];

if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
  1. 기준이 되는 array와 array에서 검색 할 value(key)를 입력 받는다.
  2. from index가 to index보다 작거나 같은 동안 반복하면서
  3. 두 index를 더한 값을 >>> 연산을 통해 나눈다.
    1. ex) 15(10) -> 1111(2), 15 >>> 1 = 1111 >>> 1 이므로, 0111(2)가 되고 이는 10진수 7이므로 15를 2로 나눈 값과 같다.
    2. ‘>>’ 연산은 부호 비트를 보존하고, ‘>>>’ 연산은 부호 비트 관계없이 무조건 0으로 채운다.
  4. 중간이 되는 index를 구해서 array의 중간 값을 구한 후
  5. 현재 값이 중간 값 보다 작은 지 큰지 비교하면서 array에 존재하는지 확인하고
  6. 존재한다면 array에서 현재 값의 index를 return하고
  7. 존재하지 않는 다면 array에서 현재 값의 가장 가까운 index를 음수로 return 한다.

결과

결과


테스트 케이스

1
2
3
4
assertArrayEquals(new int[] {1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0}, test.solution(new int[] {1, 3, 4, 6, 9, 13, 18}, new int[] {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}));
assertArrayEquals(new int[] {1, 1, 0, 0, 1}, test.solution(new int[] {4, 1, 5, 2, 3}, new int[] {1, 3, 7, 9, 5}));
assertArrayEquals(new int[] {1}, test.solution(new int[] {1,2}, new int[] {2}));
assertArrayEquals(new int[] {0,1,0,1,0,1,0,1,0,1}, test.solution(new int[] {2,4,6,8,10}, new int[] {1,2,3,4,5,6,7,8,9,10}));

댓글 공유

문제

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


코드

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
public class 달팽이는_올라가고_싶다 {
public static void main(String[] args) throws IOException {
String[] input = getInputData(System.in).split(" ");
int[] abv = convertStringArrayToIntegerArray(input);

System.out.println(solution(abv));
}

public static String getInputData(InputStream in) throws IOException {
try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {

return br.readLine();
}
}

private static int[] convertStringArrayToIntegerArray(String[] args) {
int[] array = new int[args.length];
int i = 0;

for (String str : args) {
array[i++] = Integer.parseInt(str);
}

return array;
}

public static int solution(int[] abv) {
return (abv[2] - abv[1] - 1) / (abv[0] - abv[1]) + 1;
}
}

흐름

  1. 달팽이는 하루에 A 만큼 올라가는데 자면서 B만큼 미끄러지므로 하루에 (A - B) 만큼 씩 올라가서 V미터 만큼 올라가면 된다.
  2. 하지만 꼭대기에 도달하면 미끄러지지 않는다고 하였으므로, 꼭대기(V) 에서 미끄러지는 만큼(B) 을 뺀 거리만큼만 올라가면 된다. (V - B)
  3. 그럼 수식은 (V - B) / (A / B)가 되고 int형은 소수점을 없애므로 나누어떨어지지 않으면 + 1을 하는데
  4. (V - B)에서 - 1을 먼저하고 무조건 1을 더한다.

(V - B - 1) / (A - B) + 1

  • V-B를 X, A-B를 y로 가정
  1. x/y가 나누어 떨어지는 경우
    1. x / y = d 일 때 (x-1)/y 는 반드시 d보다 작다.
    2. int형은 소수점 아래를 없애므로 x-1 /y = d - 1이 되고,
    3. +1을 하면 d가 된다.
  2. x/y가 나누어 떨어지지 않는 경우
    1. x / y = d + f 일 때 y를 양변에 곱하면
    2. x = y(d + f) 여기서 양변에 1을 빼면,
    3. x - 1 = y(d + f) - 1 여기서 y를 양변에 나누면
    4. (x - 1) / y = (d + f) -1 / y 이 된다.
    5. 이 때 1 / y 는 y >= 2 이고 int형은 소수점 아래를 없애버리므로 1 / y 는 없어진다.
      1. y >= 2 인 이유는 현재 x / y가 나누어 떨어지지 않는 경우임을 상정하고 있으므로 y가 1이면 나누어 떨어지기 때문에 y는 2보다 크게 된다.
    6. 그럼 (x - 1) / y = d + f 이 되고 +1을 하면,
    7. (x - 1) / y + 1 = d + f + 1 된다.

결과

결과


테스트 케이스

1
2
3
4
5
6
7
assertEquals(4, test.solution(new int[] {2,1,5}));
assertEquals(2, test.solution(new int[] {5,1,6}));
assertEquals(999999901, test.solution(new int[] {100,99,1000000000}));
assertEquals(1, test.solution(new int[] {5,0,5}));
assertEquals(4, test.solution(new int[] {3,2,6}));
assertEquals(2, test.solution(new int[] {100,1,101}));
assertEquals(3, test.solution(new int[] {3,1,6}));

참고 사이트

댓글 공유

문제

https://programmers.co.kr/learn/courses/30/lessons/17684


코드

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
private static final int CAPITAL_A = 65;
private static final Character LAST_INIT_ALPHABET = 'Z';

public int[] solution(String msg) {
int[] answer = getDictionaryIndex(msg.toCharArray(), initIndexMap());

return answer;
}

private Map<String, Integer> initIndexMap() {
Map<String, Integer> indexMap = new HashMap<>();

Character start = CAPITAL_A;
int i = 1;

while (start <= LAST_INIT_ALPHABET) {

indexMap.put(String.valueOf(start), i);

++start;
++i;
}

return indexMap;
}

private int[] getDictionaryIndex(char[] charArray, Map<String, Integer> indexMap) {
int i = 0;
int arrayLength = charArray.length;
int lastIndex = indexMap.get(String.valueOf(LAST_INIT_ALPHABET));

List<Integer> answer = new ArrayList<>();

while (i < arrayLength) {
StringBuilder sb = new StringBuilder();

int value = 0;
int jump = 0;
for (int j = i; j < arrayLength; j++) {
sb.append(charArray[j]);

String key = sb.toString();
if (indexMap.containsKey(key)) {
value = indexMap.get(key);
jump++;

if (j +1 == arrayLength) {
answer.add(value);
i += jump;
}

continue;
}

answer.add(value);
i += jump;
break;
}

if (!indexMap.containsKey(sb.toString())) {
indexMap.put(sb.toString(), ++lastIndex);
}

sb.setLength(0);
}

return answer.stream().mapToInt(index -> index).toArray();
}

흐름

  1. A부터 Z를 Key로 하는 Map을 만든다.
  2. 압축 할 문자열의 길이만큼 반복한다.
  3. 돌면서 현재 문자가 Map에 key에 포함되는지 확인한다.
  4. 이미 포함되어 있으면(처음엔 A~Z) 해당 문자의 index를 뽑아내기 위해 value를 꺼내서 저장한다.
  5. 이번 문자는 포함되어 있으므로 그 다음 문자열의 index까지 점프하기 위해 jump 변수를 증가시킨다.
  6. 현재 문자가 문자열의 마지막 문자라면 더 이상 사전에서 검색 할 수 없으므로,
  7. 문자열의 index 즉, value를 List에 저장하고 i를 jump 만큼 더해서 문자열의 index를 증가시킨다.
  8. 이미 사전에 있는 문자이므로 continue해서 끝내지 않고 반복문을 올라가서 문자를 더한다.
    1. A가 포함되어 있으면 A 뒤문자인 B를 더해서 AB가 존재하는지 찾기 위해
  9. 사전에 포함되어 있지 않는다면(Map에 key로 존재하지 않는다면)
  10. 이전에 검색했던 문자의 index를 저장하고 i를 jump 시킨 후 반복문을 벗어난다.
  11. 그 후 사전에 존재 하지 않았던 문자를 사전에 등록, Map에 key, lastIndex에서 + 1해서 Map에 추가하고, 문자를 저장했던 StringBuilder를 초기화 시킨다.
  12. 문자열 모두 검색 할 때까지 반복한다.
  13. 사전에서 검색한 index를 저장한 List를 array로 변경한 후 return 한다.
  14. 끝.

결과

번호 속도
테스트 1 통과 (6.64ms, 53MB)
테스트 2 통과 (6.30ms, 52.9MB)
테스트 3 통과 (5.29ms, 50.3MB)
테스트 4 통과 (9.62ms, 53MB)
테스트 5 통과 (5.94ms, 51.1MB)
테스트 6 통과 (10.26ms, 52.8MB)
테스트 7 통과 (7.65ms, 51MB)
테스트 8 통과 (8.38ms, 52.8MB)
테스트 9 통과 (6.01ms, 52.5MB)
테스트 10 통과 (11.33ms, 53MB)
테스트 11 통과 (8.25ms, 51.6MB)
테스트 12 통과 (8.79ms, 51.3MB)
테스트 13 통과 (9.26ms, 53.6MB)
테스트 14 통과 (9.22ms, 51.5MB)
테스트 15 통과 (10.26ms, 53MB)
테스트 16 통과 (8.91ms, 53.5MB)
테스트 17 통과 (10.89ms, 53.2MB)
테스트 18 통과 (7.93ms, 53.2MB)
테스트 19 통과 (8.32ms, 53.1MB)
테스트 20 통과 (8.10ms, 50.8MB)

테스트 케이스

1
2
3
4
assertArrayEquals(new int[] {11, 1, 27, 15}, test.solution("KAKAO"));
assertArrayEquals(new int[] {20, 15, 2, 5, 15, 18, 14, 15, 20, 27, 29, 31, 36, 30, 32, 34}, test.solution("TOBEORNOTTOBEORTOBEORNOT"));
assertArrayEquals(new int[] {1, 2, 27, 29, 28, 31, 30}, test.solution("ABABABABABABABAB"));
assertArrayEquals(new int[] {20, 8, 1, 20, 27, 29, 9, 19, 33, 31, 30, 28, 20, 33, 14, 15, 39, 19, 41, 43, 36, 9, 39, 46, 38, 47, 34, 19, 36, 52, 45, 40, 42, 35, 38, 48, 62, 54, 51, 61, 53, 55, 66, 57, 44, 59, 64, 32, 49, 60, 29, 52, 76, 37, 32, 71, 43, 70, 47, 75, 73, 80, 43, 79, 56, 72, 84, 61, 86, 68, 81, 90, 69, 92, 72, 85, 63, 96, 89, 87, 91, 83, 101, 94, 103, 65, 97, 106, 99, 108, 50, 74, 111, 77, 66, 98, 81, 70, 93, 118, 117, 88, 33, 122, 116, 58, 127, 62, 127, 78, 114, 123, 100, 133, 95, 112, 105, 104, 132, 145, 87, 134, 130, 129, 137, 131, 82, 79, 148, 151, 150, 144, 153, 159, 102, 135, 121, 156, 159, 125, 75, 162, 113, 158, 124, 109, 126, 149, 67, 142, 146, 166, 155, 158, 174, 171, 140, 119, 128, 175, 120, 138, 152, 161, 174, 181, 139, 154, 141, 187, 143, 176, 165, 172, 167, 191, 164, 182, 194, 184, 136, 170, 193, 147, 86}, test.solution("THATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITISTHATTHATISISTHATTHATISNOTISNOTISTHATITITIS"));

여담

  • 코드의 퀄리티가 썩 마음에 들지 않는다.
  • 시간 날 때 리팩토링을 꼭 해야 할 듯 싶다.

댓글 공유

문제

https://programmers.co.kr/learn/courses/30/lessons/17687


코드

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
private static final String[] ABCDEF = new String[] {"A","B","C","D","E","F"};
public String solution(int n, int t, int m, int p) {

int limit = t * m;
String speakString = make(n, limit);

char[] toChar = speakString.toCharArray();

StringBuilder answer = new StringBuilder();

int index = p - 1;
for (int i = 0; i < t; i++) {
answer.append(toChar[index]);
index += m;
}

return answer.toString();
}

public String make(int n, int limit) {
StringBuilder sb = new StringBuilder().append(0);

for (int i = 1; i < limit; i++) {
sb.append(changeDecimal(i, n));
}

return sb.toString();
}

public char[] changeDecimal(int currentNumber, int n) {
StringBuilder sb = new StringBuilder();
while(currentNumber > 0) {
int remain = currentNumber % n;
sb.append(remain >= 10 ? ABCDEF[remain-10] : remain);
currentNumber /= n;
}

return sb.reverse().toString().toCharArray();
}

흐름

  • 진법 n, 미리 구할 숫자의 갯수 t, 게임에 참가하는 인원 m, 튜브의 순서 p
  1. 미리 구할 숫자의 갯수와 참가 인원 수를 곱해서 구해야 할 수의 갯수를 구한다.
  2. 1부터 구해야 될 수까지 반복한다.
  3. 반복하면서 숫자를 진법으로 나눈 나머지를 구한다.
  4. 나머지가 10 이상이면 A, B, C … 으로 치환한다.
  5. 현재 수를 n 진법의 값만큼 나눈다.
  6. 작은 수부터 역순으로 저장되어야 하므로 reverse() 메서드로 역순으로 돌린다.
  7. 0부터 미리 구할 숫자 갯수만큼 반복하면서
  8. n진법으로 치환한 문자열에서 참가인원 숫자만큼 더하면서 숫자를 뽑아 저장한다.

결과

번호 속도
테스트 1 통과 (0.87ms, 50.6MB)
테스트 2 통과 (1.15ms, 50.5MB)
테스트 3 통과 (1.02ms, 52MB)
테스트 4 통과 (1.07ms, 52.1MB)
테스트 5 통과 (4.60ms, 52.6MB)
테스트 6 통과 (4.40ms, 52.2MB)
테스트 7 통과 (4.55ms, 53MB)
테스트 8 통과 (2.62ms, 52.3MB)
테스트 9 통과 (2.45ms, 52.6MB)
테스트 10 통과 (2.57ms, 52.3MB)
테스트 11 통과 (2.49ms, 52MB)
테스트 12 통과 (2.45ms, 52.7MB)
테스트 13 통과 (5.32ms, 50.3MB)
테스트 14 통과 (69.61ms, 77.9MB)
테스트 15 통과 (75.19ms, 75.8MB)
테스트 16 통과 (70.55ms, 78.1MB)
테스트 17 통과 (17.09ms, 53.3MB)
테스트 18 통과 (15.42ms, 52.7MB)
테스트 19 통과 (6.46ms, 52.6MB)
테스트 20 통과 (13.17ms, 53MB)
테스트 21 통과 (29.51ms, 58.7MB)
테스트 22 통과 (21.20ms, 56.5MB)
테스트 23 통과 (41.04ms, 64.1MB)
테스트 24 통과 (59.00ms, 77.4MB)
테스트 25 통과 (74.66ms, 80MB)
테스트 26 통과 (24.89ms, 54.3MB)

테스트 케이스

1
2
3
assertEquals("0111", test.solution(2,4,2,1));
assertEquals("02468ACE11111111", test.solution(16,16,2,1));
assertEquals("13579BDF01234567", test.solution(16,16,2,2));

참고사이트

댓글 공유

Junggu Ji

author.bio


author.job