Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions contains-duplicate/ys-han00.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <bits/stdc++.h>

class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
sort(nums.begin(), nums.end());

for(int i = 0; i < nums.size() - 1; i++)
if(nums[i] == nums[i+1])
return true;

return false;
Comment on lines +6 to +12
Copy link

Choose a reason for hiding this comment

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

아래와 같은 로직으로 이해했는데 제가 잘 이해한것이 맞을까요?

  1. 배열 nums 를 정렬한 다음
  2. 배열의 크기만큼 반복문을 돌면서
  3. 배열의 다음 요소와 같은 값이 있는지를 판단한다

로직이 명확하고 직관적이네요 👍

💡 참고: 다른 접근 방법

주석으로 남겨주신 첫 시도를 보니 이미 해싱 아이디어를 생각하셨던 것 같아요.

다만 배열 대신 unordered_set을 활용하면 시간과 메모리 문제를 해결할 수 있을 것 같아요!

unordered_set 을 이용하면 실제 등장한 숫자만 저장하기 때문에 메모리 효율적으로 동작할 수 있을 것 같아요.

Copy link
Author

Choose a reason for hiding this comment

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

아래와 같은 로직으로 이해했는데 제가 잘 이해한것이 맞을까요? 1. 배열 nums 를 정렬한 다음 2. 배열의 크기만큼 반복문을 돌면서 3. 배열의 다음 요소와 같은 값이 있는지를 판단한다 ...

네 맞게 이해하셨습니다! 간단하면서도 시간효율이 제일 좋아서 채택한 풀이입니다.

...unordered_set 을 이용하면 실제 등장한 숫자만 저장하기 때문에 메모리 효율적으로 동작할 수 있을 것 같아요.

코드에는 포함되지 않았지만, 말씀하신 unordered_set 을 사용해서도 풀어봤습니다. 예상하신대로 문제 없이 동작합니다! 하지만, 시간, 메모리 효율이 제출한 코드 보다 좋지 않아 코드에 포함하지 않았습니다 ㅎㅎ

Copy link

Choose a reason for hiding this comment

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

이미 unordered_set 을 이용해서 풀어보셨군요! 👍

sort 방식은 O(n logn) 방식이고

unordered_set 방식이 O(n)이라서 더 빠를 것 같았는데 실제로는 시간, 메모리 효율이 더 안좋았군요 🤔

리트코드 테스트 케이스에 중복이 없거나 중복이 배열 끝부분에 있는 경우가 많으면 Sort가 더 빠르게 동작했을 것 같아요 ㅎㅎ


궁금해서 Claude한테 벤치마킹을 시켜봤는데 아래와 같이 나왔어요 ㅎㅎ 재미있네요 💪

참고하면 도움될듯하여 공유드려요!

#include <bits/stdc++.h>
using namespace std;
using namespace std::chrono;

class Solution {
public:
    // 방법 1: Sort
    bool containsDuplicate_Sort(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        for(int i = 0; i < nums.size() - 1; i++)
            if(nums[i] == nums[i+1])
                return true;
        return false;
    }
    
    // 방법 2: Unordered Set
    bool containsDuplicate_Hash(vector<int>& nums) {
        unordered_set<int> s;
        for(int num : nums) {
            if(s.count(num))
                return true;
            s.insert(num);
        }
        return false;
    }
};

// 테스트 데이터 생성
vector<int> generateTestData(int size, bool hasDuplicate) {
    vector<int> nums;
    for(int i = 0; i < size; i++) {
        nums.push_back(rand() % (size * 2));
    }
    if(!hasDuplicate) {
        // 중복 제거 (최악의 케이스)
        sort(nums.begin(), nums.end());
        nums.erase(unique(nums.begin(), nums.end()), nums.end());
        // 부족한 만큼 추가
        while(nums.size() < size) {
            nums.push_back(nums.size());
        }
    }
    return nums;
}

void benchmark(int size, bool hasDuplicate, int iterations = 10) {
    Solution sol;
    
    long long total_sort = 0;
    long long total_hash = 0;
    
    // 여러 번 실행해서 평균 구하기
    for(int iter = 0; iter < iterations; iter++) {
        vector<int> data = generateTestData(size, hasDuplicate);
        
        // Sort 방식 측정
        auto data1 = data;
        auto start1 = high_resolution_clock::now();
        bool result1 = sol.containsDuplicate_Sort(data1);
        auto end1 = high_resolution_clock::now();
        total_sort += duration_cast<microseconds>(end1 - start1).count();
        
        // Hash 방식 측정
        auto data2 = data;
        auto start2 = high_resolution_clock::now();
        bool result2 = sol.containsDuplicate_Hash(data2);
        auto end2 = high_resolution_clock::now();
        total_hash += duration_cast<microseconds>(end2 - start2).count();
    }
    
    double avg_sort = total_sort / (double)iterations;
    double avg_hash = total_hash / (double)iterations;
    
    // 결과 출력
    cout << "Size: " << setw(8) << size 
         << " | Dup: " << (hasDuplicate ? "Yes" : "No ") << " | ";
    cout << "Sort: " << setw(8) << fixed << setprecision(1) << avg_sort << " μs | ";
    cout << "Hash: " << setw(8) << fixed << setprecision(1) << avg_hash << " μs | ";
    
    if(avg_sort < avg_hash) {
        cout << "Winner: Sort (x" << setprecision(2) << (avg_hash / avg_sort) << " faster)";
    } else {
        cout << "Winner: Hash (x" << setprecision(2) << (avg_sort / avg_hash) << " faster)";
    }
    cout << endl;
}

int main() {
    srand(time(0));
    
    cout << "=== Contains Duplicate: Sort vs Hash Performance ===" << endl;
    cout << string(80, '=') << endl << endl;
    
    // 다양한 크기로 테스트
    vector<int> sizes = {100, 1000, 10000, 50000, 100000, 500000, 1000000};
    
    cout << "Test with DUPLICATES (best case - early exit possible):" << endl;
    cout << string(80, '-') << endl;
    for(int size : sizes) {
        benchmark(size, true, 5);
    }
    
    cout << endl << "Test WITHOUT duplicates (worst case - full scan):" << endl;
    cout << string(80, '-') << endl;
    for(int size : sizes) {
        benchmark(size, false, 5);
    }
    
    cout << endl << string(80, '=') << endl;
    cout << "Summary:" << endl;
    cout << "- Small sizes (< 10K): Sort usually wins due to cache locality" << endl;
    cout << "- Large sizes (> 100K): Hash wins with O(n) vs O(n log n)" << endl;
    cout << "- Memory: Sort uses O(1), Hash uses O(n)" << endl;
    
    return 0;
}

테스트 환경

  • 컴파일러: g++ -std=c++17 -O2
  • 측정 단위: μs (마이크로초)
  • 반복 횟수: 각 케이스당 5회 평균

🔹 시나리오 1: 중복이 있는 경우 (Early Exit 가능)

Size Sort (μs) Hash (μs) Winner 성능 차이
100 2.2 1.6 Hash 1.4x
1,000 36.8 3.4 Hash 10.8x
10,000 479.2 17.0 Hash 28.2x
50,000 2,806.0 26.6 Hash 105.5x
100,000 6,092.8 43.8 Hash 139.1x
500,000 33,415.8 101.0 Hash 330.9x
1,000,000 71,354.8 111.8 Hash 638.2x 🚀

→ 중복을 일찍 발견할 수 있으면 Hash가 압도적으로 빠름


🔹 시나리오 2: 중복이 없는 경우 (Worst Case - 전체 스캔)

Size Sort (μs) Hash (μs) Winner 성능 차이
100 1.0 3.6 Sort 3.6x
1,000 16.6 36.2 Sort 2.2x
10,000 217.2 516.0 Sort 2.4x
50,000 1,362.6 2,795.0 Sort 2.1x
100,000 2,780.8 6,050.8 Sort 2.2x
500,000 16,313.2 43,765.8 Sort 2.7x
1,000,000 34,415.6 95,954.0 Sort 2.8x 🚀

→ 끝까지 스캔해야 하는 경우 Sort가 2~3배 빠름

}
};

// 첫 시도 및 틀린 풀이
// 틀린 이유:
// leetcode는 처음 풀어보는데, 백준보다 시간 제한이 엄격함
// -> 20억 배열 선언하는것만으로도 시간초과 발생
//
// class Solution {
// public:
// bool containsDuplicate(vector<int>& nums) {
// vector<bool> check(2'000'000'001, false);
// int offset = 1'000'000'000;

// for(int i = 0; i < nums.size(); i++) {
// int idx = nums[i] + offset;

// if(check[idx] == true)
// return true;
// check[idx] = true;
// }
// return false;
// }
// };

24 changes: 24 additions & 0 deletions house-robber/ys-han00.cpp
Copy link

Choose a reason for hiding this comment

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

와우..! 이 문제가 DP로도 풀 수 있었군요! 💪

저는 DFS를 통해서 풀었는데, 새로운 접근법 배워갑니다 👍

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class Solution {
public:
int rob(vector<int>& nums) {
vector<int> dp(nums.size(), 0);

dp[0] = nums[0];
if(dp.size() == 1)
return dp[0];

dp[1] = nums[1];
int ans = max(dp[0], dp[1]);

for(int i = 2; i < dp.size(); i++) {
int maxi = -1;
for(int j = 0; j < i - 1; j++)
maxi = max(dp[j], maxi);
dp[i] = maxi + nums[i];
ans = max(ans, dp[i]);
}

return ans;
}
};

25 changes: 25 additions & 0 deletions longest-consecutive-sequence/ys-han00.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <bits/stdc++.h>

class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if(nums.size() == 0)
return 0;

sort(nums.begin(), nums.end());

int ans = 1, cnt = 1;
Copy link

Choose a reason for hiding this comment

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

cnt가 현재 연속 수열의 길이를 나타내는 것으로 이해했는데 맞을까요?

만약 그렇다면 변수명을 조금 더 명확하게 하면 의도가 더 잘 드러나는 코드가 될 것 같아요!

current_length 와 같은 이름이 떠오르는 것 같습니다 👍

Copy link
Author

Choose a reason for hiding this comment

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

...
의견 감사합니다! 알고리즘 문제 풀 때 습관인데, 이번 스터디 때 고치도록 해보겠습니다 ㅎㅎ

이것도 알고리즘 풀 때 있는 습관이네요... 고쳐야 할 습관이 많네요

여태까지는 혼자 알고리즘 풀고 맞추면 끝이었는데, 이번 스터디에서는 다른 분들과 공유한다는 점을 참고해서 싹 고쳐봐야겠습니다!

의견 감사합니다.

for(int i = 1; i < nums.size(); i++) {
if(nums[i] == nums[i - 1])
continue;
if(nums[i] - 1 == nums[i - 1])
cnt++;
Comment on lines +13 to +16
Copy link

Choose a reason for hiding this comment

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

nums[i] 가 현재 순회하고 있는 숫자, nums[i-1] 은 이전 숫자로 이해했는데요 ㅎㅎ
인덱스 접근이다보니 한 눈에 들어오지 않더라구요 😢

아래와 같이 임시 변수로 빼서 처리하는 방법도 있을 것 같은데, 어떠신가요?

int current = nums[i]
int previous = nums[i-1]

if(current == previous) {
   ...
}

if (current == previous + 1) {
    current_length ++;
}

이렇게 하면 current, previous로 각 값의 의미가 명확해지는 것 같아서요 ㅎㅎ

  • current = previous + 1로 "현재가 이전 + 1" 이라는 의미를 더 직관적으로 전달할 수도 있을 것 같습니다

작은 차이지만 가독성 측면에서 좋을 것 같아서 제안드려봐요 👍

Copy link
Author

Choose a reason for hiding this comment

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

이것도 알고리즘 풀 때 있는 습관이네요... 고쳐야 할 습관이 많네요 여태까지는 혼자 알고리즘 풀고 맞추면 끝이었는데, 이번 스터디에서는 다른 분들과 공유한다는 점을 참고해서 싹 고쳐봐야겠습니다!

숏코딩하려는 습관이 하하. 의견 감사해요!

else
cnt = 1;
ans = max(cnt, ans);
}

return ans;
}
};

29 changes: 29 additions & 0 deletions top-k-frequent-elements/ys-han00.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <bits/stdc++.h>

class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> count;

for(int i = 0; i < nums.size(); i++) {
if(count.find(nums[i]) == count.end())
count[nums[i]] = 1;
else
count[nums[i]]++;
Comment on lines +9 to +12
Copy link

@unpo88 unpo88 Nov 9, 2025

Choose a reason for hiding this comment

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

[단순 궁금]

제가 잘 몰라서 질문드려요!

C++ map에서는 키가 없으면 자동으로 0으로 초기화해주거나 하지는 않나요?

python에서는 Key가 없으면 자동으로 0으로 초기화할 수 있는 방법이 있어서 ㅎㅎ

이게 가능하면 find 없이 아래와 같이 코드를 단순화 시킬수도 있을듯하여 질문드려요~!

for(int i = 0; i < num.size(); i++) {
    count[num[i]]++;
}

Copy link
Author

Choose a reason for hiding this comment

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

여태까지 python dict나 C++ map을 사용할 때 항상 선언 후 사용했었는데, 이런 좋은 기능이 있는지 몰랐네요;;

이번 기회에 비효율적이게 쓰던 코드들 한번 고쳐봐야겠어요!

정말 좋은 팁 감사합니다!!

}

vector<pair<int, int>> cnt(count.begin(), count.end());
sort(cnt.begin(), cnt.end(), cmp);

vector<int> ans;
for(int i = 0; i < k; i++)
ans.push_back(cnt[i].first);

return ans;
}

static bool cmp(const pair<int, int>& a, const pair<int, int>& b) {
return a.second > b.second;
}
};

21 changes: 21 additions & 0 deletions two-sum/ys-han00.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <bits/stdc++.h>

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<pair<int, int>> num_idx;
for(int i = 0; i < nums.size(); i++)
num_idx.push_back({nums[i], i});

sort(num_idx.begin(), num_idx.end());

int left = 0, right = nums.size() - 1;
while(1) {
if (num_idx[left].first + num_idx[right].first == target)
return vector<int>({num_idx[left].second, num_idx[right].second});
if(num_idx[left].first + num_idx[right].first < target) left++;
else right--;
}
}
};