[Swift] [16일차] 할인 행사

·2024년 12월 23일
0

SwiftAlgorithm

목록 보기
19/105
post-thumbnail

Programmers-할인행사

처음에는 문제 자체가 이해가 안됐다. 최적의 날짜가 아니라, 되는 날짜를 다 구하는 것이라서 너무 범위가 큰데 이걸 다 ? 이런 느낌이었는데, 완전탐색 느낌으로 한번 해봐야겠다 싶었다.

일단 할인 날짜가 10일이니까, 이걸 최대 10만길이를 어떻게 판단해줄까? 싶어서 이걸 좀 고민하다가 딕셔너리로해서 첫번째 원소를 그다음 원소로 교체해주면서 슬라이딩윈도우 느낌으로 해주면 되지 않을까? 해서 그쪽으로 가닥을 잡고 코드를 짰다.

풀이과정

1. 이거 want랑 number를 일단 띠로 있는걸 DICT로 매칭을 시켜줬다.

var answer_dict = [String: Int]()

    for i in 0 ..< want.count {
        answer_dict[want[i], default: 0] = number[i]
    }

2. 첫번째 배열 인덱스 9까지 짜른걸 첫 값으로 들고 있게 할 것이다.

var window = discount[0 ..< 10]

3. 10개 담은 window를 dict형태로 변환

var dict = [String: Int]()
    for item in window {
        dict[item, default: 0] += 1
    }

4. 슬라이딩 윈도우 로직 !

first를 뽑아주고, 다음날자에 해당하는 친구들 window에 넣으면서 슬라이딩 윈도우를 업데이트 시켜줄 것이다.

Q : 그러면 굳이 window가 필요없지 않나? 어처피 dict를 가지고 놀건데?

A: 라고 생각을 하긴 했는데, 첫번째 값을 인덱스로 찾는게 아닌지라 쉽게 찾고 지우고 할 수 있게 window를 보조로 계속 데리고 있었다. 아마 타인의 코드를 볼 때 더 좋은 코드가 있으면 그것으로 바로잡기를 해보면 될 것 같다.

for i in 10 ..< discount.count {
        let first = window.removeFirst()
        dict[first]! -= 1
        window.append(discount[i])
        dict[discount[i], default: 0] += 1

        if isCorrect() {
            answer += 1
        }
    }

5. iscorrect() 함수를 통해서 카운팅해주기

이제 마지막으로 isCorrect()라는 함수를 통해서 현재 윈도우에 내가 사고싶은게 다 담겨있는지만 판단해주면 된다.
딕셔너리를 내가 원하는것, 할인 윈도우의 딕셔너리 를 관리하다보니 변수명땜에 좀 헷갈렸던 것 같다.

func isCorrect() -> Bool {
        for fruit in answer_dict {
            if let dictValue = dict[fruit.key], dictValue < fruit.value {
                return false
            }
        }
        return true
    }

1차 완성코드

import Foundation

func solution(_ want: [String], _ number: [Int], _ discount: [String]) -> Int {
    var answer = 0
    
    var window = discount[0 ..< 10]

    var answer_dict = [String: Int]()

    for i in 0 ..< want.count {
        answer_dict[want[i], default: 0] = number[i]
    }
    var dict = [String: Int]()
    for item in window {
        dict[item, default: 0] += 1
    }
//    반복문에서 카운팅해주기
    func isCorrect() -> Bool {
        for fruit in answer_dict {
            if let dictValue = dict[fruit.key], dictValue < fruit.value {
                return false
            }
        }
        return true
    }
    for i in 10 ..< discount.count {
        let first = window.removeFirst()
        dict[first]! -= 1
        window.append(discount[i])
        dict[discount[i], default: 0] += 1
//        여기서 이제 다 들어있는지를 판단 !
        if isCorrect() {
            answer += 1
        }
    }
    return answer
}

이렇게 하니까 한개가 틀리게 나오더라...

원인을 찾아보니까 예를 들어서 14일까지 있을 때
인덱스 기준으로 0~9, 1~10 , 2~11, 3~12,4~13
이렇게 담겨야하는데, 내가 로직이

for i in 10 ..< discount.count {
        let first = window.removeFirst()
        dict[first]! -= 1
        window.append(discount[i])
        dict[discount[i], default: 0] += 1

        if isCorrect() {
            answer += 1
        }
    }

이렇게 되어있으니까 처음 담긴 0~9에 대해서는 판단이 안되는 것을 확인했다! 그래서 이걸 수정했다. 그냥 위에다가

if isCorrect() {
        answer += 1
    }

반복문 시작하기전에 한번 isCorrect()를 돌려줬다 !

결과는..

이번엔 11번은 맞았는데 다른데에서 3~4개 정도 틀렸다.

그니까 이게 첫번째꺼로 판단을 안해주고 있었는데 대부분의 케이스들이 그런 경우가 없어서 11번 빼고 맞았다고 판단해준 것 같다. 그러니까 로직 자체가 좀 잘못되어있는 것 같아서 이걸

want : ["apple"] ,
number : [10] , 
discount ["banana","banana","banana","banana","banana",
"banana","banana","banana","banana","banana"] 

이렇게 인자를 넣어서 돌려봤는데,

func isCorrect() -> Bool {
        for fruit in answer_dict {
            if let dictValue = dict[fruit.key], dictValue < fruit.value {
                return false
            }
        }
        return true
    }

이게 true가 나오더라 ...

dictValue에 안들어있으니까 false뜨는게 아니라, 아예 안거치니까 그냥 통과해서 return true하고 있더라.. 그래서 이 부분을 더 확실하게 수정해줬다.

func isCorrect() -> Bool {
        for fruit in answer_dict {
            if let dictValue = dict[fruit.key] {
                if dictValue < fruit.value {
                    return false
                }
            } else {
                return false
            }
        }
        return true
    }

fruit.value가 적으면 당연히 false고, 이제 그게 아닌 없는 경우에도 return false


채점 결과

정확성: 100.0
합계: 100.0 / 100.0

완성 코드

import Foundation

func solution(_ want: [String], _ number: [Int], _ discount: [String]) -> Int {
    var answer = 0
    var window = discount[0 ..< 10]

    var answer_dict = [String: Int]()

    for i in 0 ..< want.count {
        answer_dict[want[i], default: 0] = number[i]
    }
    var dict = [String: Int]()
    for item in window {
        dict[item, default: 0] += 1
    }
//    반복문에서 카운팅해주기
    func isCorrect() -> Bool {
        for fruit in answer_dict {
            if let dictValue = dict[fruit.key] {
                if dictValue < fruit.value {
                    return false
                }
            } else {
                return false
            }
        }
        return true
    }
    if isCorrect() {
        answer += 1
    }
    for i in 10 ..< discount.count {
        let first = window.removeFirst()
        dict[first]! -= 1
        window.append(discount[i])
        dict[discount[i], default: 0] += 1

        if isCorrect() {
            answer += 1
        }
    }

    return answer
}

타인의 코드

import Foundation

func solution(_ want:[String], _ number:[Int], _ discount:[String]) -> Int {
    var answer = 0

    for i in 0..<(discount.count - 9) {
        var temp = Array(repeating: 0, count: want.count)
        for j in i..<(i + 10) {
            if let idx = want.firstIndex(of: discount[j]) {
                temp[idx] += 1
            }
        }
        if number == temp {
            answer += 1
        }
    }

    return answer
}

이중for문 이긴한데, 내부 반복문은 10번만 돌아가니까 문제는 없고,
want.firstIndex(of: discount[j]) 이 부분이 좋게 느껴졌다. want의 원소를 discount에서 찾을 생각은 했는데 그 반대를 사용할 지 몰랐다. 그래서 결국 number배열이랑 똑같게 만들어주면 카운팅해주는거로 깔끔하게 짠 것 같았다.

profile
기억보단 기록을

0개의 댓글