-
-
Notifications
You must be signed in to change notification settings - Fork 195
[forest000014] Week 07 #943
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
4e05063
Longest Increasing Subsequence - 풀이 수정
forest000014 df9bd02
Reverse Linked List
forest000014 fc55d4e
Longest Substring Without Repeating Characters
forest000014 063a924
Number of Islands
forest000014 282433f
Unique Paths
forest000014 bd409f8
Set Matrix Zeroes
forest000014 02c4246
Set Matrix Zeroes - 풀이 수정
forest000014 233b460
DaleStudy#273 Unique Paths - 공간 복잡도 O(n)으로 줄임
forest000014 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
longest-substring-without-repeating-characters/forest000014.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
Time Complexity: O(n) | ||
Space Complexity: O(c) | ||
(c는 사용되는 모든 character의 가짓수) | ||
|
||
solution (two pointers) | ||
|
||
begin, end 포인터를 각각 1에 두고 시작한다. | ||
end 포인터를 1씩 증가하면서 탐색하다가, 현재 window 내에 이미 존재하는 문자가 또 추가된다면, 그 문자가 window에서 사라질 때까지 begin을 증가시킨다. | ||
|
||
(1) end++을 하는 도중의 모든 end에 대해서는, 또 다른 begin을 찾을 필요성은 없는가? | ||
- 현재 begin보다 더 왼쪽의 begin : 현재의 begin은, window 내에 중복 문자가 없게끔 하는 leftmost 인덱스이다. 따라서, 더 작은 begin은 중복이 있을 것이므로, 탐색할 필요가 없다. | ||
- 현재 begin보다 더 오른쪽의 begin : 더 짧은 길이는 탐색할 필요가 없다. | ||
|
||
(2) begin++을 하는 도중의 모든 begin에 대해서는, 또 다른 end를 찾을 필요성은 없는가? | ||
- 현재 end보다 더 왼쪽의 end : 더 짧은 길이는 탐색할 필요가 없다. | ||
- 현재 end보다 더 오른쪽의 end : 중복된 문자가 있는 구간은 LSWRC가 될 수 없으므로, 탐색할 필요가 없다. | ||
*/ | ||
class Solution { | ||
public int lengthOfLongestSubstring(String s) { | ||
Set<Character> set = new HashSet<>(); | ||
int begin = 0, end = 0; | ||
|
||
int ans = 0; | ||
while (end < s.length()) { | ||
if (set.contains(s.charAt(end))) { | ||
while (begin < end && s.charAt(begin) != s.charAt(end)) { | ||
set.remove(s.charAt(begin++)); | ||
} | ||
set.remove(s.charAt(begin++)); | ||
} else { | ||
set.add(s.charAt(end++)); | ||
ans = Math.max(ans, end - begin); | ||
} | ||
} | ||
|
||
return ans; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* | ||
# Time Complexity: O(m * n) | ||
모든 격자를 최대 2번씩(2중 for loop, dfs 호출) 방문 | ||
|
||
# Space Complexity: O(m * n) | ||
최악의 경우, 모든 격자가 '1'인 경우에 m * n회 dfs() 재귀 호출이 이뤄진다. 각 콜 스택에서의 파라미터와 지역변수가 상수개 필요하므로, O(m * n) | ||
*/ | ||
class Solution { | ||
public int numIslands(char[][] grid) { | ||
int m = grid.length; | ||
int n = grid[0].length; | ||
int[] dr = {-1, 0, 1, 0}; | ||
int[] dc = {0, 1, 0, -1}; | ||
int ans = 0; | ||
for (int i = 0; i < m; i++) { | ||
for (int j = 0; j < n; j++) { | ||
if (grid[i][j] != '1') { | ||
continue; | ||
} | ||
dfs(grid, i, j, dr, dc); | ||
ans++; | ||
} | ||
} | ||
return ans; | ||
} | ||
|
||
private void dfs(char[][] grid, int r, int c, int[] dr, int[] dc) { | ||
grid[r][c] = '2'; // mark as visited | ||
|
||
for (int i = 0; i < 4; i++) { | ||
int nr = r + dr[i]; | ||
int nc = c + dc[i]; | ||
if (nr < 0 || nr >= grid.length || nc < 0 || nc >= grid[0].length | ||
|| grid[nr][nc] != '1') { | ||
continue; | ||
} | ||
dfs(grid, nr, nc, dr, dc); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
Time Complexity: O(n) | ||
Space Complexity: O(1) | ||
|
||
head에서부터 하나씩 next를 탐색하면서, 연결을 반대로 맺어준다. | ||
*/ | ||
|
||
/** | ||
* Definition for singly-linked list. | ||
* public class ListNode { | ||
* int val; | ||
* ListNode next; | ||
* ListNode() {} | ||
* ListNode(int val) { this.val = val; } | ||
* ListNode(int val, ListNode next) { this.val = val; this.next = next; } | ||
* } | ||
*/ | ||
class Solution { | ||
public ListNode reverseList(ListNode head) { | ||
if (head == null) { | ||
return null; | ||
} | ||
|
||
ListNode curr = head; | ||
ListNode next = head.next; | ||
|
||
head.next = null; // 마지막 노드가 될 노드의 next는 null로 세팅 | ||
while (next != null) { | ||
ListNode nnext = next.next; // 연결을 끊기 전에, 그 다음 노드를 미리 nnext로 참조해둔다. | ||
next.next = curr; // 연결을 반대로 맺어준다. | ||
curr = next; | ||
next = nnext; | ||
} | ||
|
||
return curr; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/* | ||
solution 1. 재귀 호출 | ||
Time Complexity: O(m * n * (m + n)) | ||
Space Complexity: O(m * n) | ||
처음에는 공간 복잡도를 O(1)이라고 생각했으나, 검색해보니 함수 호출 스택도 공간 복잡도 계산에 포함시켜야만 한다. 따라서 이 방법은 공간 복잡도 제한을 만족시키지 못한다. | ||
(참고 : https://en.wikipedia.org/wiki/In-place_algorithm), | ||
|
||
|
||
solution 2. bit manipulation | ||
|
||
long 변수를 선언해서, 각 bit에 x번째 row(혹은 col)를 0으로 바꿀지 여부를 기록한다. | ||
(m + n) / 64 개의 변수를 써서 가능하긴 하지만, 64라는 factor가 다소 클 뿐, 결국 공간 복잡도는 O(m + n). | ||
|
||
|
||
solution 3. matrix 내에 안 쓰이는 값 찾기 (probabilistic 접근) | ||
int 범위 내에서, 쓰이는 값보다는 안 쓰이는 값의 갯수가 압도적으로 많다.(1 - (200 * 200 / 2^32) = 0.99999+) | ||
|
||
matrix 내에 안 쓰이는 수를 찾을 때까지 int 범위 내의 랜덤하게 뽑는 행위를 10번만 반복해도, | ||
O(m * n) 시간에 상당히 높은 확률로 안 쓰이는 값을 찾을 수 있다. | ||
(10번 이내에 찾지 못할 확률은 10^(-50) 정도.) | ||
이렇게 찾은 값을 x라고 하자. matrix의 모든 원소를 순회하며, 0인 원소가 있다면 같은 행/열에 존재하는 모든 원소(또다른 0은 제외)를 x로 바꾼 뒤에, 마지막에 한번에 모든 x를 0으로 바꾸는 식으로 풀 수 있다. | ||
|
||
그러나 이 접근법의 확률은 문제의 제한 조건 m, n 범위 하에서 계산한 것이라는 한계가 있다. | ||
m, n이 꽤나 커진다면 랜덤 추출로 안 쓰이는 값을 찾을 확률이 낮아지고, 극단적으로 m * n 이 2^32 이상이 되면, 쓸 수 없는 방법이기도 하다. | ||
Comment on lines
+15
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여러 방법을 시도해보시는 모습이 참 보기 좋습니다 :) 멋집니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 방법을 떠올렸을 땐 꽤나 괜찮아 보였는데, 다시 생각해보니 m, n 크기에 의존하는 풀이더라구요... 🥲 아쉬웠습니다 |
||
|
||
|
||
solution 4. in-place marking | ||
(AlgoDale 풀이를 참고함) | ||
Time Complexity: O(m * n) | ||
Space Complexity: O(1) | ||
|
||
*/ | ||
class Solution { | ||
|
||
// solution 4. in-place marking | ||
public void setZeroes(int[][] matrix) { | ||
int m = matrix.length; | ||
int n = matrix[0].length; | ||
|
||
boolean should0thColumnBeZero = false; | ||
for (int i = 0; i < m; i++) { | ||
if (matrix[i][0] == 0) { | ||
should0thColumnBeZero = true; | ||
} | ||
} | ||
|
||
for (int i = 0; i < m; i++) { | ||
for (int j = 1; j < n; j++) { | ||
if (matrix[i][j] == 0) { | ||
matrix[i][0] = matrix[0][j] = 0; | ||
} | ||
} | ||
} | ||
|
||
for (int i = 1; i < m; i++) { | ||
if (matrix[i][0] == 0) { | ||
for (int j = 1; j < n; j++) { | ||
matrix[i][j] = 0; | ||
} | ||
} | ||
} | ||
for (int i = 1; i < n; i++) { | ||
if (matrix[0][i] == 0) { | ||
for (int j = 0; j < m; j++) { | ||
matrix[j][i] = 0; | ||
} | ||
} | ||
} | ||
if (matrix[0][0] == 0) { | ||
for (int i = 0; i < n; i++) { | ||
matrix[0][i] = 0; | ||
} | ||
} | ||
if (should0thColumnBeZero) { | ||
for (int i = 0; i < m; i++) { | ||
matrix[i][0] = 0; | ||
} | ||
} | ||
} | ||
|
||
/* solution 1. 재귀 호출 | ||
public void setZeroes(int[][] matrix) { | ||
dfs(matrix, 0, 0); | ||
} | ||
|
||
public void dfs(int[][] matrix, int sr, int sc) { | ||
int m = matrix.length; | ||
int n = matrix[0].length; | ||
for (int r = sr; r < m; r++) { | ||
boolean found = false; | ||
for (int c = (r == sr) ? sc : 0; c < n; c++) { | ||
if (matrix[r][c] != 0) { | ||
continue; | ||
} | ||
|
||
int nr = (c == n) ? (r + 1) : r; | ||
int nc = (c == n) ? 0 : c + 1; | ||
dfs(matrix, nr, nc); | ||
setRowAndColumnZeroes(matrix, r, c); | ||
|
||
found = true; | ||
break; | ||
} | ||
if (found) { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
public void setRowAndColumnZeroes(int[][] matrix, int r, int c) { | ||
int m = matrix.length; | ||
int n = matrix[0].length; | ||
for (int i = 0; i < n; i++) { | ||
matrix[r][i] = 0; | ||
} | ||
for (int i = 0; i < m; i++) { | ||
matrix[i][c] = 0; | ||
} | ||
} | ||
*/ | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
Time Complexity: O(m * n) | ||
Space Complexity: O(n) | ||
*/ | ||
class Solution { | ||
public int uniquePaths(int m, int n) { | ||
int[] dp = new int[n]; | ||
|
||
for (int i = 0; i < n; i++) { | ||
dp[i] = 1; | ||
} | ||
|
||
for (int i = 1; i < m; i++) { | ||
int prev = dp[0]; | ||
for (int j = 1; j < n; j++) { | ||
dp[j] += prev; | ||
prev = dp[j]; | ||
} | ||
} | ||
|
||
return dp[n - 1]; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
왠지 forest님께서는 관심 있으실 것 같아서 key-value hashmap을 이용하는 풀이도 남깁니다 :)
시간 복잡도는 둘 다 O(N)인데, key-value로 관리하는 풀이가 연산량이 최대 두 배 적을 것으로 생각합니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
삭제 연산도 적고, left 포인터도 한번에 점프할 수 있어서 더 효율적이겠네요! 한 칸씩 전진하는 걸 더 줄여볼 생각을 했더라면 떠올렸을지도 모르겠네요... 다음 번엔 좀 더 끈질기게 고민해봐야겠습니다 😄