개발 공부/코딩 공부

프로그래머스 리스트 자르기

baby-t 2025. 9. 13. 13:55

프로그래머스 리스트 자르기

 

간단한 문제지만, string에선 substr로 빠르게 해결되는 문제지만 vector는 잘 모르겠어서 gemini에 물어봤다.


C++ 벡터 슬라이싱

벡터의 특정 부분을 복사해 새로운 벡터를 만들고 싶을 때, 두 개의 이터레이터를 사용하는 **범위 생성자(range constructor)**를 사용합니다.

  • begin(): 벡터의 시작 위치를 가리키는 이터레이터입니다.
  • end(): 벡터의 끝 바로 다음 위치를 가리키는 이터레이터입니다.

코드 예시

C++
 
#include <iostream>
#include <vector>

int main() {
    std::vector<int> original = {0, 10, 20, 30, 40, 50};

    // 인덱스 2부터 4까지 슬라이싱 (20, 30, 40)
    // original.begin() + 2: 시작 위치
    // original.begin() + 5: 끝 위치 (포함하지 않음)
    std::vector<int> sliced(original.begin() + 2, original.begin() + 5);

    // 슬라이싱 결과 출력
    for (int num : sliced) {
        std::cout << num << " "; // 20 30 40 
    }
    std::cout << std::endl;

    return 0;
}

C++ 문자열 슬라이싱

말씀하신 대로, std::string은 substr 멤버 함수를 사용해 매우 직관적으로 슬라이싱할 수 있습니다.

  • substr(시작 인덱스, 길이)

코드 예시

C++
 
#include <iostream>
#include <string>

int main() {
    std::string original = "hello world";

    // 인덱스 6부터 5글자 슬라이싱 ("world")
    std::string sliced = original.substr(6, 5);

    std::cout << sliced << std::endl; // world

    return 0;
}

요약

자료형 슬라이싱 방법 설명
std::vector vector(시작_이터레이터, 끝_이터레이터) 범위 생성자를 이용한 복사
std::string substr(시작_인덱스, 길이) 내장 멤버 함수 사용

 

그러고 vector의 생성 방식 중 이런 방식이 있는지 몰랐어서 정리했다.


### vector 생성 방법 2가지

  1. 채우기 생성자 (Fill Constructor)
    • 형태: vector<int> my_vector(개수, 초기화할_값);
    • 설명: 지정한 개수만큼의 공간을 만들고 모든 요소를 동일한 초기화할_값으로 채워서 벡터를 생성합니다.
  2. 범위 생성자 (Range Constructor)
    • 형태: vector<int> my_vector(시작_이터레이터, 끝_이터레이터);
    • 설명: 다른 컨테이너(예: 다른 벡터나 배열)의 시작 위치부터 끝 위치 바로 앞까지의 모든 요소를 복사해서 새로운 벡터를 만듭니다.

그러나 answer = (num_list.begin(), num_list.begin() + b + 1); 처럼 따로 하나씩 만드니까 오류가 발생했다.

 

answer.assign(num_list.begin(), num_list.begin() + b + 1); 이런식으로 assign으로 재할당해줘야 했다.

 

그런 이유는 타입 불일치이기 때문.


### 왜 일반 대입(=)은 안 될까?

컴퓨터(컴파일러)는 타입을 매우 엄격하게 구분합니다. vector<int> 타입의 변수에는 vector<int> 타입의 값만 대입할 수 있습니다.

  • vector<int>: '정수를 담는 상자' 자체입니다.
  • vector<int>::iterator: 상자 안의 **'특정 물건을 가리키는 포인터 또는 책갈피'**입니다.

answer = (num_list.begin(), num_list.end()); 와 같은 코드는 **'상자'**에 **'책갈피'**를 넣으려는 시도와 같습니다. 둘은 완전히 다른 종류이기 때문에 C++ 컴파일러가 "타입이 맞지 않아서 대입할 수 없습니다."라는 오류를 발생시킵니다.

C++
 
vector<int> answer;
vector<int> original = {1, 2, 3, 4};

// 아래 코드는 컴파일 에러 발생!
// error: cannot convert ‘std::vector<int>::iterator’ to ‘std::vector<int>’
answer = original.begin(); 

### 올바른 방법 2가지

그래서 C++는 이터레이터 범위를 다루는 두 가지 방법을 명확하게 구분해서 제공합니다.

  1. 생성자 (선언과 동시에 초기화)
    • vector<int> answer(original.begin(), original.end());
    • answer라는 벡터가 태어날 때부터 original의 특정 범위를 복사해서 태어나도록 하는 것입니다.
  2. assign 메소드 (이미 있는 벡터의 내용 교체)
    • answer.assign(original.begin(), original.end());
    • 이미 존재하는 answer 벡터의 기존 내용을 싹 지우고, 지정된 범위의 새로운 내용으로 갈아끼우는 것입니다.

결론적으로, 이터레이터를 사용하는 것은 생성할 때와 그 이후 모두 가능하지만, 그 이후에는 반드시 assign이라는 전용 메소드를 사용해야 합니다.

'개발 공부 > 코딩 공부' 카테고리의 다른 글

C++ 람다식  (0) 2025.09.16
C++ 입출력  (0) 2025.09.15
c++ <limits>, const &auto  (0) 2025.09.03
복사와 함수 인자 전달 , 그리고 메모리  (0) 2025.09.03
간단한 수학 공식들  (1) 2025.09.01