ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 행렬 문제
    알고리즘 2025. 4. 11. 00:20

     

     

     

    행렬 채우기 

     

    1) set-matrix-zeroes

    문제 : https://leetcode.com/problems/set-matrix-zeroes/

    0이 표시된 행렬의 열과 행을 모두 0으로 바꾸는 문제이다. 

     

    1. 모든 0위치를 찾아 저장하고 해당 열과 행을 전체 0으로 설정하는 방법 

    시간 복잡도 : O(m x n)  + z (0의 갯수) * (O(m+n)

    공간 복잡도 : 최대 O(m x n)  (0의 갯수를 따로 저장함)

    class Solution {
        fun setZeroes(matrix: Array<IntArray>): Unit {
            if(matrix.size == 0) return 
            val zeros = mutableListOf<Array<Int>>()
            val v = matrix.size 
            val h = matrix[0].size 
            for(i in 0..v-1) {
                for (j in 0..h-1) {
                    if(matrix[i][j] == 0) {
                        zeros.add(arrayOf(i, j))
                    }
                }
            }
    
            for(zero in zeros) {
                checkZeroMatrix(zero[0], zero[1], matrix, v, h)
            }
    
        }
    
        private fun checkZeroMatrix(i: Int, j: Int, matrix: Array<IntArray>, v: Int, h: Int) {
            for(a in 0..h-1) {
                matrix[i][a] = 0
            }
            for (b in 0..v-1) {
                matrix[b][j] = 0 
            }
        }
    }

     

    2. in-place 풀이 방법 

    • 1)  첫 행/열을 기준으로 삼아서 0이 있는 자리에 마킹한다. 
    • 2) 나머지 셀들을 순회하며 0이 있는 칸(i, j)에서는 첫 행 / 열 에 해당하는 위치에 0으로 마킹한다.
    • 3) 마킹된 행 / 열을 기준으로 0으로 설정한다. 
    • 4) 첫행/열이 0이 맞다면 모두 0으로 표시한다. 

    시간 복잡도 : O(m x n)

    공간 복잡도 : O(1) in-place

    class Solution {
        fun setZeroes(matrix: Array<IntArray>) {
            val m = matrix.size
            val n = matrix[0].size
    
            var firstRowZero = false
            var firstColZero = false
    
            // 1. 첫 행/열에 0이 있는지 확인
            for (i in 0 until m) {
                if (matrix[i][0] == 0) firstColZero = true
            }
            for (j in 0 until n) {
                if (matrix[0][j] == 0) firstRowZero = true
            }
    
            // 2. 0이 있는 셀의 행과 열을 첫 행/열에 마킹
            for (i in 1 until m) {
                for (j in 1 until n) {
                    if (matrix[i][j] == 0) {
                        matrix[i][0] = 0
                        matrix[0][j] = 0
                    }
                }
            }
    
            // 3. 마킹된 행/열을 기준으로 0 설정
            for (i in 1 until m) {
                for (j in 1 until n) {
                    if (matrix[i][0] == 0 || matrix[0][j] == 0) {
                        matrix[i][j] = 0
                    }
                }
            }
    
            // 4. 첫 행/열 처리
            if (firstColZero) {
                for (i in 0 until m) matrix[i][0] = 0
            }
            if (firstRowZero) {
                for (j in 0 until n) matrix[0][j] = 0
            }
        }
    }

     

     

    행렬 특정 순서대로 출력하기 

    1) spiral-matrix 

    문제 : https://leetcode.com/problems/spiral-matrix/

     

    1. 행렬을 변경하면서 방문하는 방법

    처음에는 while문을 사용해서 in-place 방식으로 풀었다. 

    시간 복잡도 : O(m × n)

    공간 복잡도 : O(m × n) (필수 공간이므로 공간 복잡도에 포함) 

    // 내가 푼 방식 
    class Solution {
        fun spiralOrder(matrix: Array<IntArray>): List<Int> {
            if(matrix.size == 0 || matrix[0].size == 0) {
                return listOf()
            }
            val answer = mutableListOf<Int>()
            val m = matrix.size
            val n = matrix[0].size
            
            val d = listOf(listOf(0, 1), listOf(1, 0), listOf(0, -1), listOf(-1, 0))
            var i = 0 
            var j = 0 
            var idx = 0
    
            while(matrix[i][j]!=-200) {
                answer.add(matrix[i][j])
                matrix[i][j] = -200
                var nx = i + d[idx][0]
                var ny = j + d[idx][1]
                if(nx<0 || ny<0 || nx>=m || ny>=n || matrix[nx][ny] == -200) {
                    idx = (idx + 1) % 4
                    nx = i + d[idx][0]
                    ny = j + d[idx][1]
                }
                i = nx 
                j = ny  
                if(nx<0 || ny<0 || nx>=m || ny>=n ) {
                    break
                }       
            }
            return answer.toList()
        }
    }

     

     

    내가 푼 방식은 인덱스 안정성에 떨어질 수 있다. 

    또, while문의 수는 m*n (행렬을 모두 돌아야함) 이므로 이를 활용할 수 있다. 

    class Solution {
        fun spiralOrder(matrix: Array<IntArray>): List<Int> {
            if(matrix.size == 0 || matrix[0].size == 0) {
                return listOf()
            }
            val answer = mutableListOf<Int>()
            val m = matrix.size
            val n = matrix[0].size
            
            val d = listOf(listOf(0, 1), listOf(1, 0), listOf(0, -1), listOf(-1, 0))
            var i = 0 
            var j = 0 
            var idx = 0
            var step = 0 
    
            while(step<m*n) {
                answer.add(matrix[i][j])
                matrix[i][j] = -200
                var nx = i + d[idx][0]
                var ny = j + d[idx][1]
                step ++ 
                if(nx<0 || ny<0 || nx>=m || ny>=n || matrix[nx][ny] == -200) {
                    idx = (idx + 1) % 4
                    nx = i + d[idx][0]
                    ny = j + d[idx][1]
                }
                i = nx 
                j = ny  
    
            }
            return answer.toList()
        }
    }

     

     

    2. 경계 범위를 정하고 순회하는 방법 

    시간 복잡도 : O(m × n)

    공간 복잡도 : O(m × n) (필수 공간이므로 공간 복잡도에 포함) 

     // Solution 2
            val m = matrix.size 
            val n = matrix[0].size
            val result = mutableListOf<Int>()
    
            var top = 0
            var bottom = m-1
            var left =0 
            var right = n-1
    
            while(top<= bottom && left <= right) {
                for(j in left..right) result.add(matrix[top][j])
                top ++
                for(i in top..bottom) result.add(matrix[i][right])
                right --
                if(top<=bottom) {
                    for(j in right downTo left) result.add(matrix[bottom][j]) 
                    bottom --
                }
                if(left <= right) {
                    for(i in bottom downTo top) result.add(matrix[i][left])
                    left++
                }
            }
            return result 
        }

     

     

     

    행렬 회전하기 

    1) rotate-image

    문제 : https://leetcode.com/problems/rotate-image/

     

    행렬을 90도 회전하는 방법은 

    Step1: Transpose ( 전치 행렬 = 행과 열을 바꿈 = (matrix[i][j] <->  matrix[j][i] ) 후 

    Step2: Horizontal revers ( 좌우 반전 = 각 행을 뒤집음)을 실행하는 것이다. 

     

     

    class Solution {
        fun rotate(matrix: Array<IntArray>): Unit {
            val n = matrix.size
    
            // Step1: Transpose 
            for (i in 0 until n) {
                for (j in i+1 until n) {
                    val temp = matrix[i][j]
                    matrix[i][j]= matrix[j][i]
                    matrix[j][i] = temp 
                }
            }
    
            // Step2: horizontal reverse
            for (row in matrix) {
                row.reverse()
            }
        }
    }

     

     

     

    행렬 백트래킹 

     

    1) word-search 

    문제 : https://leetcode.com/problems/word-search

     

    행렬에 주어진 문자와 일치하는 항목이 있는지 검사하는 문제이다. 

    class Solution {
        fun exist(board: Array<CharArray>, word: String): Boolean {
            val m = board.size
            val n = board[0].size
    
            for(i in 0 until m) {
                for(j in 0 until n) {
                    if(board[i][j] == word[0]) {
                        if(find(i, j, 0, board, word)) {
                            return true 
                        }
                    }
                }
            }
            return false 
        }
    
        private fun find(i: Int, j: Int, idx: Int, board: Array<CharArray>,  word: String): Boolean {
            if(idx == word.length) {
                return true 
            }
            if (i !in board.indices || j !in board[0].indices || board[i][j] != word[idx]) {
                return false 
            }
    
            val temp = board[i][j]
            board[i][j] = '#'
    
            val result = find(i+1, j, idx+1, board, word) ||
            find(i-1, j, idx+1, board, word) ||
            find(i, j+1, idx+1, board, word) ||
            find(i, j-1, idx+1, board, word) 
            board[i][j] = temp 
            
            return result 
        }
    
    }

     

     

    '알고리즘' 카테고리의 다른 글

    트리  (1) 2025.05.14
    문자열  (0) 2025.04.17
    연결리스트 문제  (0) 2025.04.10
    그래프(DFS, BFS) 문제  (0) 2025.03.11
    백준 14891) 톱니바퀴 (골드.5)  (0) 2022.08.02
Designed by Tistory.