2009년 10월 29일
2009년 다음 입사시험 문제
2009년 후반기 다음 입사시험 문제 중 일부. 입사시험은 크게 두 부분으로 나뉘는데, 전산일반과 DB, SQL, 프로그래밍 일반 등에 대한 단답식 문항들이 1 영역이고, 2 영역은 코딩 테스트. 아래 내용은 2영역의 문제다.
1. 문자열을 역순으로 출력하는 함수를 작성하시오. 예를들어 1423을 입력했으면 3241, 1320을 입력했으면 231이 나와야 합니다. 아래의 프로토타입에 맞게 작성하시오. 단 입력값이 잘못되었다거나, 계산할 수 없는 경우를 고려하여 이상한 출력이 발생하지 않도록 해야 함.(예외처리)
int reverse(int input);
2. 임의의 문자열 S가 있다고 했을 때, 문자열 중 연속되는 문자열 중, 2번 이상 중복되는 것만을 골라낸 후, 그 중 가장 긴 문자열의 시작 위치를 반환하는 함수를 작성하시오.
S=[abeabcdefkkkabcd]라고 한다면, 연속되는 문자열은 "ab", "abcd", "abcdef"이며, 이 중 2회 이상 중복되는 문자열은 "ab", "abcd"이다. "abcdef"는 1회만 등장하므로 제외.
"ab"보다 "abcd"가 문자열 길이가 기므로, 함수는 "abcd"의 위치를 리턴해야 한다. 맨 앞을 0번째라고 했을 때, 3번째 혹은 12번째가 답이 될 것이다. 이 중 무엇을 리턴하던 상관은 없다.(작성자 자유)
단, 전체 문자열의 길이는 1000을 넘지 않는다고 가정한다.
(원래 이 문제는 해결 알고리즘을 슈더코드나 설명으로 제시하는 것이 첫번째 문제고, 해당 알고리즘의 원리나 장단점, 효율성 등을 설명한 후 시간복잡도를 계산하고, 마지막으로 코드를 작성하게끔 되어 있는 문제였으나, 편의상 저렇게 하였다.
3. 1차원의 점들이 주어졌을 때, 그 중 가장 거리가 짧은 것의 쌍을 출력하는 함수를 작성하시오. 단 점들의 배열은 모두 정렬되어있다고 가정한다.
S={1, 3, 4, 8, 13, 17, 20}이 주어졌다면, 결과값은 (3, 4)가 될 것이다.
단, 디바이드 앤 컨커 기법을 반드시 써야 함.
예상보다는 쉬운 문제였으나, 디버거가 없는 현실-_-덕에 조금 고생했다. 난 체질적으로 디버거 돌리면서 코딩해야 하는데!; 꼭 전문 디버거가 아니더라도(임베디드 개발환경 등에서는 디버거가 지원되지 않는 경우도 흔하다.) printf 등으로 값을 찍거나 레지스터, 메모리 등을 덤프 떠 보면서 디버깅하는 게 내 습관이거든-_-
또 손코딩의 힘든 점은 코드를 쓰다가 뭐 변수를 빼먹거나 과정 하나를 빼먹거나 하여, 나중에 아차 싶어 위 라인에 뭔가를 추가하려 들면, 자리가 없어서 결국 아래에 쓴 걸 다 지우고 다시써야 하는..-_-;; 아니면 쓰고나서 생각해보니 버그가 있다거나 하는 경우. 컴퓨터로 코딩할 땐 즉석 수정이 가능하지만 손코딩은 그러기 힘들다.
어쨌든 시험시간 한시간 남기고 다 풀고 집에 왔긴 한데, 막상 돌아와서 생각해보니 영 어설프게 푼 것 같기도 하고.. 특히 1번 같은 건 진짜 쉬운 문제임에도 불구하고 리턴값을 반환하는 방식이 아닌 즉석에서 바로 찍어버리는 방법을 택해서, 어째 정해진 규약에 어긋나게 푼 것 같기도 하다. 문제를 차근히 읽지 않고 너무 성급하게 풀어버렸나 싶고..;
모르겠다. 붙으면 좋고 아니면 말고.. 저 정도 문제는 다들 잘 풀었겠지.
관심있는 분은 풀어봐도 괜찮을 것 같다.
-------------------------------------------------------------------------------------------------------
예전에 올렸다가 혹시 몰라서 비공개로 돌렸었는데, 이미 떨어진 마당에 뭐 어떠냐 싶고..(..) 그냥 올려봅니다.
그때 다 풀고 나오긴 했습니다만, 물론 제 답안은 탈락한 거라 별로 보실 필요는 없을듯 (...)
1번 따위 넘어가고, 2번부터.
일단 문자열의 위치와 길이를 관리하기 위해 구조체를 정의하였다.
typedef struct str
{
int startindex; //문자열 시작위치
int endindex; //문자열 끝 위치
int length; //문자열 길이
}str;
/*
기본 구조는 이렇다. 앞에서부터 문자열을 탐색하며 연속된 문자열을 찾는다. 문자는 ASCII코드 등을 따른다는 전제 하에, (s[i]+1==s[i+1]) 같은 수식으로 문자열의 연속을 감지할 수 있다. 만약 연속된 문자열을 찾게 되면, 그 연속 규칙이 어디까지 적용되는가, 다시말해 (s[i]+1==s[i+1]) 라는 수식이 적용되는 부분이 어디까지인가를 별도로 알아낸다. 한 문자열 부분의 처음과 끝 위치를 알아냈다면, 끝 위치-시작 위치 = 문자열 길이 가 성립할 것이다. 이 세 정보를 아까 정의한 구조체에 담은 후, 이 구조체를 스택에 저장한다. 여기에 사용한 스택의 내부구조에 대한 설명은 생략한다. (구현 코드는 하단 첨부)
*/
int cal(char *s, int length)
{
stack stack1, stack2;
struct str mystr;
bool flag=false;
for(int i=0;i<length;++i)
{
if((s[i]+1==s[i+1]) && flag==false)
{
mystr.startindex=i;
flag=true;
}
else if((s[i]+1 != s[i+1]) && flag==true)
{
mystr.endindex=i;
flag=false;
mystr.length=mystr.endindex-mystr.startindex+1;
stack1.push(mystr);
}
}
/*하나의 스택에 이렇게 연속된 문자열들의 구조체 정보들이 모두 담기게 되면, 중복되는 것만 추출할 차례다.
스택 내부의 원소들을 서로 비교해서 중복되지 않는 것들을 모두 제거한다. 원래 스택을 링크드리스트로 구현하여 삽입, 삭제에 용이하게 하는 것이 좋겠지만, 한페이지로 제한된 시험지 지면의 한계상(...) 간단한 배열을 사용하였다.
*/
int ret=0;
for(i=0;i<stack1.count();++i)
{
int ret=0;
struct str mys=stack1.getter(i);
for(int j=0;j<stack1.count();++j)
{
struct str mys2=stack1.getter(j);
if(!strncmp(&s[mys.startindex], &s[mys2.startindex], mys.length) && (mys.startindex != mys2.startindex )&& mys.length!= 0)
{
mys.length=0;
ret++;
}
}
if (ret==0)
{
stack1.setDelete(i);
}
}
//중복되지 않은 것을 제거했다면, 최대값을 추출하면 된다. 최대값 구하는 알고리즘은 정형화되어 있다. 다만 문제에서 요구하는 출력값은 최대 길이 자체가 아니라, 해당 문자열의 시작위치이므로 startindex를 찾아낸다.
int max=0;
int sindex=0;
for(i=0;i<stack1.count();++i)
{
struct str ss=stack1.getter(i);
if(max<=ss.length)
{
max=ss.length;
sindex=ss.startindex;
}
}
return sindex;
}
//이 프로그램을 구동시킬 메인함수는, 문자열을 간단히 넘겨주면 된다. 아래 문자열 대로 하면 결과값은 14가 나온다.
int main(int argc, char *argv[]) {
char *ary="abcdefaaabeabcabcdeabcjjjab";
int result=cal(ary, strlen(ary));
printf("%d", result);
return 0;
}
//아래는 자료구조로 사용한 간단한 스택이다. 크게 특별한 것은 없다.
class stack
{
public:
stack()
{
sp=0;
c=NULL;
}
void push(struct str mys)
{
if(c==NULL)
c=new struct str[1];
else
{
struct str *temp=new struct str[sp+2];
memcpy(temp, c, sizeof(struct str)*(sp));
delete c;
c=temp;
}
c[sp].startindex=mys.startindex;
c[sp].endindex=mys.length;
c[sp].length=mys.length;
sp++;
}
struct str getter(int i)
{
if(sp>=i)
{
return c[i];
}
else
{
struct str a;
return a;
}
}
int setDelete(int i)
{
if(sp<=i)
return 0;
else
{
c[i].startindex=0;
c[i].endindex=0;
c[i].length=0;
}
}
int count()
{
return sp;
}
int sp;
struct str *c;
};
문제에는 문자열 최대길이를 1000으로 제한하였으나, 본 알고리즘은 문자열 길이에 제한없이 사용이 가능하다.
2번 설명은 이쯤 하고, 3번.
숫자의 포인터를 받아 옆 숫자와 비교하는 함수이다. 원래라면 바운더리에 관련한 예외처리를 해주어야 하나, 지면상 생략하였다.
int *cmp(int *a, int *b, int *c)
{
if(a[1]-a[0] >= c[1]-c[0] && b[1]-b[0] >=c[1]-c[0])
return c;
else if(a[1]-a[0] >= b[1]-b[0] && b[1]-b[0]<= c[1]-c[0])
return b;
else if( a[1]-a[0] <= b[1]-b[0] && a[1]-a[0] <= c[1]-c[0])
return a;
else
return a;
}
// 전체 배열을 총 3 부분으로 나눈다. 사실 두 부분으로 나누든 세 부분으로 나누든 네 부분으로 나누든 별 상관은 없다.
int *cal(int s[], int length)
{
int *a, *b, *c;
if(length>3)
{
a=cal(&s[0], length/3);
b=cal(&s[length/3], length/3);
if(length%3==0)
{
c=cal(&s[length/3*2], length/3);
}
else
{
c=cal(&s[length/3*2], length/3+1);
}
}
else if(length==3)
{
a=&s[0];
b=&s[1];
c=&s[2];
}
else
{
return &s[0];
}
return cmp(a, b, c);
}
//계산결과로 나온 숫자들을 출력하는 함수
void print(int s[], int length)
{
int *a=cal(s, length);
printf("(%d, %d)", *a, *(a+1));
}
//메인함수. 아래 값대로 하면 결과값은 (44, 45)가 나온다.
int main()
{
int s[12]={1, 4, 6, 8, 11, 13, 15, 18, 21, 25, 44, 45};
print(s, 12);
return 0;
}
사실 예외처리도 안한 부분이 많고, 좀더 시간을 들였다면 더 잘 쓸 수도 있었겠군요. 역시 한시간만에 뛰쳐나오는 게 아니었나보죠..(...) 일단 집에서 그대로 돌려보니 다 제대로 돌아가긴 합니다만, 3번같은 경우 예외처리가 별로 없다는 게 흠이군요.
뭐 그래봐야 떨어진 마당에 어쩔..OTL...근데 다른사람들은 대체 얼마나 잘 풀었길래..
# by | 2009/10/29 21:40 | 트랙백 | 덧글(14)






☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
1. 해결 알고리즘을 슈더코드나 설명
2. 해당 알고리즘의 원리나 장단점, 효율성 등을 설명한 후
3. 시간복잡도를 계산하고, 마지막으로 코드를 작성
4. 디바이드 앤 컨커 기법
위의 1.2.3.4.는 전혀 못하겠네요.. ㅠㅠ
signed integer 의 최대치가 2147483648 이니까... 사실 1,999,999,999 도 예외처리를 해야 할텐데 말이죠. 은근히 이것저것 함정이 많은 문제들이네요 전부.
계산의 편의를 위해 2byte int 로 가정하면 MAX 32767.
이때 10004를 뒤집으면 결과값이 40001 이 되는데, 2byte int의 표기 범위를 넘네요. 이거 예외처리 필요하지 않을까요? :)
int reverse(int input)
{
if(input <0 )
return -1;
else
{
double result=0;
while(input> 0)
{
result=((result*10) + (input%10));
input/=10;
}
if(result == (int)result)
return (int)result;
else
return -1;
}
}
이정도면 될듯..
혹시 이 시험 보셨나요.