문제

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


코드

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
public String solution(String m, String[] musicinfos) {
String answer = "(None)";

m = getSharpReplace(m);

int maxPlayTime = 0;

for (String music : musicinfos) {
String[] info = music.split(",");

int playTimeToMinute = getPlayTime(info[0], info[1]);
String melody = getMelody(playTimeToMinute, info[3]);

if (melody.contains(m)) {
if (maxPlayTime < playTimeToMinute) {
answer = info[2];
maxPlayTime = playTimeToMinute;
}
}
}

return answer;
}

private String getSharpReplace(String arg) {
return arg.replace("C#", "1")
.replace("D#", "2")
.replace("E#", "3")
.replace("F#", "4")
.replace("G#", "5")
.replace("A#", "6");
}

private int getPlayTime(String start, String end) {
LocalTime startTime = convertLocalTime(start);
LocalTime endTime = convertLocalTime(end);

LocalTime playTime = endTime.minusHours(startTime.getHour()).minusMinutes(startTime.getMinute());

return playTime.getHour() * 60 + playTime.getMinute();
}

private LocalTime convertLocalTime(String time) {
String[] hourAndMinute = time.split(":");

return LocalTime.of(Integer.parseInt(hourAndMinute[0]), Integer.parseInt(hourAndMinute[1]), 0);
}

private String getMelody(int playtime, String melody) {
String sharpReplaceMelody = getSharpReplace(melody);
StringBuilder sb = new StringBuilder();

char[] array = sharpReplaceMelody.toCharArray();
for (int i = 0; i < playtime; i++) {
sb.append(array[i % sharpReplaceMelody.length()]);
}

return sb.toString();
}

흐름

  1. “#”이 붙은 음계들을 유일한 값으로 치환한다.
  2. 곡 정보를 담은 musicinfos의 개수만큼 반복한다.
  3. 돌면서 “,”로 잘라 시작시간, 끝난시간, 곡 이름, 멜로디 순으로 구분하여 String array에 저장한다.
  4. 시작 시간과 끝난 시간을 LocalTime type으로 만들어서 끝난 시간에서 시작 시간을 빼서 얼마나 오래 방송 됐는지 playTime을 구한다.
  5. 곡 정보에 있는 멜로디에서도 “#”이 붙은 음계들을 1번에서 한 것과 같은 값으로 치환한다.
  6. playtime에 따라 멜로디에 음계를 추가하기 위해 멜로디를 char array로 변경한다.
  7. playtime 만큼 반복하면서 멜로디를 만든다.
    1. playtime보다 멜로디가 짧은 경우엔 지금 멜로디에 음계를 이어 붙여 playtime 길이 만큼 만든다.
    2. 멜로디가 더 긴 경우엔 playtime 만큼 자른다.
  8. 이렇게 구한 멜로디에 기억 중인 멜로디 m이 포함된다면 playtime이 가장 긴지 확인하고 곡 정보를 저장한다.
  9. 끝.

결과

번호 속도
테스트 1 통과 (1.31ms, 54.1MB)
테스트 2 통과 (1.38ms, 52.7MB)
테스트 3 통과 (3.19ms, 52.6MB)
테스트 4 통과 (1.33ms, 51.7MB)
테스트 5 통과 (1.44ms, 52.7MB)
테스트 6 통과 (1.42ms, 52.2MB)
테스트 7 통과 (2.26ms, 52.7MB)
테스트 8 통과 (2.27ms, 53.3MB)
테스트 9 통과 (2.38ms, 52.5MB)
테스트 10 통과 (2.31ms, 52MB)
테스트 11 통과 (2.24ms, 53.4MB)
테스트 12 통과 (2.03ms, 53.2MB)
테스트 13 통과 (2.27ms, 53.2MB)
테스트 14 통과 (2.23ms, 52.2MB)
테스트 15 통과 (2.19ms, 53.2MB)
테스트 16 통과 (2.22ms, 52.1MB)
테스트 17 통과 (1.78ms, 52.4MB)
테스트 18 통과 (2.22ms, 53MB)
테스트 19 통과 (2.66ms, 52.5MB)
테스트 20 통과 (2.42ms, 52.1MB)
테스트 21 통과 (2.41ms, 52.3MB)
테스트 22 통과 (3.55ms, 52.9MB)
테스트 23 통과 (3.94ms, 53.2MB)
테스트 24 통과 (2.15ms, 51.9MB)
테스트 25 통과 (1.24ms, 52.3MB)
테스트 26 통과 (1.30ms, 53.2MB)
테스트 27 통과 (1.41ms, 52.6MB)
테스트 28 통과 (1.12ms, 53.1MB)
테스트 29 통과 (12.67ms, 53.4MB)
테스트 30 통과 (13.24ms, 53.1MB)

테스트 케이스

1
2
3
4
5
assertEquals("HELLO", test.solution("ABCDEFG", new String[] {"12:00,12:14,HELLO,CDEFGAB", "13:00,13:05,WORLD,ABCDEF"}));
assertEquals("FOO", test.solution("CC#BCC#BCC#BCC#B", new String[] {"03:00,03:30,FOO,CC#B", "04:00,04:08,BAR,CC#BCC#BCC#B"}));
assertEquals("WORLD", test.solution("ABC", new String[] {"12:00,12:14,HELLO,C#DEFGAB", "13:00,13:05,WORLD,ABCDEF"}));
assertEquals("(None)", test.solution("CDEFGAC", new String[] {"12:00,12:06,HELLO,CDEFGA"}));
assertEquals("FOO", test.solution("CCB", new String[] {"03:00,03:10,FOO,CCB#CCB", "04:00,04:08,BAR,ABC"}));

댓글 공유

문제

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


코드

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
public String[] solution(String[] files) {

List<File> fileList = new ArrayList<>();
for (int i = 0; i < files.length; i++) {
char[] array = files[i].toCharArray();

String originName = files[i];
String head = "";
Integer number = 0;

boolean isString = true;
int numberStartIndex = 0;
for (int j = 0; j < array.length; j++) {
if (isString && isNumber(array[j])) {
head = new String(array, 0, j).toUpperCase();
numberStartIndex = j;
isString = false;
continue;
}

if (!isString && !isNumber(array[j])) {
number = Integer.parseInt(new String(array, numberStartIndex, j - numberStartIndex));
isString = true;
break;
}
}

if (!isString) {
number = Integer.parseInt(new String(array, numberStartIndex, array.length - numberStartIndex));
}

fileList.add(new File(originName, head, number, i));
}

sort(fileList);

return fileList.stream()
.map(File::getOriginName)
.toArray(String[]::new);
}

private void sort(List<File> fileList) {
fileList.sort((f1, f2) -> {
if (f1.head.compareTo(f2.head) != 0) {
return f1.head.compareTo(f2.head);
} else if (f1.number.compareTo(f2.number) != 0) {
return f1.number.compareTo(f2.number);
} else {
return f1.index.compareTo(f2.index);
}
});
}

private boolean isNumber(char ch) {
return (48 <= ch && ch <= 57);
}

static class File {
private final String originName;
private final String head;
private final Integer number;
private final Integer index;

public File(String originName, String head, Integer number, Integer index) {
this.originName = originName;
this.head = head;
this.number = number;
this.index = index;
}

public String getOriginName() {
return this.originName;
}

public String getHead() {
return this.head;
}

public Integer getNumber() {
return this.number;
}

public Integer getIndex() {
return this.index;
}
}

흐름

  1. file 개수만큼 반복하면서 파일명을 char array로 만든다.
  2. char array를 숫자가 나올 때 까지 반복한다.
  3. 숫자가 나오면 0부터 숫자가 나온 index까지 짤라서 head 변수에 저장시키고 숫자가 시작된 index와 다음에 숫자인지 체크 할 flag 변수를 false로 변경한다.
  4. head를 만들고 난 후엔 숫자만 뽑아서 number로 저장해야 하므로
  5. 돌면서 현재 문자가 아니고 지금 값도 숫자가 아니면 지금 index까지 잘라서 number에 저장한다.
  6. 만약 tail이 없어서 이번 조건문에 걸리지 않았다면, 숫자가 시직된 index부터 array 길이에서 숫자가 시작된 index를 뺀 크기 만큼 잘라서 number에 저장한다.
  7. 구한 head, number를 가지고 원래 파일명, head, number, 원래 순서를 갖는 File Object를 생성하고 List에 추가한다.
  8. 리스트를 문제의 제약조건 처럼 정렬한다.
    1. head로 비교해서 정렬
    2. head가 같으면 number로 비교해서 정렬
    3. 둘 다 같으면 원래 순서대로 정렬
  9. 정렬한 List를 String[]로 만들어서 return 한다.

결과

번호 속도
테스트 1 통과 (2.80ms, 52.3MB)
테스트 2 통과 (2.92ms, 52.8MB)
테스트 3 통과 (15.41ms, 54.1MB)
테스트 4 통과 (17.89ms, 54.3MB)
테스트 5 통과 (16.74ms, 54.3MB)
테스트 6 통과 (15.07ms, 53.3MB)
테스트 7 통과 (21.21ms, 54.5MB)
테스트 8 통과 (21.20ms, 53.8MB)
테스트 9 통과 (17.57ms, 53.6MB)
테스트 10 통과 (20.00ms, 53.5MB)
테스트 11 통과 (15.30ms, 53.8MB)
테스트 12 통과 (14.44ms, 54.1MB)
테스트 13 통과 (10.24ms, 53.8MB)
테스트 14 통과 (12.50ms, 54.1MB)
테스트 15 통과 (18.61ms, 54.1MB)
테스트 16 통과 (20.40ms, 53.9MB)
테스트 17 통과 (10.36ms, 53.8MB)
테스트 18 통과 (13.84ms, 54.6MB)
테스트 19 통과 (16.07ms, 54.4MB)
테스트 20 통과 (14.91ms, 53.8MB)


정렬을 stream에 추가 할 경우

stream sorted

1
2
3
4
5
6
return fileList.stream()
.sorted(Comparator.comparing(File::getHead)
.thenComparing(Comparator.comparing(File::getNumber)
.thenComparing(File::getIndex)))
.map(File::getOriginName)
.toArray(String[]::new);

결과

번호 속도
테스트 1 통과 (10.64ms, 53.2MB)
테스트 2 통과 (18.65ms, 53.2MB)
테스트 3 통과 (25.96ms, 54.7MB)
테스트 4 통과 (24.73ms, 54.8MB)
테스트 5 통과 (20.97ms, 54.3MB)
테스트 6 통과 (29.57ms, 54.3MB)
테스트 7 통과 (30.45ms, 54.3MB)
테스트 8 통과 (24.91ms, 54.3MB)
테스트 9 통과 (26.40ms, 54.8MB)
테스트 10 통과 (28.88ms, 54.1MB)
테스트 11 통과 (22.73ms, 54.7MB)
테스트 12 통과 (25.60ms, 54.4MB)
테스트 13 통과 (22.06ms, 54.2MB)
테스트 14 통과 (19.49ms, 54.9MB)
테스트 15 통과 (17.53ms, 54.2MB)
테스트 16 통과 (20.05ms, 54.1MB)
테스트 17 통과 (18.01ms, 54.7MB)
테스트 18 통과 (18.53ms, 53.7MB)
테스트 19 통과 (26.25ms, 54.2MB)
테스트 20 통과 (20.81ms, 55.2MB)

테스트 케이스

1
2
3
4
5
assertArrayEquals(new String[] {"img1.png", "IMG01.GIF", "img02.png", "img2.JPG", "img10.png", "img12.png"}, test.solution(new String[] {"img12.png", "img10.png", "img02.png", "img1.png", "IMG01.GIF", "img2.JPG"}));
assertArrayEquals(new String[] {"A-10 Thunderbolt II", "B-50 Superfortress", "F-5 Freedom Fighter", "F-14 Tomcat"}, test.solution(new String[] {"F-5 Freedom Fighter", "B-50 Superfortress", "A-10 Thunderbolt II", "F-14 Tomcat"}));
assertArrayEquals(new String[] {"img100.p2ng", "img202.png123"}, test.solution(new String[] {"img202.png123", "img100.p2ng"}));
assertArrayEquals(new String[] {"foo010bar020.zip", "foo010bar030.zip"}, test.solution(new String[] {"foo010bar020.zip", "foo010bar030.zip"}));
assertArrayEquals(new String[] {"F-15", "F-17", "F-22"}, test.solution(new String[] {"F-22", "F-17", "F-15"}));

댓글 공유

문제

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"}));

댓글 공유

문제

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));

참고사이트

댓글 공유

문제

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


코드

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
private static final int MISS_RUN_TIME = 5;
public int solution(int cacheSize, String[] cities) {
if (cacheSize == 0) {
return cities.length * MISS_RUN_TIME;
}

Map<String, Integer> lru = new LinkedHashMap<String, Integer>(cacheSize, 1, true){
@Override
public boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
return size() > cacheSize;
}
};

int answer = 0;
for(String key : cities) {
key = key.toLowerCase();

if(lru.containsKey(key)) {
lru.get(key);
answer += 1;
} else {
lru.put(key, 0);
answer += MISS_RUN_TIME;
}
}

return answer;
}

흐름

  1. 캐시가 0인 경우엔 캐시에 저장 할 수 없으니 항상 miss 이므로 배열의 크기 만큼 5를 곱해서 return 한다.
  2. LinkedHashMap의 경우 accessOrder parameter를 통해 Map의 순서를 access 기준으로 변경 할 수 있는데 우리는 LRU, 즉 가장 오래 사용되지 않은 데이터를 삭제 해야하므로 accessOrder를 true로 갖는 생성자로 LinkedHashMap 인스턴스를 생성한다.
  3. 그 후 removeEldestEntry()를 override해서 캐시의 크기보다 Map의 사이즈가 커질 경우 가장 오래 사용되지 않은 데이터를 삭제하도록 수정한다.
  4. 배열에서 문자열을 가져오면서 Map에 저장되어 있는지 비교한다.
  5. Map에 저장되어 있다면, get()을 통해 access하고 1초를 더한다.
  6. 저장되어 있지 않다면, put 하는데 이 때 Map의 크기가 캐시보다 크다면 아까 Override 한 removeEldestEntry()에 의해 가장 오래 사용되지 않은 값이 삭제되면서 지금 put한 데이터가 추가한다.
  7. 캐시에 없는 데이터를 추가했으니 5초를 더한다.
  8. 모든 초를 더한 값을 return 한다.

결과

번호 속도
테스트 1 통과 (1.11ms, 52.1MB)
테스트 2 통과 (1.20ms, 52.2MB)
테스트 3 통과 (1.08ms, 50.9MB)
테스트 4 통과 (1.23ms, 51.7MB)
테스트 5 통과 (0.94ms, 52.4MB)
테스트 6 통과 (0.78ms, 50.2MB)
테스트 7 통과 (0.78ms, 52.2MB)
테스트 8 통과 (1.12ms, 52.7MB)
테스트 9 통과 (1.15ms, 50.8MB)
테스트 10 통과 (1.34ms, 52.4MB)
테스트 11 통과 (45.53ms, 89.6MB)
테스트 12 통과 (1.45ms, 52.5MB)
테스트 13 통과 (1.43ms, 52.5MB)
테스트 14 통과 (1.69ms, 52.7MB)
테스트 15 통과 (2.42ms, 50.5MB)
테스트 16 통과 (2.85ms, 52.9MB)
테스트 17 통과 (0.78ms, 52MB)
테스트 18 통과 (4.34ms, 53.5MB)
테스트 19 통과 (4.28ms, 53.3MB)
테스트 20 통과 (4.15ms, 50.9MB)

테스트 케이스

1
2
3
4
5
6
7
8
assertEquals(42, test.solution(3, new String[]{"Jeju", "Pangyo", "Jeju", "NewYork", "LA", "Jeju", "Pangyo", "Seoul", "NewYork", "LA"}));
assertEquals(50, test.solution(3, new String[]{"Jeju", "Pangyo", "Seoul", "NewYork", "LA", "Jeju", "Pangyo", "Seoul", "NewYork", "LA"}));
assertEquals(21, test.solution(3, new String[]{"Jeju", "Pangyo", "Seoul", "Jeju", "Pangyo", "Seoul", "Jeju", "Pangyo", "Seoul"}));
assertEquals(60, test.solution(2, new String[]{"Jeju", "Pangyo", "Seoul", "NewYork", "LA", "SanFrancisco", "Seoul", "Rome", "Paris", "Jeju", "NewYork", "Rome"}));
assertEquals(52, test.solution(5, new String[]{"Jeju", "Pangyo", "Seoul", "NewYork", "LA", "SanFrancisco", "Seoul", "Rome", "Paris", "Jeju", "NewYork", "Rome"}));
assertEquals(16, test.solution(2, new String[]{"Jeju", "Pangyo", "NewYork", "newyork"}));
assertEquals(25, test.solution(0, new String[]{"Jeju", "Pangyo", "Seoul", "NewYork", "LA"}));
assertEquals(18, test.solution(1, new String[]{"LA", "LA", "LA", "LA", "LA", "LA", "LA", "LA", "LA", "LA", "LA", "LA", "LA", "LA"}));

참고 사이트

댓글 공유

문제

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


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public int[] solution(int brown, int yellow) {
int sum = brown + yellow;
int[] answer = new int[2];

for (int i = 2; i < sum; i++) {
if (sum % i == 0) {
int x = ((sum / i) * 2) + ((i * 2) - 4);
int y = sum - x;

if (brown == x && yellow == y) {
answer = new int[] {sum / i, i};
break;
}
}
}
return answer;
}

흐름

  1. 갈색과 노란색을 더해 전체 크기를 구한다.
  2. 전체 크기를 2부터 반복한다. (1인 경우는 없으므로)
  3. i로 sum을 나눠서 떨어진다면, 즉 약수라면
  4. sum에서 i를 나눈 값에 2를 곱해서 위 아래 가로의 길이를 구하고
  5. i에 마찬가지로 2를 곱해서 좌 우 세로의 길이를 구하고
  6. 꼭지점들은 가로 세로가 겹치므로 -4를 한다.
  7. 이렇게 구한 갈색을 sum에서 빼서 노란색의 값을 구한다.
  8. 구한 갈색과 노란색 값이 넘겨받은 brown과 yellow와 같으면 끝
  9. 아니라면 반복한다.

결과

번호 속도
테스트 1 통과 (1.57ms, 52.3MB)
테스트 2 통과 (1.76ms, 51.1MB)
테스트 3 통과 (1.88ms, 50.1MB)
테스트 4 통과 (1.44ms, 52.7MB)
테스트 5 통과 (1.52ms, 50.5MB)
테스트 6 통과 (1.48ms, 49.8MB)
테스트 7 통과 (1.62ms, 50.8MB)
테스트 8 통과 (1.52ms, 52.6MB)
테스트 9 통과 (1.58ms, 52.4MB)
테스트 10 통과 (1.58ms, 50.4MB)
테스트 11 통과 (1.53ms, 53MB)
테스트 12 통과 (1.56ms, 52.3MB)
테스트 13 통과 (1.48ms, 53.3MB)

테스트 케이스

1
2
3
assertArrayEquals(new int[]{4, 3}, test.solution(10, 2));
assertArrayEquals(new int[]{3, 3}, test.solution(8, 1));
assertArrayEquals(new int[]{8, 6}, test.solution(24, 24));

댓글 공유

문제

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


코드

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

private static final String ENTER = "Enter";
private static final String LEAVE = "Leave";
private static final String CHANGE = "Change";

private static final String MESSAGE_ENTER = "님이 들어왔습니다.";
private static final String MESSAGE_LEAVE = "님이 나갔습니다.";

public String[] solution(String[] record) {
List<String[]> list = new ArrayList<>();
Map<String, String> nickName = new HashMap<>();

int returnArraySize = 0;
for (String s : record) {
String[] split = s.split(" ");
String[] actionAndUid = new String[3];

actionAndUid[0] = split[0];
actionAndUid[1] = split[1];

if (!CHANGE.equals(split[0])) {
list.add(actionAndUid);
returnArraySize++;
}

if (!LEAVE.equals(split[0])) {
nickName.put(split[1], split[2]);
}
}

String[] answer = new String[returnArraySize];
int i = 0;
for (String[] array : list) {
switch (array[0]) {
case ENTER :
answer[i] = nickName.get(array[1]) + MESSAGE_ENTER;
break;
case LEAVE :
answer[i] = nickName.get(array[1]) + MESSAGE_LEAVE;
break;
}

i++;
}

return answer;
}

흐름

  1. 문자열을 공백으로 나눠서 행동과 유저의 아이디를 저장하는 배열에 담는다.
  2. 행동이 Change가 아닌 경우엔 채팅방에 입장했거나 나갓다는 문구룰 출력해야 하기 때문에 List에 담는다.
  3. 행동이 Leave가 아닌 경우엔 닉네임이 변경되었거나, 새로 방에 들어온 것이므로 유저 아이디를 key로하는 map에 value로 닉네임을 저장한다.
  4. 모두 저장했으면 List만큼 돌면서 해당 행동에 맞는 문자열을 만들어 저장한다.

결과

번호 속도
테스트 1 통과 (18.70ms, 54.1MB)
테스트 2 통과 (17.35ms, 52.4MB)
테스트 3 통과 (17.84ms, 54.4MB)
테스트 4 통과 (19.81ms, 54MB)
테스트 5 통과 (27.75ms, 56.1MB)
테스트 6 통과 (30.38ms, 56.1MB)
테스트 7 통과 (35.26ms, 54.4MB)
테스트 8 통과 (27.59ms, 55.2MB)
테스트 9 통과 (30.72ms, 56.5MB)
테스트 10 통과 (28.67ms, 56.1MB)
테스트 11 통과 (25.16ms, 56.2MB)
테스트 12 통과 (26.04ms, 56.6MB)
테스트 13 통과 (26.07ms, 55MB)
테스트 14 통과 (43.84ms, 57.2MB)
테스트 15 통과 (20.35ms, 52.4MB)
테스트 16 통과 (18.03ms, 52.8MB)
테스트 17 통과 (19.77ms, 54.2MB)
테스트 18 통과 (18.86ms, 52.5MB)
테스트 19 통과 (35.94ms, 56.7MB)
테스트 20 통과 (26.22ms, 55.5MB)
테스트 21 통과 (30.18ms, 56.5MB)
테스트 22 통과 (28.53ms, 52.5MB)
테스트 23 통과 (29.40ms, 57.5MB)
테스트 24 통과 (37.73ms, 57.3MB)
테스트 25 통과 (262.95ms, 158MB)
테스트 26 통과 (292.57ms, 158MB)
테스트 27 통과 (333.29ms, 169MB)
테스트 28 통과 (324.94ms, 163MB)
테스트 29 통과 (282.87ms, 157MB)
테스트 30 통과 (286.21ms, 153MB)
테스트 31 통과 (225.37ms, 147MB)
테스트 32 통과 (255.96ms, 137MB)

테스트 케이스

1
2
3
String[] actual = {"Enter uid1234 Muzi", "Enter uid4567 Prodo","Leave uid1234","Enter uid1234 Prodo","Change uid4567 Ryan"};
String[] expected ={"Prodo님이 들어왔습니다.", "Ryan님이 들어왔습니다.", "Prodo님이 나갔습니다.", "Prodo님이 들어왔습니다."};
assertArrayEquals(expected, test.solution(actual));

댓글 공유

문제

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


코드

1
2
3
4
5
6
7
8
9
10
11
12
int solution(int[][] land) {
for (int i = land.length - 2; i >= 0; i--) {
int rowIndex = i + 1;
land[i][0] += max(land[rowIndex][1], max(land[rowIndex][2], land[rowIndex][3]));
land[i][1] += max(land[rowIndex][0], max(land[rowIndex][2], land[rowIndex][3]));
land[i][2] += max(land[rowIndex][0], max(land[rowIndex][1], land[rowIndex][3]));
land[i][3] += max(land[rowIndex][0], max(land[rowIndex][1], land[rowIndex][2]));
}

int answer = max(land[0][0], max(land[0][1], max(land[0][2], land[0][3])));
return answer;
}

흐름

  1. 마지막 행 전행 부터 반복문을 시작해서 i가 0이 될 때까지 반복한다.
  2. i행의 각 인덱스에는 자기 자신의 열을 제외한 이전 행의 값 중 가장 큰 값과 자기 자신의 값을 더한 값을 저장한다.
  3. 위 과정을 반복하면 0번째 행들의 index에 계산된 값들이 할당되어 있을 테니
  4. 0 번째 행 중에서 가장 큰 값을 return한다.

결과

정확성

번호 속도
테스트 1 통과 (1.05ms, 51.1MB)
테스트 2 통과 (1.16ms, 52.7MB)
테스트 3 통과 (1.16ms, 50.8MB)
테스트 4 통과 (1.18ms, 53MB)
테스트 5 통과 (1.18ms, 52.7MB)
테스트 6 통과 (1.14ms, 52.9MB)
테스트 7 통과 (1.18ms, 51.4MB)
테스트 8 통과 (1.13ms, 52.7MB)
테스트 9 통과 (1.25ms, 53.3MB)
테스트 10 통과 (1.21ms, 50.7MB)
테스트 11 통과 (1.18ms, 52.4MB)
테스트 12 통과 (4.25ms, 52.5MB)
테스트 13 통과 (1.19ms, 53.2MB)
테스트 14 통과 (1.16ms, 53.1MB)
테스트 15 통과 (1.19ms, 51MB)
테스트 16 통과 (1.16ms, 52.5MB)
테스트 17 통과 (1.14ms, 55.3MB)
테스트 18 통과 (1.16ms, 52.2MB)

효율성

번호 속도
테스트 1 통과 (28.10ms, 94.3MB)
테스트 2 통과 (28.01ms, 95.7MB)
테스트 3 통과 (25.28ms, 97.6MB)
테스트 4 통과 (25.93ms, 101MB)

테스트 케이스

1
2
3
4
5
6
7
8
assertEquals(16, test.solution(new int[][] {{1,2,3,5},{5,6,7,8},{4,3,2,1}}));
assertEquals(20, test.solution(new int[][] {{4, 3, 2, 1}, {2, 2, 2, 1}, {6, 6, 6, 4}, {8, 7, 6, 5}}));
assertEquals(115, test.solution(new int[][] {{1, 2, 3, 5}, {5, 6, 7, 8}, {4, 3, 2, 1}, {100, 0, 9, 8}}));
assertEquals(33, test.solution(new int[][] {{1, 2, 3, 5}, {10, 11, 12, 11}, {16, 15, 13, 13}}));
assertEquals(409, test.solution(new int[][] {{1, 100, 15, 3}, {1, 2, 3, 4}, {100, 99, 98, 97}, {97, 98, 99, 100}, {4, 3, 2, 1}, {100, 100, 100, 100}, {1, 1, 1, 1}}));
assertEquals(16, test.solution(new int[][] {{1, 2, 3, 4}, {5, 6, 7, 9}, {4, 3, 2, 1}}));
assertEquals(125, test.solution(new int[][] {{9, 5, 2, 3}, {9, 8, 6, 7}, {8, 9, 7, 1}, {100, 9, 8, 1}}));
assertEquals(20, test.solution(new int[][] {{4, 3, 2, 1}, {2, 2, 2, 1}, {6, 6, 6, 4}, {8, 7, 6, 5}}));

댓글 공유

문제

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


코드

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
private static final char PLUS = '+';
private static final char MINUS = '-';
private static final char MULTIPLICATION = '*';

public long solution(String expression) {
char[] chars = expression.toCharArray();

Object[] numberAndOperator = getNumbersAndOperatorSet(chars);
List<Long> numberList = (List<Long>) numberAndOperator[0];
List<Character> operatorList = (List<Character>) numberAndOperator[1];

char[] operators = getExpressionIncludeOperators(operatorList);
List<String> operatorSetList = getOperatorSetList(operators);

return getMax(numberList, operatorList, operatorSetList);
}

private Object[] getNumbersAndOperatorSet(char[] expression) {
List<Long> numberList = new ArrayList<>();
List<Character> operatorList = new ArrayList<>();

StringBuilder sb = new StringBuilder();
for (char c : expression) {
switch (c) {
case PLUS:
case MINUS:
case MULTIPLICATION:
numberList.add(Long.valueOf(sb.toString()));
operatorList.add(c);

sb.setLength(0);
break;
default:
sb.append(c);
break;
}
}

numberList.add(Long.valueOf(sb.toString()));

return new Object[] {numberList, operatorList};
}

private char[] getExpressionIncludeOperators(List<Character> operatorList) {
Set<Character> set = new HashSet<>();
List<Character> list = new ArrayList<>();

for (char c : operatorList) {
if (set.add(c)) {
list.add(c);
}
}

char[] operators = new char[list.size()];
int i = 0;
for (char c : list) {
operators[i++] = c;
}

return operators;
}


private List<String> getOperatorSetList(char[] chars) {
List<String> operatorSetList = new ArrayList<>();
Set<String> set = new HashSet<>();

for (int i = 1; i <= chars.length; i++) {
perm(chars, 0, i, operatorSetList, set);
}

return operatorSetList;
}

private void perm(char[] array, int depth, int length, List<String> operatorList, Set<String> set) {
if (depth == length) {

StringBuilder sb = new StringBuilder();
for (char c : array) {
sb.append(c);
}

if (set.add(sb.toString())) {
operatorList.add(sb.toString());
}

return;
}

for (int i = depth; i < array.length; i++) {
swap(array, i, depth);
perm(array, depth + 1, length, operatorList, set);
swap(array, i, depth);
}
}

private void swap(char[] arrary, int i, int j) {
char temp = arrary[i];
arrary[i] = arrary[j];
arrary[j] = temp;
}

private Long getMax(List<Long> numberList, List<Character> operatorList, List<String> operatorSetList) {
long max = 0;

for (String operatorSet : operatorSetList) {
char[] operators = operatorSet.toCharArray();

LinkedList<Long> numberQueue = new LinkedList<>(numberList);
LinkedList<Character> operatorQueue = new LinkedList<>(operatorList);

for (char operatorToCalculate : operators) {
Stack<Long> numberStack = new Stack<>();
Stack<Character> operatorStack = new Stack<>();

long first = numberQueue.poll();
numberStack.push(first);
numberQueue.offer(first);

Stack[] stacks = new Stack[] {numberStack, operatorStack};
LinkedList[] queues = new LinkedList[] {numberQueue, operatorQueue};

calculatePriority(stacks, queues, operatorToCalculate);
}

max = (max > Math.abs(numberQueue.peek())) ? max : Math.abs(numberQueue.poll());
}

return max;
}

private void calculatePriority(Stack[] staks, LinkedList[] queues, char operatorToCalculate) {
Stack<Long> numberStack = staks[0];
Stack<Character> operatorStack = staks[1];

LinkedList<Long> numberQueue = queues[0];
LinkedList<Character> operatorQueue = queues[1];

int limit = operatorQueue.size();
for (int i = 0; i < limit; i++) {
long currentNumber = numberQueue.poll();
numberStack.push(currentNumber);

Character currentOperator = operatorQueue.poll();
operatorStack.push(currentOperator);

if (operatorStack.peek() == operatorToCalculate) {
long n1 = numberStack.pop();
long n2 = numberStack.pop();
char op = operatorStack.pop();

long sum = sum(n2, n1, op);
numberStack.push(sum);

numberQueue.pollLast();
numberQueue.offer(sum);
} else {
numberQueue.offer(currentNumber);
operatorQueue.offer(currentOperator);
}
}
}

private Long sum(long n2, long n1, char op) {
long sum = 0;

switch (op) {
case '*' :
sum = n2 * n1;
break;
case '+' :
sum = n2 + n1;
break;
case '-' :
sum = n2 - n1;
break;
}

return sum;
}

흐름

  1. 수식으로 넘어온 문자열을 숫자와 연산자로 나눈다.
  2. 연산자들을 중복되지 않게 저장한다.
  3. 문자열에 포함되어 있는 연산자들을 재귀로 반복하면서 모든 순열을 구한다.
    1. 0번째와 1번째를 교환하고 0번째와 2번째를 교환하고 하는 식으로 모든 순열을 구한다.
    2. 연산자의 개수만큼 순열로 만들어서 경우의 수를 구하기 위해 연산자가 2개인 경우엔 2! = 2개, 3개인 경우엔 3! = 6개가 된다.
  4. 모든 경우의 수를 구했으면 우선 순열의 수 만큼 반복해서 모든 경우의 수의 값을 구해야 하므로 순열의 수 만큼 반복한다.
  5. 돌면서 숫자를 담은 리스트와 연산자를 담은 리스트의 사이즈와 같은 큐를 만들고 각각 값들을 저장해서 초기화한다.
  6. 이번에 계산 할 순열(ex) * + -)을 char[]로 나눠서 그 갯수만큼 loop 돈다.
  7. 돌면서 숫자와 연산자를 저장 할 Stack를 각각 만든다.
  8. 숫자를 저장한 큐에서 하나를 꺼내서 stack에 저장하고 꺼낸 놈을 다시 큐의 맨 마지막에 저장한다.
  9. 그 후 큐의 개수만큼 loop 돌면서 큐들에서 하나씩 꺼내고 마찬가지로 스택에 저장한다.
  10. 그리고 꺼낸 연산자가 지금 계산 해야할 연산자라면 stack들에서 숫자 2개와 연산자를 pop하고 연산자에 맞게 계산해준다.
  11. 계산 한 값은 뒤에 또 그 값을 다른 값과 계산해야하므로 stack와 queue에 저장한다.
  12. 그리고 8번에서 큐에 초기값을 먼저 저장해서 큐의 맨 앞값과 큐의 맨 마지막 값이 계산된 것이므로 큐의 맨 마지막 값을 꺼낸다.
  13. 이번에 계산 할 연산자가 아니라면 지금 꺼낸 값과 연산자는 다시 큐에 저장한다.
  14. 4번부터 13번 까지를 모두 반복하면 끝

* + - 일 경우 Queue와 Stack의 변화

  1. 초기화
1
2
LinkedList<Long> numberQueue = new LinkedList<>(numberList);
LinkedList<Character> operatorQueue = new LinkedList<>(operatorList);
1 2 3 4 5
숫자 100 200 300 500 20
연산자 - * - +
  1. 숫자 초기값 저장
1
2
3
long first = numberQueue.poll();
numberStack.push(first);
numberQueue.offer(first);
1 2 3 4 5
숫자 200 300 500 20 100
연산자 - * - +

숫자 연산자
5
4
3
2
1 100
  1. 이후 반복
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
for (int i = 0; i < limit; i++) {
long currentNumber = numberQueue.poll();
numberStack.push(currentNumber);

Character currentOperator = operatorQueue.poll();
operatorStack.push(currentOperator);

if (operatorStack.peek() == operatorToCalculate) {
long n1 = numberStack.pop();
long n2 = numberStack.pop();
char op = operatorStack.pop();

long sum = sum(n2, n1, op);
numberStack.push(sum);

numberQueue.pollLast();
numberQueue.offer(sum);
} else {
numberQueue.offer(currentNumber);
operatorQueue.offer(currentOperator);
}
}

1회 반복

1 2 3 4 5
숫자 300 500 20 100 200
연산자 * - + -
숫자 연산자
5
4
3
2 200
1 100 -

2회 반복

1 2 3 4 5
숫자 500 20 100 60000
연산자 - + -
숫자 연산자
5
4
3
2 60000
1 100

3회 반복

1 2 3 4 5
숫자 20 100 60000 500
연산자 + - -
숫자 연산자
5
4
3 500
2 60000
1 100 -

4회 반복

1 2 3 4 5
숫자 100 60000 500 20
연산자 - - +
숫자 연산자
5
4 20
3 500 -
2 60000 +
1 100 -
  • 이런 식으로 반복되고 queue 크기 만큼 돌았다는건 우선 계산해야 될 연산자를 다 계산 했다는 것이므로 다시 스택을 비우고 처음부터 위 계산을 반복한다.
  • 다시 계산해도 큐에 계산 된 값이 저장되어 있으므로 정상적으로 계산된다.

결과

번호 속도
테스트 1 통과 (1.22ms, 52.9MB)
테스트 2 통과 (1.25ms, 51.9MB)
테스트 3 통과 (1.54ms, 51.7MB)
테스트 4 통과 (1.62ms, 52.6MB)
테스트 5 통과 (1.70ms, 52.8MB)
테스트 6 통과 (1.73ms, 52.9MB)
테스트 7 통과 (1.69ms, 52.1MB)
테스트 8 통과 (1.76ms, 52.9MB)
테스트 9 통과 (1.81ms, 52.3MB)
테스트 10 통과 (1.86ms, 52.1MB)
테스트 11 통과 (1.70ms, 50.6MB)
테스트 12 통과 (1.90ms, 52.3MB)
테스트 13 통과 (2.62ms, 52.2MB)
테스트 14 통과 (2.17ms, 53.2MB)
테스트 15 통과 (2.15ms, 53.1MB)
테스트 16 통과 (1.36ms, 52.7MB)
테스트 17 통과 (1.57ms, 52.8MB)
테스트 18 통과 (1.28ms, 52.9MB)
테스트 19 통과 (1.30ms, 51.3MB)
테스트 20 통과 (1.33ms, 52.6MB)
테스트 21 통과 (1.53ms, 52.5MB)
테스트 22 통과 (1.47ms, 54.3MB)
테스트 23 통과 (1.21ms, 52.3MB)
테스트 24 통과 (2.11ms, 50.7MB)
테스트 25 통과 (2.17ms, 52.2MB)
테스트 26 통과 (1.39ms, 52.3MB)
테스트 27 통과 (2.70ms, 53MB)
테스트 28 통과 (1.74ms, 52.6MB)
테스트 29 통과 (1.59ms, 50.4MB)
테스트 30 통과 (1.58ms, 50.2MB)

테스트 케이스

1
2
assertEquals(60420, test.solution("100-200*300-500+20"));
assertEquals(300, test.solution("50*6-3*2"));

댓글 공유

Junggu Ji

author.bio


author.job