PS/문제 풀이
[프로그래머스/Swift] 17679번 - 프렌즈 4블록
시르베어
2025. 3. 1. 14:22
🔗 문제 링크
https://school.programmers.co.kr/learn/courses/30/lessons/17679
💡 구현 아이디어
- 맵을 순회하면서 조건을 확인( (x, y) 가 (x+1, y), (x, y+1), (x+1, y+1)와 같은 블록인가?
- 만약 같은 블록이라면 checkPos에 (x, y)를 저장
- 순회가 끝나면 checkPos에 저장된 위치인 (x, y), (x+1, y), (x, y+1), (x+1, y+1)의 값이 “-1”이 아니면 “-1”로 바꿔주면서 개수를 기록. 이때 저장된 위치가 없으면 삭제할 블록이 없기 때문에 종료하고 현재까지의 기록한 개수를 반환
- 종료되지 않았다면 블록을 정렬한다. 정렬할떄는 왼쪽 아래에서 부터 순회하면서 “-1”이면 자신과 가장 가까운 위쪽 블록과 자리를 바꾼다
- 주의점 : 블록은 항상 위에서 아래로 내려온다는 것이다 단순히 입력된 순서로 배열을 만들었을 경우 (0, 0) 은 좌상단의 블록을 가리키게 된다. 그러면 블록을 정렬할때 헷갈리는 경우가 있어 내 경우엔 최초의 입력을 reversed 시켜 board를 만들었다.
💻 코드
func solution(_ m:Int, _ n:Int, _ board:[String]) -> Int {
var b: [[String]] = board.reversed().map { $0.map { String($0) } }
var checkPos: [(Int,Int)] = [] // 지워질 블록의 위치
var result: Int = 0
while true {
// 지워하는 블록을 찾음
for y in 0..<m-1 {
for x in 0..<n-1 {
if b[y][x] == "-1" { continue }
else if b[y][x] == b[y][x+1] && b[y][x] == b[y+1][x] && b[y][x] == b[y+1][x+1] {
checkPos.append((y,x))
}
}
}
if checkPos.isEmpty { break }
// 블록들을 지움
while !checkPos.isEmpty {
let pos = checkPos.removeLast()
for y in 0...1 {
for x in 0...1 {
if b[pos.0+y][pos.1+x] != "-1" {
result += 1
b[pos.0+y][pos.1+x] = "-1"
}
}
}
}
// 전체 블록들을 재정렬
for y in 0..<m {
for x in 0..<n {
if b[y][x] == "-1" {
for yi in y..<m {
if b[yi][x] != "-1" {
b[y][x] = b[yi][x]
b[yi][x] = "-1"
break
}
}
}
}
}
}
return result
}
❌ 틀린 이유 및 틀린 부분
- 마지막 재정렬 부분에서 블록의 위치를 바꾼뒤 break를 걸어야하는데 까먹고 안해줬다…. (코드 아이디어를 짤때는 생각을 해놓은 부분이었는데!)
⏳ 시간 복잡도
- 반복문이 3중으로 되어있지만 대부분이 전체 순회를 하는 구조여서 O(n2)으로 생각된다.
📌 풀이 또는 기억할 정보
- 다른 사람의 경우 보드를 하나더 만들어서 지우고 보드를 정렬한뒤 보드를 바꾸는 식으로 푼사람도 있다.
- 이 문제의 경우엔 반복을 돌리는 행위가 큰 영향을 끼치지 않는것 같다. 다만 구조를 생각해야하는 것과 코드가 난잡해지기 때문에 몇몇 사람은 함수로 내용을 분리시켜 구성했다.