{ }codelper
포인터P0074

포인터로 걷는 가장 긴 덩이

첫 줄에 n, 둘째 줄에 정수 n개가 주어진다.
같은 수가 연달아 붙어 있는 부분을 덩이라고 한다(수 하나도 길이 1인 덩이다).
가장 긴 덩이의 시작 자리(1부터 센다)와 길이를 빈칸 하나로 띄워 출력하라.
가장 긴 덩이가 여럿이면 가장 앞의 것을 출력한다.
배열의 첫 칸과 끝 바로 다음 칸을 가리키는 포인터 두 개를 받아 포인터를 한 칸씩 옮기며 걷고, 가장 긴 덩이의 시작을 가리키는 포인터를 돌려주는 함수를 만들어 풀어 보자.
시작 자리는 그 포인터에서 배열의 첫 칸 포인터를 빼서 구한다.

입력
1 ≤ n ≤ 100,000, 모든 수는 -1,000,000,000 이상 1,000,000,000 이하의 정수
출력
한 줄: 시작 자리 길이
예시 1 · stdin
7
3 1 2 2 2 1 1
stdout
3 3
예시 2 · stdin
5
1 2 2 3 3
stdout
2 2
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 2개 언어 풀이

이 문제는 C·C++만 받아요.
주소를 쥐고 p++로 옮기며 걷는 포인터와 포인터 빼기는 두 언어에만 있고, Python·JavaScript·TypeScript·Java·크레이콘은 번호 i로 걸어요(C#은 unsafe 안에서만 포인터).
함수는 const int *longest_run(const int *first, const int *last, int *len)처럼 [first, last)를 받아요.
last = a + n은 끝 바로 다음 칸이라 가리키기만 하고 읽지 않고, 걷는 조건은 p != last예요.
같은 배열 안의 두 포인터를 빼면 바이트 수가 아니라 칸 수가 나와서, start - a가 0부터 센 자리, q - p가 덩이 길이예요.
C++는 a.data()와 a.data() + a.size()를 넘기고, 실제로는 같은 모양의 반복자(a.begin(), a.end())를 더 많이 써요.
함정 셋: ① 함수 안에서 sizeof(a) / sizeof(a[0])로 길이를 구하면, 매개변수 int a[]는 사실 포인터라 64비트에서 8 / 4 = 2가 나와 앞의 두 칸만 봐요.
그래서 길이나 끝 포인터를 따로 넘겨요.
② (start - a) / sizeof(int)처럼 또 나누면 안 돼요.
포인터 빼기는 이미 칸 수예요.
③ 길이를 >=로 비교하면 비길 때 뒤의 덩이로 바뀌어요.
더 길 때(>)만 바꿔요.

C++main.cpp · 31 줄
#include <iostream>#include <vector> // [first, last) 를 포인터로 걷는다. 길이는 참조로 돌려준다const int* longest_run(const int* first, const int* last, int& len) {    const int* best = first;    len = 0;    for (const int* p = first; p != last;) {        const int* q = p;        while (q != last && *q == *p) ++q;        if (q - p > len) {            best = p;            len = static_cast<int>(q - p);        }        p = q;    }    return best;} int main() {    std::ios::sync_with_stdio(false);    std::cin.tie(nullptr);    int n;    std::cin >> n;    std::vector<int> a(n);    for (int& v : a) std::cin >> v;     int len;    const int* start = longest_run(a.data(), a.data() + a.size(), len);    std::cout << (start - a.data()) + 1 << " " << len << "\n";}
Cmain.c · 34 줄
#include <stdio.h>#include <stdlib.h> /* [first, last) 구간을 포인터로 걸으며 가장 긴 같은 수 덩이를 찾는다.   덩이의 시작을 가리키는 포인터를 돌려주고, 길이는 *len에 써 넣는다. */const int *longest_run(const int *first, const int *last, int *len) {    const int *best = first;    *len = 0;    const int *p = first;    while (p != last) {        const int *q = p;        while (q != last && *q == *p) q++;  /* q는 덩이 바로 다음 칸 */        if (q - p > *len) {                 /* 포인터 빼기 = 칸 수. 더 길 때만 바꿔서 비기면 앞의 것 */            best = p;            *len = (int)(q - p);        }        p = q;    }    return best;} int main(void) {    int n;    scanf("%d", &n);    int *a = malloc(n * sizeof *a);    for (int i = 0; i < n; i++) scanf("%d", &a[i]);     int len;    const int *start = longest_run(a, a + n, &len);  /* a + n은 끝 바로 다음: 가리키기만 하고 읽지 않는다 */    printf("%d %d\n", (int)(start - a) + 1, len);    /* start - a 가 0부터 센 자리 */     free(a);    return 0;}