[책] 프로그래밍 면접 이렇게 준비한다 - Chapter3. 전화 예비 면접 문제

Kim Yuhyeon·2023년 7월 2일
0

면접

목록 보기
4/5

C언어 메모리 할당


C에서 메모리를 어떻게 할당하는가?

  • 면접관이 비전문가일 경우 :
    malloc을 호출하는 방법입니다.

  • 면접관이 전문가일 경우 :
    동적, 정적 할당의 장단점, calloc, realloc 같이 덜 흔하게 쓰이는 표준 C 메모리 관리자 호출에 대한 내용, 맞춤형 메모리 관리자를 써야 할만한 특별한 상황 등의 대답 준비하기

재귀 호출의 장단점


재귀 호출이 나쁜 이유는 무엇인가? (재귀 호출을 사용할 때 생길 수 있는 단점은 무엇인가요?)

  • 재귀 호출을 하려면 함수를 반복해서 호출해야 하는데, 매번 호출할 때마다 시간과 스택 공간에서 오버헤드가 발생합니다.
  • 재귀 호출을 헷갈리는 사람이 많기 때문에, 재귀 호출 함수는 문서화나 디버깅, 유지보수가 어려울 수 있습니다.

모바일 프로그래밍


모바일 기기용 프로그래밍과 일반 컴퓨터용 프로그래밍은 어떻게 다른가?

  • 모바일 기기는 보통 안드로이드나 iOS처럼 모바일용으로 특화된 운영체제를 사용한다. 이런 운영체제는 데스크톱이나 서버 운영체제와는 다른 파일 시스템 액세스, 메모리 액세스, 애플리케이션 간 통신 패러다임 같은 특징이 있다.

  • 모바일 프로그래밍에서는 전력 소모에 더 신경을 써야 하고, 저장 공간이나 네트워크 대역폭에도 제약이 더 심한 편이다. 네트워크 연결이 중간중간 끊어질 수도 있고, 대역폭도 크게 달라질 수 있다.

  • 모바일 기기에서는 터치스크린과 마이크를 주 입력 장치로 사용하기 때문에 작은 화면, 손가락으로 다루기 좋은 위젯, 제스쳐, 음성인식 사용을 최적화하고 화면을 누르는 소프트 키보드로 불편한 텍스트 입력은 최소화하는 식으로 사용자 인터페이스 디자인을 구성한다.

  • 모바일 기기는 가속도계, GPS 위치 서비스, 알림, 연락처 데이터베이스 같은 자원의 가용성 면에서 모바일이 아닌 기기에 비해 일관성이 높은 편이나, 이런 자원에 대한 접근은 접근 권한 모형에 의해 제한될 수도 있다.

  • 어플리케이션 배포는 보통 온라인 어플리케이션 스토어를 통해서만 이루어진다.

FizzBuzz


1에서 100까지 숫자를 출력하는 프로그램을 만들어라. 숫자가 3으로 나누어 떨어지면 그 숫자 대신 Fizz를, 5로 나누어 떨어지면 그 숫자 대신 Buzz를, 3과 5 모두로 나누어 떨어지면 그 숫자 대신 FizzBuzz를 출력해라

for(int i=1; i<=100; ++i)
{
    bool divByThree = (i%3 == 0);
    bool divByFive = (i%5 == 0);

    if (divByThree &&divByFive)
       cout << "FizzBuzz\n";
    else if (divByThree)
       cout << "Fizz\n";
    else if (divByFive)
       cout << "Buzz\n";
    else
       cout << i << '\n';
}

문자열 뒤집기


라이브러리 함수를 쓰지 않고 문자열을 뒤집는 함수를 만들어라.

string ReverseString(string in)
{
    string out = "";

    for(int i = in.length()-1; i >= 0; --i)
    {
        out += in[i];
    }
    
    return out;
}
  • 위 답에서는 효율성 문제를 일으킬 수 있는 부분에 대한 추가 질문이 나올 수 있다.

    • 문자열 연산의 효율성 개선:
      문자열 연결 연산인 +=를 사용하는 대신, std::stringpush_back 함수를 사용하여 문자를 하나씩 추가하는 방식으로 변경할 수 있습니다.
      이렇게 하면 문자열을 재할당하거나 복사할 필요가 없으므로 성능이 향상됩니다.

    • 문자열 사전 할당 :
      입력 문자열의 길이를 미리 알고 있는 경우, 출력 문자열인 out에 사전에 충분한 크기의 메모리를 할당할 수 있습니다.
      이를 위해 out을 입력 문자열과 같은 크기로 미리 할당하면 재할당 없이 문자를 추가할 수 있으므로 성능이 향상됩니다.

string ReverseString(string in)
{
    int len = in.length();
    string out;
    out.reserve(len);

    for(int i = len-1; i >= 0; --i)
    {
       out.push_back(in[i]);
    }
    
    return out;
}

❗ 중복 삭제 ❗


정렬되지 않은 정수 리스트가 주어졌을 때 모든 중복된 값을 제거한 새로운 리스트를 리턴하는 함수를 만들어라

  • 2번째 리스트를 하나 만든 다음,
    어떤 값이 이미 들어있는지 검색하고 없으면 2번째 리스트에 추가하는 방법
#include <list>

list<int> RemoveDuplicates(list<int>& in)
{
    list<int> out;

    for(auto ival : in)
    {
        bool found = false;

        for ( auto oval : out)
        {
            if (ival == oval)
            {
                found = true;
                break;
            }
        }

        if (!found)
        {
            out.push_back(ival);
        }
    }


    return out;

}
  • 집합 이용
    • 순서를 유지하는 조건이 있는지 없는지 미리 물어보기
    • 단순히 중복을 피하는 것이 조건이라면 리스트보다는 집합에 데이터를 저장하는 것이 좋다.
      • 순서 유지는 보장되지 않는다.
    • 그러나 문제에서 리스트를 리턴하라고 했기 때문에 집합을 다시 리스트로 변환해야 한다.
    • C++에서는 한 자료구조의 반복자를 다른 자료구조의 생성자에 전달하는 식으로 리스트와 집합 사이에서 변환할 수 있다.
#include <list>
#include <unordered_set>

list<int> RemoveDuplicates2(list<int>& in)
{
    unordered_set<int> s (in.begin(), in.end());
    list<int> out (s.begin(), s.end());

    return out;
}

중첩 괄호


왼쪽과 오른쪽 괄호가 포함된 문자열이 주어졌다. 괄호가 제대로 중첩되어 있는지 판단하는 코드를 작성하라. 예를 들어 (())와 ()()에서는 괄호가 제대로 중첩돼 있지만 (()()나 )(에서는 그렇지 않다.

  • 괄호가 바르게 중첩된 문자열에는 왼쪽과 오른쪽 괄호 개수가 같아야 하므로 개수를 세는 문제로 접근
    • 왼쪽과 오른쪽 괄호의 상대적인 개수를 추적하는 변수
      • 왼쪽 괄호가 나오면 1 증가, 오른쪽 괄호가 나오면 1 감소
      • 끝까지 갔을 때 카운터가 0이 아니면 괄호가 제대로 중첩되어 있지 않은 것
      • 최종에서만 체크하면 안되고 중간에도 음수가 되면 안된다.
        - ex. )(
bool checkNesting(string s)
{
    int count = 0;
    for(int i=0; i<s.length(); i++)
    {
        char ch = s[i];
        if (ch == '(')
            ++count;
        else if (ch == ')')
        {
            --count;
            if (count < 0) return false;
        }
    }

    return count == 0;
}
  • 개인적 풀이) 스택
    • 오른쪽 괄호가 들어갔을 때 top이 왼쪽 괄호이면 상쇄시키기
 string str = "(()()";

    stack<char> ss;

    for(int i=0; i<str.length(); ++i)
    {
        if (i == 0)
            ss.push(str[i]);
        else 
        {
            if (str[i] == ')' && ss.top() == '(')
                ss.pop();
            else
                ss.push(str[i]);
        }

    }

    if (ss.size() == 0)
        cout << "YES\n";
    else 
        cout << "NO\n";

0개의 댓글