Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

68-9kyo-hwang #230

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

68-9kyo-hwang #230

wants to merge 5 commits into from

Conversation

9kyo-hwang
Copy link
Collaborator

πŸ”— 문제 링크

2024 KAKAO WINTER INTERNSHIP n + 1 μΉ΄λ“œκ²Œμž„

1 ~ n 사이 μˆ˜κ°€ 적인 μΉ΄λ“œκ°€ ν•˜λ‚˜μ”© μžˆλŠ” μΉ΄λ“œ λ­‰μΉ˜μ™€ 동전 coin개λ₯Ό 가지고 μžˆλ‹€. λ‹€μŒκ³Ό 같은 μˆœμ„œλ‘œ κ²Œμž„μ„ μ§„ν–‰ν•œλ‹€.

  1. μ²˜μŒμ— μΉ΄λ“œ λ­‰μΉ˜μ—μ„œ n/3μž₯을 뽑아 λͺ¨λ‘ 가진닀. n은 6의 λ°°μˆ˜μ΄λ‹€.
  2. 1λΌμš΄λ“œλΆ€ν„° μ§„ν–‰ν•˜λ©°, 각 λΌμš΄λ“œκ°€ μ‹œμž‘ν•  λ•Œλ§ˆλ‹€ μΉ΄λ“œ 2μž₯을 λ½‘λŠ”λ‹€. μΉ΄λ“œ λ­‰μΉ˜μ— 남은 μΉ΄λ“œκ°€ μ—†λ‹€λ©΄ κ²Œμž„μ€ μ’…λ£Œλœλ‹€. 뽑은 μΉ΄λ“œ ν•œ μž₯ λ‹Ή 동전을 ν•˜λ‚˜ μ†Œλͺ¨ν•΄ κ°€μ§€κ±°λ‚˜, 동전을 μ†Œλͺ¨ν•˜μ§€ μ•Šκ³  버릴 수 μžˆλ‹€.
  3. μΉ΄λ“œμ— 적힌 수의 합이 n+1이 λ˜λ„λ‘ μΉ΄λ“œ 2μž₯을 λ‚΄κ³  λ‹€μŒ λΌμš΄λ“œλ₯Ό 진행할 수 μžˆλ‹€. λ§Œμ•½ μΉ΄λ“œ 2μž₯을 λ‚Ό 수 μ—†λ‹€λ©΄ κ²Œμž„μ€ μ’…λ£Œλœλ‹€.
μ˜ˆμ‹œ μ„€λͺ…

예λ₯Ό λ“€μ–΄ n = 12, coin = 4이고 [3, 6, 7, 2, 1, 10, 5, 9, 8, 12, 11, 4] μˆœμ„œλŒ€λ‘œ μΉ΄λ“œλ₯Ό 뽑도둝 μΉ΄λ“œ λ­‰μΉ˜κ°€ 주어진닀.
μ²˜μŒμ— 3, 6, 7, 2 μΉ΄λ“œ 4μž₯(= n/3)κ³Ό 동전 4개(= coin)λ₯Ό 가지고 μ‹œμž‘ν•œλ‹€. λ‹€μŒ λΌμš΄λ“œλ‘œ μ§„ν–‰ν•˜κΈ° μœ„ν•΄ λ‚΄μ•Ό ν•  μΉ΄λ“œ 두 μž₯에 적힌 수의 합은 13(= n+1)이닀. λ‹€μŒκ³Ό 같은 λ°©λ²•μœΌλ‘œ μ΅œλŒ€ 5λΌμš΄λ“œκΉŒμ§€ 도달할 수 μžˆλ‹€.

  1. 1λΌμš΄λ“œμ—μ„œ 뽑은 μΉ΄λ“œ 1, 10을 동전 두 개λ₯Ό μ†Œλͺ¨ν•΄μ„œ λͺ¨λ‘ 가진닀. μΉ΄λ“œ 3, 10을 λ‚΄κ³  λ‹€μŒ λΌμš΄λ“œλ‘œ μ§„ν–‰ν•œλ‹€. μ΄λ•Œ 손에 남은 μΉ΄λ“œλŠ” 1, 2, 6, 7이고 동전이 2개 λ‚¨λŠ”λ‹€.
  2. 2λΌμš΄λ“œμ—μ„œ 뽑은 μΉ΄λ“œ 5, 9λ₯Ό 동전을 μ†Œλͺ¨ν•˜μ§€ μ•Šκ³  λͺ¨λ‘ 버린닀. μΉ΄λ“œ 6, 7을 λ‚΄κ³  λ‹€μŒ λΌμš΄λ“œλ‘œ μ§„ν–‰ν•œλ‹€. μ΄λ•Œ 손에 남은 μΉ΄λ“œλŠ” 1, 2κ³  동전이 2개 λ‚¨λŠ”λ‹€.
  3. 3λΌμš΄λ“œμ—μ„œ 뽑은 μΉ΄λ“œ 8, 12 쀑 동전 ν•œ 개λ₯Ό μ†Œλͺ¨ν•΄μ„œ μΉ΄λ“œ 12λ₯Ό 가진닀. μΉ΄λ“œ 1, 12을 λ‚΄κ³  λ‹€μŒ λΌμš΄λ“œλ‘œ μ§„ν–‰ν•œλ‹€. μ΄λ•Œ 손에 남은 μΉ΄λ“œλŠ” 2이고 동전이 1개 λ‚¨λŠ”λ‹€.
  4. 4λΌμš΄λ“œμ—μ„œ 뽑은 μΉ΄λ“œ 11, 4 쀑 동전 ν•œ 개λ₯Ό μ†Œλͺ¨ν•΄μ„œ μΉ΄λ“œ 11을 가진닀. μΉ΄λ“œ 2, 11을 λ‚΄κ³  λ‹€μŒ λΌμš΄λ“œλ‘œ μ§„ν–‰ν•œλ‹€. μ΄λ•Œ 손에 남은 μΉ΄λ“œμ™€ 동전은 μ—†λ‹€.
  5. 5λΌμš΄λ“œμ—μ„œ μΉ΄λ“œ λ­‰μΉ˜μ— 남은 μΉ΄λ“œκ°€ μ—†μœΌλ―€λ‘œ κ²Œμž„μ„ μ’…λ£Œν•œλ‹€.

μ²˜μŒμ— 가진 λ™μ „μˆ˜λ₯Ό λ‚˜νƒ€λ‚΄λŠ” μ •μˆ˜ coinκ³Ό μΉ΄λ“œλ₯Ό λ½‘λŠ” μˆœμ„œλŒ€λ‘œ μΉ΄λ“œμ— 적힌 수λ₯Ό 담은 1차원 μ •μˆ˜ λ°°μ—΄ cardsκ°€ λ§€κ°œλ³€μˆ˜λ‘œ μ£Όμ–΄μ§ˆ λ•Œ, κ²Œμž„μ—μ„œ 도달 κ°€λŠ₯ν•œ μ΅œλŒ€ λΌμš΄λ“œμ˜ 수λ₯Ό return ν•˜λ„λ‘ solution ν•¨μˆ˜λ₯Ό μ™„μ„±ν•˜λΌ.

βœ”οΈ μ†Œμš”λœ μ‹œκ°„

1μ‹œκ°„ 반?

✨ μˆ˜λ„ μ½”λ“œ

λ””νŽœμŠ€ κ²Œμž„μ„ μ΅œκ·Όμ— ν’€μ–΄μ„œ κ·ΈλŸ°κ°€, 이 문제의 접근법이 μƒκ°λ³΄λ‹€λŠ” 금방 λ– μ˜¬λžλ‹€. 이 λ¬Έμ œλ„ λ§ˆμ°¬κ°€μ§€λ‘œ, μΉ΄λ“œλ₯Ό 뽑은 κ²ƒκ³ΌλŠ” λ¬΄κ΄€ν•˜κ²Œ "μΉ΄λ“œ μ‚¬μš© μ‹œμ μ„ λ’€λ‘œ λ―Έλ£° 수 μžˆλ‹€"λŠ” 것을 μΊμΉ˜ν•΄μ•Ό ν•œλ‹€.
λ˜ν•œ μΉ΄λ“œ μ‚¬μš© μ‹œμ μ„ λ’€λ‘œ λ―Έλ£¬λ‹€λŠ” 것은 μ–΄λ”˜κ°€μ— μΉ΄λ“œκ°€ μ €μž₯λ˜μ–΄ μžˆλ‹€λŠ” 것인데, κ±°κΈ°μ„œ n+1 숫자λ₯Ό λ§Œλ“€ 수 μžˆλŠ” 2μž₯을 λΉ λ₯΄κ²Œ μ°Ύμ•„λ‚΄μ•Ό ν•˜λ―€λ‘œ Set 자료ꡬ쑰λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 점도 ν¬μΈνŠΈλ‹€.

λ‚˜μ˜ 경우 Set에 <card 숫자, κ΅ν™˜μ— ν•„μš”ν•œ coin 개수> 쌍으둜 μ§‘μ–΄λ„£λŠ” μ‹μœΌλ‘œ coin μ†Œλͺ¨ 개수λ₯Ό 확인할 수 있게 ν–ˆλ‹€.

const int N = (int)InCards.size();
const int RequiredSum = N + 1;
reverse(InCards.begin(), InCards.end());

μ „μ²˜λ¦¬ 과정이닀. μ΄λ•Œ μ£Όμ–΄μ§€λŠ” cards 배열을 λ’€μ§‘λŠ” μ΄μœ λŠ” μΉ΄λ“œλ₯Ό 2μž₯μ”© 뽑을 λ•Œ stack처럼 pop_back()을 ν˜ΈμΆœν•΄μ„œ 효율적으둜 뽑을 수 μžˆλ„λ‘ ν•˜κΈ° μœ„ν•¨μ΄λ‹€.

struct Comparator
{
    bool operator()(const pair<int, int>& Lhs, const pair<int, int>& Rhs) const
    {
        const auto& [LhsCard, LhsCoin] = Lhs;
        const auto& [RhsCard, RhsCoin] = Rhs;
        
        return LhsCoin == RhsCoin ? LhsCard < RhsCard : LhsCoin < RhsCoin;
    }
};

set<pair<int, int>, Comparator> Deck;
for(int i = 0; i < N / 3; ++i)
{
    Deck.emplace(InCards.back(), 0); InCards.pop_back();
}

μΉ΄λ“œλ₯Ό μ†Œμ§€ν•  Set이닀. μ²˜μŒμ— n / 3 μž₯을 κ°–κ³  μ‹œμž‘ν•˜λ―€λ‘œ, μ—¬κΈ°μ„œλŠ” 동전 μ†Œλͺ¨ 개수λ₯Ό 0으둜 μ„€μ •ν•΄μ„œ Set에 μ‚½μž…ν•œλ‹€. ComparatorλŠ” λ’€μ—μ„œ μ„€λͺ…ν•˜κ² λ‹€.

int Round;
for(Round = 1; !InCards.empty(); ++Round)
{
    Deck.emplace(InCards.back(), 1); InCards.pop_back();
    Deck.emplace(InCards.back(), 1); InCards.pop_back();
    
    ...
}

이제 λΌμš΄λ“œλ₯Ό μ‹œμž‘ν•œλ‹€. 더 이상 주어진 μΉ΄λ“œκ°€ 없을 λ•ŒκΉŒμ§€ λΌμš΄λ“œλ₯Ό λ°˜λ³΅ν•˜λ©°, 2μž₯μ”© μΉ΄λ“œλ₯Ό 뽑아 Set에 μ‚½μž…ν•œλ‹€. μ΄μ œλΆ€ν„° 뽑은 μΉ΄λ“œλ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„  λ°˜λ“œμ‹œ 동전을 μ†Œλͺ¨ν•΄μ•Ό ν•˜λ―€λ‘œ 동전 μ†Œλͺ¨ 개수λ₯Ό 1둜 μ„ΈνŒ…ν•΄μ„œ μ‚½μž…ν•œλ‹€.

bool FindCombination = false;
for(const auto& [Card, Coin] : Deck)
{
    ...
}

이제 λ³΄μœ ν•œ 덱을 μˆœνšŒν•˜λ©° n+1을 λ§Œλ“€ 수 μžˆλŠ” μΉ΄λ“œ 쑰합이 μžˆλŠ” 지 ν™•μΈν•œλ‹€.

  • λ§Œμ•½ κ·Έ 쑰합이 λ°œκ²¬λλ‹€λ©΄ FindCombination = true둜 μ„€μ •λ˜λ©° 덱 순회λ₯Ό μ€‘λ‹¨ν•œλ‹€.
for(const auto& [Card, Coin] : Deck)
{
    int TargetCard = RequiredSum - Card;
    if(Card == TargetCard)
    {
        continue;
    }
    
    int TargetCoin;
    if(Deck.count({TargetCard, 0}))
    {
        TargetCoin = 0;
    }
    else if(Deck.count({TargetCard, 1}))
    {
        TargetCoin = 1;
    }
    else
    {
        continue;
    }
    
    if(Coin + TargetCoin <= InCoin)
    {
        InCoin -= (Coin + TargetCoin);
        Deck.erase({Card, Coin});
        Deck.erase({TargetCard, TargetCoin});
        FindCombination = true;
        break;
    }
}

덱에 μ‘΄μž¬ν•˜λŠ” λͺ¨λ“  μΉ΄λ“œλ₯Ό μˆœνšŒν•˜λ©° n+1, 즉 RequiredSum을 λ§Œλ“€ 수 μžˆλŠ” TargetCardλ₯Ό μ°ΎλŠ”λ‹€.

  • 계산 상 Card와 TargetCardκ°€ λ™μΌν•œ μˆ«μžκ°€ λ‚˜μ˜¬ μˆ˜λ„ μžˆλŠ”λ°, λ¬Έμ œμ—μ„œ 주어진 μΉ΄λ“œλŠ” λͺ¨λ‘ μˆ«μžκ°€ λ‹€λ₯΄λ‹€.
  • λ”°λΌμ„œ 이 경우 더 이상 μ§„ν–‰ν•˜μ§€ μ•Šλ„λ‘ continueλ₯Ό κ±Έμ–΄μ€€λ‹€.

μ˜¬λ°”λ₯Έ TargetCardκ°€ κ³„μ‚°λ˜μ—ˆλ‹€λ©΄ ν˜„μž¬ Deck에 이 μΉ΄λ“œκ°€ μ‘΄μž¬ν•˜λŠ” 지 κ²€μ‚¬ν•œλ‹€.

  • 이 μΉ΄λ“œκ°€ κ²Œμž„ μ‹œμž‘ 전에 뽑은 μΉ΄λ“œμΌ μˆ˜λ„ 있고, λΌμš΄λ“œ 진행 쀑에 뽑은 μΉ΄λ“œμΌ μˆ˜λ„ μžˆλ‹€.
  • 이λ₯Ό κ²€μ‚¬ν•΄μ„œ TargetCoin을 μ‚°μ •ν•œλ‹€.
  • λ§Œμ•½ μΉ΄λ“œ μžμ²΄κ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ 더 이상 μ§„ν–‰ν•˜μ§€ μ•Šλ„λ‘ continueλ₯Ό κ±Έμ–΄μ€€λ‹€.

덱에 μΉ΄λ“œκ°€ μ‘΄μž¬ν•˜λŠ” 것이 확인됐닀면, λ§ˆμ§€λ§‰μœΌλ‘œ 이 쑰합을 μ“Έ 수 μžˆλŠ” 지 ν™•μΈν•œλ‹€.

  • μ΄λŠ” ν˜„μž¬ λ³΄μœ ν•œ λ™μ „μœΌλ‘œ μΉ΄λ“œ 2μž₯을 μ‚¬μš©ν•  수 μžˆλŠ” 지λ₯Ό ν™•μΈν•˜λŠ” 과정이닀.
  • λ§Œμ•½ 동전을 1개 λ³΄μœ ν–ˆλŠ”λ°, μΉ΄λ“œ 2μž₯ λͺ¨λ‘ 동전을 λ‚΄μ•Ό ν•œλ‹€λ©΄ μ‚¬μš©ν•  수 μ—†λŠ” 것이닀.
  • λ§Œμ•½ μΉ΄λ“œ 2μž₯을 μ‚¬μš©ν•  수 μžˆλ‹€λ©΄ 보유 동전 개수λ₯Ό μ°¨κ°ν•˜κ³ , λ±μ—μ„œ μΉ΄λ“œ 2μž₯을 μ§€μš°λ©° FindCombination = true둜 μ„€μ •ν•œλ‹€.

μ—¬κΈ°μ„œ Set에 ComparatorλΌλŠ” λ³„λ„μ˜ 비ꡐ 기쀀이 ν•„μš”ν•œλ°,

  • n+1을 λ§Œλ“œλŠ” μΉ΄λ“œ 쑰합이 λ°˜λ“œμ‹œ 1κ°€μ§€λΌλŠ” 보μž₯은 μ—†λ‹€. 동전을 0개 μ†Œλͺ¨ν•˜λŠ” μ‘°ν•©, 1개 μ†Œλͺ¨ν•˜λŠ” μ‘°ν•©, 2개 μ†Œλͺ¨ν•˜λŠ” 쑰합이 μžˆμ„ 수 μžˆλ‹€.
  • μš°λ¦¬λŠ” μ΅œλŒ€ν•œ λΌμš΄λ“œλ₯Ό 였래 이어가야 ν•˜λ―€λ‘œ 동전을 μ΅œλŒ€ν•œ 였래 λ³΄μœ ν•΄μ•Ό ν•œλ‹€. 그런데 μ†Œλͺ¨ 동전 κ°œμˆ˜κ°€ λ§Žμ€ μΉ΄λ“œλ₯Ό μš°μ„ μ μœΌλ‘œ 확인해 쑰합이 λ§Œλ“€μ–΄μ§ˆ μˆ˜κ°€ μžˆλ‹€.
  • μ΄λŸ¬ν•œ 경우λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ Set에 넣을 λ•Œ μ†Œλͺ¨ 동전 κ°œμˆ˜κ°€ 적은 μΉ΄λ“œλ₯Ό λ¨Όμ € 확인할 수 μžˆλ„λ‘ λ³„λ„μ˜ μ •λ ¬ 기쀀을 λ„£μ–΄μ€€ 것이닀.
if(false == FindCombination)
{
    break;
}

λ°˜λ³΅λ¬Έμ„ λΉ μ Έλ‚˜μ™”λŠ”λ°λ„ FindCombination == false인 경우, n+1을 λ§Œλ“œλŠ” μΉ΄λ“œ 2μž₯이 덱에 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” λœ»μ΄λ―€λ‘œ λΌμš΄λ“œ 진행을 μ€‘λ‹¨ν•œλ‹€.

return Round;

전체 반볡문이 μ’…λ£Œλ˜λ©΄ μ΄μ œκΉŒμ§€ μ§„ν–‰ν•œ λΌμš΄λ“œ μˆ˜κ°€ κΈ°λ‘λΌμžˆμœΌλ―€λ‘œ 이λ₯Ό λ°˜ν™˜ν•œλ‹€.

전체 μ½”λ“œ

#include <string>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;

struct Comparator
{
    bool operator()(const pair<int, int>& Lhs, const pair<int, int>& Rhs) const
    {
        const auto& [LhsCard, LhsCoin] = Lhs;
        const auto& [RhsCard, RhsCoin] = Rhs;
        
        return LhsCoin == RhsCoin ? LhsCard < RhsCard : LhsCoin < RhsCoin;
    }
};

int solution(int InCoin, vector<int> InCards) 
{
    const int N = (int)InCards.size();
    const int RequiredSum = N + 1;
    reverse(InCards.begin(), InCards.end());
    
    set<pair<int, int>, Comparator> Deck;
    for(int i = 0; i < N / 3; ++i)
    {
        Deck.emplace(InCards.back(), 0); InCards.pop_back();
    }
    
    int Round;
    for(Round = 1; !InCards.empty(); ++Round)
    {
        Deck.emplace(InCards.back(), 1); InCards.pop_back();
        Deck.emplace(InCards.back(), 1); InCards.pop_back();
        
        bool FindCombination = false;
        for(const auto& [Card, Coin] : Deck)
        {
            int TargetCard = RequiredSum - Card;
            if(Card == TargetCard)
            {
                continue;
            }
            
            int TargetCoin;
            if(Deck.count({TargetCard, 0}))
            {
                TargetCoin = 0;
            }
            else if(Deck.count({TargetCard, 1}))
            {
                TargetCoin = 1;
            }
            else
            {
                continue;
            }
            
            if(Coin + TargetCoin <= InCoin)
            {
                InCoin -= (Coin + TargetCoin);
                Deck.erase({Card, Coin});
                Deck.erase({TargetCard, TargetCoin});
                FindCombination = true;
                break;
            }
        }

        if(false == FindCombination)
        {
            break;
        }
    }
    
    return Round;
}

πŸ“š μƒˆλ‘­κ²Œ μ•Œκ²Œλœ λ‚΄μš©

사싀 λ‚˜λŠ” μ€‘λ³΅λœ μ½”λ“œλ₯Ό μ•ˆμ“Έλ €κ³  Set에 Comparator μ •μ˜ν•˜κ³  μ’€ λ³΅μž‘ν•˜κ²Œ ν’€μ΄ν–ˆλŠ”λ°, λ‹€λ₯Έ λΆ„λ“€ 풀이λ₯Ό 보면 κ·Έλƒ₯ μ΄ˆκΈ°μ— 뽑은 μΉ΄λ“œ λͺ©λ‘ Setκ³Ό λΌμš΄λ“œ 진행 쀑에 뽑은 μΉ΄λ“œ Set 2개λ₯Ό μ‚¬μš©ν•œλ‹€. 이게 μ’€ 더 직관적일 μˆ˜λ„...?

μ§€λ‚œ μ£Όμ—λŠ” λ°”λΉ΄μ–΄μ„œ PR을 λͺ»μΌμŠ΅λ‹ˆλ‹€ μ£„μ†‘ν•©λ‹ˆλ‹€ 😒
image

Copy link
Collaborator

@mjj111 mjj111 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μ–΄μ œ λ•Œλ§ˆμΉ¨ λ”°λˆλ”°λˆ ν•˜κ²Œ ν’€μ—ˆμ—ˆμŠ΅λ‹ˆλ‹€ γ…Ž
κ°œμΈμ μœΌλ‘œλŠ” μ €μ²˜λŸΌ Set 2개 μ‚¬μš©ν•˜λŠ” 것보닀 κ΅ν™©λ‹˜ 풀이가 더 직관적인거 κ°™μ•„μš”πŸ€”

import java.util.*;

class Solution {    
    public int solution(int coin, int[] cards) {
        int N = cards.length;
        Set<Integer> original = new HashSet();
        Set<Integer> additional = new HashSet();
        
        int index = N / 3;
        for(int i = 0 ; i < index; ++i) {
            original.add(cards[i]);
        }
        
        int target = N + 1;   
        int round = 0;
        while(true){
            round++;
            
            if(index >= N){
                break;
            }
            
            additional.add(cards[index]);
            additional.add(cards[index+1]);
            index += 2;
            
            boolean flag = false;
            for(int i : original){
                if(original.contains(target - i)){
                    original.remove(i);
                    original.remove(target - i);
                    flag = true;
                    break;
                }
            }
            
            if(!flag && coin > 0){
                for(int i : original){
                    if(!additional.contains(target - i)) continue;
                    original.remove(i);
                    additional.remove(target - i);
                    --coin;
                    flag = true;
                    break;
                }
            }
            
            if(!flag && coin > 1){
                for(int i : additional){
                    if(!additional.contains(target - i)) continue;
                    additional.remove(i);
                    additional.remove(target - i);
                    coin -= 2;
                    flag = true;
                    break;
                }
            }
            
            if(!flag) break;
        }
        return round;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants