Problem Solving

[Swift] 프로그래머스 [1차] 뉴스 클러스터링(lv. 2)

DuncanKim 2023. 3. 28. 09:40
728x90

[Swift] 프로그래머스 [1차] 뉴스 클러스터링(lv. 2)

 

1. 문제

https://school.programmers.co.kr/learn/courses/30/lessons/17677

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

2. 접근

 

 

'숫자나 공백 기타 특수문자'를 제외한 문자열의 유사도를 체크하는 로직이 필요하다는 점을 주목했다. 또한 대소문자를 구분하지 않고 유사도를 체크하라는 부분이 있는데, 그 부분을 주목하였다.

 

주어진 str1, str2를 배열화하고, lowercased()를 사용하여 일괄적으로 소문자로 만들어주었다. 그런 다음 한 글자가 Character가 되지 않고 String이 되도록 타입을 정해주었다. 이는 두 글자씩 끊어서 만드는 부분집합을 만들기 위함이다.

 

lowercased()는 문자에만 적용이 된다. 그렇기 때문에 str1, str2에서 문자인 것만 골라내기 위해 6번 라인에 반복문이 들어간다. string1, string2 두 번에 걸쳐서 적용이 되었기 때문에 두 번 반복하는 코드가 나왔는데, 이 부분은 조금 아쉬운 것 같다. 다른 식으로 변형할 수도 있을 것 같은데 생각은 잘 나지 않는다.

 

wholeCount는 전체 원소의 개수를 세주는 것이다. 합집합의 개수를 세기 위해서 필요한데, 집합에서 n(A) + n(B) - n(A n B) = n(A U B) 이기 때문에 n(A) + n(B)를 얻어내기 위한 것이라고 보면 된다.

 

wholeCount 밑의 반복문은 합집합과 교집합의 개수를 구하기 위한 로직이다.

교집합에 해당하는 것을 체크하기 위해 similar1, 2에 있는 것 중 겹치는 것은 "" 으로 표현하였다. 나중에 ""의 개수를 세면 교집합이 되는 것이고, wholeCount에서 교집합의 수를 제하면 합집합의 수가 된다.

 

합집합의 수를 체크하고, 교집합을 나누면 정답이 도출된다.

Swift는 타입 체크를 잘해야 하기 때문에, Double로 만들어 나눠준 다음에 Int로 변환해주는 것은 필수이다....

 

 

3. 코드

func solution(_ str1:String, _ str2:String) -> Int {
    var string1 = Array(str1.lowercased()).compactMap({ String($0) })
    var string2 = Array(str2.lowercased()).compactMap({ String($0) })
    var similar1 = [String]()
    var similar2 = [String]()
    for (index, i) in string1.enumerated() {
        if index == string1.count - 1 {
            similar1.sort()
            break
        }
        if (i + string1[index + 1]).filter({ $0.isLetter }).count == 2 {
            similar1.append(i + string1[index + 1])
        }
    }
    for (index, i) in string2.enumerated() {
        if index == string2.count - 1 {
            similar2.sort()
            break
        }
        if (i + string2[index + 1]).filter({ $0.isLetter }).count == 2 {
            similar2.append(i + string2[index + 1])
        }
    }
    let wholeCount = similar1.count + similar2.count
    for (index, i) in similar1.enumerated() {
        if similar2.contains(i) {
            similar1[index] = ""
            similar2[similar2.firstIndex(of: i)!] = ""
        }
    }
    let interCount = (similar1.filter({ $0 == "" }).count + similar2.filter({ $0 == "" }).count) / 2
    let unionCount = wholeCount - interCount
    
    return unionCount != 0 ? Int(Double(interCount) / Double(unionCount) * Double(65536)) : 65536
}
728x90