Skip to content

Commit 605857f

Browse files
week11 mission decode-ways
1 parent 6a8a17f commit 605857f

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

_posts/2024-07-08-leetcode-91.md

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
layout: post
3+
title: (Leetcode) 647 - Decode Ways 풀이
4+
categories: [스터디-알고리즘]
5+
tags:
6+
[자바, java, 리트코드, Leetcode, 알고리즘, string, dp, dynamic programming]
7+
date: 2024-07-08 17:50:00 +0900
8+
toc: true
9+
---
10+
11+
---
12+
13+
기회가 되어 [달레님의 스터디](https://github.com/DaleStudy/leetcode-study)에 참여하여 시간이 될 때마다 한문제씩 풀어보고 있다.
14+
15+
[https://neetcode.io/practice](https://neetcode.io/practice)
16+
17+
---
18+
19+
[https://leetcode.com/problems/decode-ways/description/](https://leetcode.com/problems/decode-ways/description/)
20+
21+
## dfs를 통한 모든 경우의 수 탐색하기
22+
23+
일단 가장 단순하게 접근해보았다. 해보면 시간 초과로 실패한다.
24+
25+
```java
26+
class Solution {
27+
public int numDecodings(String s) {
28+
Counter counter = new Counter();
29+
dfs(counter, s, 0, 1);
30+
dfs(counter, s, 0, 2);
31+
return counter.counter;
32+
}
33+
34+
public void dfs(Counter counter, String s, int start, int end) {
35+
if(end > s.length()) {
36+
return;
37+
}
38+
39+
String substring = s.substring(start, end);
40+
int value = Integer.parseInt(substring);
41+
if (value <= 0 || value > 26 || substring.startsWith("0")) {
42+
return;
43+
}
44+
45+
if (end == s.length()) {
46+
counter.increment();
47+
}
48+
49+
dfs(counter, s, end, end + 1);
50+
dfs(counter, s, end, end + 2);
51+
}
52+
}
53+
54+
class Counter {
55+
int counter = 0;
56+
57+
void increment() {
58+
counter++;
59+
}
60+
}
61+
```
62+
63+
## 규칙성으로 풀기 (DP)
64+
65+
우리가 각 자리에서 고려할 수 있는 케이스는 2가지이다.
66+
한 자리를 선택할지, 두 자리를 선택할지이다.
67+
68+
각 자리까지의 경우의 수를 dp 배열에 저장한다.
69+
70+
첫번쨰 자리는 하나밖에 선택하지 못한다.
71+
맨 앞자리가 0인 경우는 불가능이다. 따라서 0을 반환해주고 그 외의 경우에는 1을 넣어준다. (`dp[0] = 1`)
72+
73+
그 이후부터가 조금 복잡하다.
74+
75+
우선 해당 수가 0보다 큰 자리인지를 확인한다.
76+
0보다 크다면 혼자서 선택이 가능하다. 이 경우 앞 자리(n-1)의 경우의 수를 물려받는다. (`dp[i] = dp[i - 1]`)
77+
앞의 수가 무엇이 되었든 혼자서 독립적으로 선택이 가능하다.
78+
79+
이제 두 숫자를 묶어서 선택하는 케이스를 고려해보자.
80+
이 경우에는 앞자리가 0이면 불가능 하다. (`prevDigit == 0`)
81+
문제에 있는 `06` 이 이 케이스에 속한다.
82+
그리고 두 자리를 선택했을 때 26보다 작거나 같아야 한다. (`twoDigit <= 2`)
83+
27보다 큰 경우는 decode 될 수 없다.
84+
만약 두 자리로 선택이 가능할 경우 n-2의 경우의 수를 물려받는다.
85+
다만 앞에서 한자리 수를 선택했을 경우도 있기 때문에 기존의 dp[i] 에 더하기를 해준다. (`dp[i] = dp[i] + dp[i - 2]`)
86+
예외적으로 만약 i가 1인 상태라면 이전의 케이스가 없다. 따라서 1을 더해준다. (`dp[i] = dp[i] + 1`)
87+
88+
```java
89+
class Solution {
90+
public int numDecodings(String s) {
91+
int[] dp = new int[s.length()];
92+
93+
if (s.charAt(0) == '0') {
94+
return 0;
95+
}
96+
dp[0] = 1;
97+
98+
for (int i = 1; i < s.length(); i++) {
99+
int oneDigit = Integer.parseInt(String.valueOf(s.charAt(i)));
100+
if (oneDigit > 0) {
101+
dp[i] = dp[i - 1];
102+
}
103+
104+
int prevDigit = Integer.parseInt(String.valueOf(s.charAt(i - 1)));
105+
if (prevDigit == 0) {
106+
continue;
107+
}
108+
109+
int twoDigit = prevDigit * 10 + oneDigit;
110+
if (twoDigit <= 26) {
111+
if (i > 2) {
112+
dp[i] = dp[i] + dp[i - 2];
113+
} else {
114+
dp[i] = dp[i] + 1;
115+
}
116+
}
117+
}
118+
119+
return dp[s.length() - 1];
120+
}
121+
}
122+
```
123+
124+
### TC, SC
125+
126+
시간 복잡도는 O(n), 공간 복잡도는 O(n)이다.
127+
이런식으로 최근 데이터만 재사용 하는 경우에는 공간복잡도를 O(1) 으로도 줄일 수 있을 것이다.
128+
최근의 데이터가 아닌 이전 데이터들은 더 이상 참조되지 않기 때문에 필요한 공간만 만들어서 보관하면 된다.

0 commit comments

Comments
 (0)