diff --git "a/Ho/202507/23.\354\204\254 \354\247\200\355\202\244\355\202\244.md" "b/Ho/202507/23.\354\204\254 \354\247\200\355\202\244\355\202\244.md" new file mode 100644 index 0000000..1bea005 --- /dev/null +++ "b/Ho/202507/23.\354\204\254 \354\247\200\355\202\244\355\202\244.md" @@ -0,0 +1,274 @@ +```java +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class UserSolution +{ + static int MAX_HASH_SIZE = 10000; + int N; + int[] hash; + Map> map; + int[][] temp; + boolean[][] vis; + int[][] grid; + + public void init(int N, int mMap[][]) + { + //init 과정에서 전처리가 필요함 + map = new HashMap<>(); + hash = new int[MAX_HASH_SIZE]; + this.N = N; + grid = new int[N][N]; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + // 해당 블록을 기준으로 1 ~ 5개, 4방향 다 고려하기 + // k가 현재 구조물 길이 결정 + grid[i][j] = mMap[i][j]; + for (int k = 1; k <= 4 ; k++) { + + if(inRange(i, j + k)) { + + int curHash = 0; + + for (int l = 0; l < k; l++) { + curHash *= 10; + curHash += mMap[i][l + j] - mMap[i][l + 1 + j] + 5; + } + + hash[curHash]++; + List list = map.getOrDefault(curHash, new ArrayList<>()); + list.add(new Block(i, j, 0)); + map.put(curHash, list); + + int reverseHash = 0; + for (int l = k; l > 0; l--) { + reverseHash *= 10; + reverseHash += mMap[i][l + j] - mMap[i][l - 1 + j] + 5; + } + + if (curHash != reverseHash) { + hash[reverseHash]++; + list = map.getOrDefault(reverseHash, new ArrayList<>()); + list.add(new Block(i, j, 1)); + map.put(reverseHash, list); + } + } + + // 수직도 체크해야함 + if(!inRange(i + k, j)) continue; + + int verCurHash = 0; + + for (int l = 0; l < k; l++) { + verCurHash *= 10; + verCurHash += mMap[l + i][j] - mMap[l + 1 + i][j] + 5; + } + + hash[verCurHash]++; + List list = map.getOrDefault(verCurHash, new ArrayList<>()); + list.add(new Block(i, j, 2)); + map.put(verCurHash, list); + + int verReverseHash = 0; + for (int l = k; l > 0; l--) { + verReverseHash *= 10; + verReverseHash += mMap[l + i][j] - mMap[l - 1 + i][j] + 5; + } + + + if(verCurHash != verReverseHash) { + hash[verReverseHash]++; + list = map.getOrDefault(verReverseHash, new ArrayList<>()); + list.add(new Block(i, j, 3)); + map.put(verReverseHash, list); + } + } + + } + } + } + + public int numberOfCandidate(int M, int mStructure[]) + { + int sum = 0; + if(M == 1) { + return N * N; + } + int fHash = 0; + + for (int i = 0; i < M - 1; i++) { + fHash *= 10; + fHash += mStructure[i+1] - mStructure[i] + 5; + } + sum += hash[fHash]; + return sum; + } + + public int maxArea(int M, int mStructure[], int mSeaLevel) + { + int hashNumber = 0; + + for (int i = 0; i < M - 1; i++) { + hashNumber *= 10; + hashNumber += mStructure[i+1] - mStructure[i] + 5; + } + + if(map.get(hashNumber) == null && M != 1) { + return -1; + } + + if(M == 1) { + temp = new int[N][N]; + int result = 0; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + temp[i][j] += mStructure[0]; + result = Math.max(bfs(mSeaLevel),result); + temp[i][j] -= mStructure[0]; + } + } + return result; + } + + List blocks = map.get(hashNumber); + // 상하좌우로만 영향을 주는 파도 bfs() 구현하기 + + int result = 0; + + + for(Block block : blocks) { + // 현재 블럭 위치에 구조물을 설치하고 섬 개수 카운팅 + temp = new int[N][N]; + if(block.dir == 0) { + for (int i = 0; i < M; i++) { + temp[block.r][block.c + i] = mStructure[i]; + } + } + else if(block.dir == 1) { + for (int i = 0; i < M; i++) { + temp[block.r][block.c + M - 1 - i] = mStructure[i]; + } + } + else if(block.dir == 2) { + for (int i = 0; i < M; i++) { + temp[block.r + i][block.c] = mStructure[i]; + } + } + else if(block.dir == 3) { + for (int i = 0; i < M; i++) { + temp[block.r + M - 1 - i][block.c] = mStructure[i]; + } + } + + int cnt = bfs(mSeaLevel); + result = Math.max(result, cnt); + } + + return result; + } + + int[] drs = {0, 0, 1, -1}; + int[] dcs = {1, -1, 0, 0}; + + private int bfs(int mSeaLevel) { + vis = new boolean[N][N]; + + ArrayDeque q = new ArrayDeque<>(); + for (int i = 0; i < N; i++) { + if (canGo(0, i, mSeaLevel)) { + vis[0][i] = true; + q.add(new Pair(0, i)); + } + if (canGo(i, 0, mSeaLevel)) { + vis[i][0] = true; + q.add(new Pair(i, 0)); + } + if(canGo(N-1,i, mSeaLevel)) { + vis[N-1][i] = true; + q.add(new Pair(N-1, i)); + } + if(canGo(i, N-1, mSeaLevel)) { + vis[i][N-1] = true; + q.add(new Pair(i, N-1)); + } + } + + while(!q.isEmpty()) { + Pair cur = q.poll(); + + for (int i = 0; i < 4; i++) { + int nr = cur.r + drs[i]; + int nc = cur.c + dcs[i]; + + if(canGo(nr, nc, mSeaLevel)) { + vis[nr][nc] = true; + q.add(new Pair(nr, nc)); + } + } + } + + int cnt = 0; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if(!vis[i][j]) { + cnt++; + } + } + } + return cnt; + } + + private boolean canGo(int r, int c, int mSeaLevel) { + if(!inRange(r, c)) return false; + if(vis[r][c]) return false; + if(grid[r][c] + temp[r][c] >= mSeaLevel) return false; + return true; + } + + private boolean inRange(int r, int c) { + return r >= 0 && r < N && c >= 0 && c < N; + } + + class Block { + // dir 0: 우, 1 리버스, 2 하, 3,하 리버스 + int r, c, dir; + + public Block(int r, int c,int dir) { + this.r = r; + this.c = c; + this.dir = dir; + } + } + + class Pair { + int r, c; + + public Pair(int r, int c) { + this.r = r; + this.c = c; + } + } + /** + * 정방향 + * 90도만 돌리기 + * 리버스 돌리기 + * 90도 + 리버스 돌리기 + */ + + /** + * 발생할 수 있는 모든 경우의 수를 cache에 저장하기 + * 1개인 경우는 고려안해도 된다. + * + * i 에서 i + 1 번쨰의 차를 구하고 + 5한 값을 사용한다. + * + */ + + /** + * 부족했던 부분 + * 각 타일간 gap을 이용해서 해싱하는 부분을 잘 못한다. + */ +} +``` \ No newline at end of file