핑퐁게임

출처: https://brunch.co.kr/@sunghokimnxag/5

일련의 숫자가 있고, 이 숫자는 1씩 증가, 또는 감소한다. n번째의 숫자가 있을 시에, 이 숫자가 7의 배수(7, 14, 21,...)거나 7이란 숫자를 포함할 시에 (7, 17, 27,...) 방향을 바꾼다.

즉, 다음과 같이 숫자는 진행한다.

1,2,3,4,5,6,[7],6,5,4,3,2,1,[0],1,2,[3],2,1,0,[-1],0,1

(첫 번째 7은 7번째, 두번째 0은 14번째, 세번째 3은 17번째, 네번째 -1은 21번째)

이와 같은 pingpong(x)의 함수를 작성하라. 예시의 인풋과 아웃풋은 다음과 같다.

pingpong(8) = 6
pingpong(22) = 0
pingpong(68) = 2
pingpong(100) = 2

심화학습

위 문제에 다음과 같은 제약을 추가하여 다시 풀어보자.

  • For Loop 또는 Array를 쓰지 말 것
  • Assignment를 쓰지 말 것, 즉, 변수 할당을 하지 말 것.
  • String을 쓰지 말 것
면접문제 재귀호출
죄송하지만 저한테 조금 어려워서 그러는데 진행이 끝나는 곳이 어디죠? - 최승호, 2016/07/23 21:39 M D
pingpong 함수의 입력이 8이면 8번째 해당 하는 값이 출력되면 되구요, 100이면 100번째 해당하는 값을 출력하면 됩니다. - 길가의풀, 2016/07/24 16:12 M D
※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

22개의 풀이가 있습니다. 1 / 3 Page

Ruby

3가지로 품. ( list조작 + 문자열, list 조작 + 문자열 사용않기, recursion + 아무것도 사용않기)

string, list comprehension - 쉽게 풀기

sevens = ->nth { (0..nth).select {|n| n%7==0 || n.to_s.include?("7") || n==nth} }
pingpong = ->x { sevens.(x).each_cons(2).map {|a,b| b-a }.map.with_index.
                           reduce(0) {|sum,(gap,i)| sum + gap*(i.odd?? -1:1)} }
# test
expect( [8,22,68,100,10000,100000].map &pingpong ).to eq [6, 0, 2, 2, -122, 212]
expect( Benchmark.realtime { pingpong.(100000) } ).to be_between(0.001, 0.1)

list comprehension - string 쓰지 않기

is_7 = ->n { n.abs<10 ? (n.abs==7) : is_7.(n/10) || is_7.(n%10) }
sevens = ->nth { (0..nth).select {|n| is_7.(n) || n%7==0 || n==nth } }
pingpong = ->x { sevens.(x).each_cons(2).map {|a,b| b-a }.
                        map.with_index {|gap,i| gap * (i.odd?? -1:1) }.sum }
# test
expect( [7, 17, -7].all? &is_7 ).to be_truthy # 7s
expect( [8,  0, -2].all? &is_7 ).to be_falsy  # not 7s
expect( sevens.(20) ).to eq [0, 7, 14, 17, 20]
expect( [8, 22, 68, 100].map(&pingpong) ).to eq [6, 0, 2, 2]
expect( Benchmark.realtime { pingpong.(100000) } ).to be_between(0.001, 0.2)

recursion - 아무것도 쓰지 않기

is_7 = ->n { n.abs<10 ? n.abs==7 : is_7[n/10] || is_7[n%10] || n%7==0 }
pingpong = proc do |nth, idx, val, inc|
  idx.nil? ? pingpong.(nth, 1, 1, 1) : idx == nth ? val : 
             pingpong.(nth, idx+1, val+inc, is_7.(idx+1) ? -inc : inc )                         
end
# test
expect( [8, 22, 68, 100].map(&pingpong) ).to eq [6, 0, 2, 2]
expect( Benchmark.realtime { pingpong.(1000) } ).to be_between(0.0001, 0.01)
※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

이런식으로 처리하면 될 것 같습니다.


int pingpong(char *wantto){
    int ret = 0;    int count = 1;  int realdata = 1;   int wanttoint = 0;  char wanttostr[20];
    wanttoint = atoi(wantto);
    while(1){
        snprintf(wanttostr, 20, "%d",count);
        ret = realdata;
        if(count == wanttoint) break;
        if(count % 7 == 0 || strstr(wanttostr, "7")){
            while(1){
                count++;
                snprintf(wanttostr, 20, "%d",count);
                realdata --;
                ret = realdata;
                if(count == wanttoint || count % 7 == 0 || strstr(wanttostr, "7"))  break;
            }
        }
        if(count == wanttoint) break;
        count++; realdata++;
    }
    return ret;
}
※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

변수를 선언하면 안된다는 조건은 통과하지 못했습니다. 재귀를 사용했는데 이또한 1000 이상은 maximum limit때문에 계산이 불가능하네요.

파이썬입니다..

def has7(n):
    return n % 7 == 0 or (n % 10 and n % 10 % 7 == 0) \
        or (n // 10 and has7(n // 10))


def pingpong(limit, val=1, direction=1, count=1):
    if(count==limit): return val
    if has7(count): direction = -direction
    return pingpong(limit, val+direction, direction, count+1)


import unittest

class PingPongTest(unittest.TestCase):
    def test_has7(self):
        self.assertTrue(has7(7))
        self.assertFalse(has7(8))
        self.assertFalse(has7(10))
        self.assertTrue(has7(7*22))
        self.assertTrue(has7(17))
        self.assertTrue(has7(170))
        self.assertTrue(has7(178))

    def test_pingpong(self):
        self.assertEqual(6, pingpong(8))
        self.assertEqual(0, pingpong(22))
        self.assertEqual(2, pingpong(68))
        self.assertEqual(2, pingpong(100))


if __name__ == "__main__":
    unittest.main()
※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

string말고는 없애기가 힘드네요..

int sevenBool(int numbering) {
    if (numbering % 7 == 0 || numbering % 10 == 7) {
        return -1;
    }
    else if (numbering / 10 != 0) {
        return sevenBool(numbering / 10);
    }
    else {
        return 1;
    }
}
int pingpong(int pingpongCount) {
    int direction = 1;
    int result = 0;
    for (int i = 1; i <= pingpongCount; i++) {
        result = result + direction;
        direction = direction * sevenBool(i);
    }
    return result;
}
※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

자바스크립트로 짜봤습니다.

    function check7(value){
        return (value%7==0||(/7/).test(value)) ? -1 : 1;
    }
    function pingpong(value,cnt, returnVal, direction){
        cnt = cnt==undefined ? 1 : cnt;
        returnVal = returnVal==undefined ? 1 : returnVal;
        direction = direction==undefined ? 1 : direction;

        return (value==cnt) ? returnVal
        : pingpong(value, cnt+1, returnVal+direction, direction*check7(cnt+1));

    }
    console.log(pingpong(8));
    console.log(pingpong(22));
    console.log(pingpong(68));
    console.log(pingpong(100));
※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

조건이 하나 빠진 거 같아서 원문까지 살펴봤는데요, n 은 1000 미만이라는 조건이 붙어야 제약을 적용해서 풀이가 가능할 것 같은데 원문에도 그 언급이 그냥 뒤에서 슬그머니 나오네요.

def pingpong(n: int) -> int:
    def has7(x: int, first=True) -> bool:
        if x is 0:
            return False
        elif first:
            if x % 7 is 0 or x % 10 is 7:
                return True
        elif x % 10 is 7:
            return True
        else:
            return has7(x//10, False)

    def inner(count=1, step=1, result=1):
        if count == n:
            return result
        return inner(count+1, step if has7(count) else -step, result+ (step if has7(count) else -step))
    return inner()

print(pingpong(997))

n의 크기를 한정할 수 없다고 가정하면 7이 있는지 여부를 찾는 부분도 재귀로 구성해야 합니다. 그러면 실질적으로는 997까지의 값만 구할 수 있습니다. (재귀스택에서 has7이 써버리는 부분이 있다보니..)

만약, 할당을 허용한다고 하면 꼬리재귀 호출 대신에 다음 재귀 호출에 넘길 인자를 튜플로 리턴하는 식으로 코드를 약간 뜯어고쳐서 반복문으로 만들 수 있습니다.

def pingpong(n: int) -> int:

    def has7(x: int, first=True) -> bool:
        if x is 0:
            return False
        elif first:
            if x % 7 == 0 or x % 10 is 7:
                return True
        elif x % 10 is 7:
            return True
        else:
            return has7(x//10, False)

    def inner(count=1, step=1, result=1):
        if count == n:
            return result
        return (count+1, step if has7(count) else -step, result+ (step if has7(count) else -step))

    r = inner()
    while not isinstance(r, int):
        r = inner(*r)
    return r

print(pingpong(1000000))
※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.
    private static void pingpongRestriction(int end) {
        System.out.println("pingpong (" + end + ") = " + recursiveFunc(end, 1, 1, 1));
    }

    // end          : 종료 횟수
    // count        : 회차
    // result       : 회차의 결과값
    // fluctuation  : 증감값
    private static int recursiveFunc(int end, int count, int result, int fluctuation) {

        if (count == end) {
            return result;
        } else {
            return recursiveFunc(end, count + 1, result + (fluctuation * fluctiationFunc(count)), fluctuation * fluctiationFunc(count));        
        }
    }

    //증감
    private static int fluctiationFunc(int count) {
        return ( ((count % 7) == 0) || ((count % 10) == 7) || ((count / 10) == 7) ) ? -1 : 1;
    }
※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.
#include <stdio.h>

int pm(int num)
{
    if (num == 0) return 1;

    if (num % 7 == 0 || num % 10 == 7 || (num / 10) % 10 == 7 || num / 100 == 7)
        return -pm(num - 1);
    else
        return pm(num - 1);
}

int pingpong(int num)
{
    if (num == 1) return 1;

    return pingpong(num - 1) + pm(num - 1);
}

void main(void)
{
    printf("%d\n",pingpong(8));
    printf("%d\n", pingpong(22));
    printf("%d\n", pingpong(68));
    printf("%d\n", pingpong(100));
}
※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

허접한 풀이!! ㅠ,.ㅠ

#include<stdio.h>
#include<windows.h>

struct Sseq {
    int seq;
    int out;
};

int pingpong(int input);

Sseq s;
int temp;
char ch;

void main(void) {
    int input;

    ch = '+';
    s.out = 1;
    s.seq = 1;
    temp = 0;

    printf("#입력 : ");
    scanf("%d", &input);

    printf("\n#출력 : ");
    printf("%d\n", pingpong(input));


}

int pingpong(int input) {

    if(((s.seq % 7) == 0 || (s.seq % 10) == 7  || (s.seq/7)%10 == 0) && s.seq/7!=0) {
        if(temp < s.out)
            ch='-';
        else 
            ch='+';
    }
    if(ch == '-') {
        temp = s.out;
        s.out--;
    }
    else {
        temp = s.out;
        s.out++;
    }

    s.seq++;
    input--;

    if(input > 1)
        return pingpong(input);
    else
        return s.out;
}
※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

자바

package study;

public class study {

    public static void main(String[] args) {
        System.out.println("pingpong(" + 8 + ") = " + pingpong(8));
    }

    public static int pingpong(int n) {
        int dir = 1, result = 0;

        for (int i = 1; i < n + 1; i++) {
            if (dir == 1) {
                result++;
            } else {
                result--;
            }

            if (i % 7 == 0 || i % 10 == 7 || (i / 10) % 10 == 7 || (i / 100) % 10 == 7 || (i / 1000) % 10 == 7) {
                dir = (dir + 1) % 2;
            }
        }

        return result;
    }
}

귀찮아서 String 안 쓰고 4자리까지만 되게 했습니다 추가조건은 어려워서 요까지만...

※ 상대에게 상처를 주기보다 서로에게 도움이 될 수 있는 댓글을 달아 주세요.

풀이 작성

※ 풀이작성 안내
  • 본문에 코드를 삽입할 경우 에디터 우측 상단의 "코드삽입" 버튼을 이용 해 주세요.
  • 마크다운 문법으로 본문을 작성 해 주세요.
  • 풀이를 읽는 사람들을 위하여 풀이에 대한 설명도 부탁드려요. (아이디어나 사용한 알고리즘 또는 참고한 자료등)
  • 작성한 풀이는 다른 사람(빨간띠 이상)에 의해서 내용이 개선될 수 있습니다.
목록으로
코딩도장

코딩도장은 프로그래밍 문제풀이를 통해서 코딩 실력을 수련(Practice)하는 곳입니다.

면접문제 x 7
재귀호출 x 3
연관 문제
예강효빠, 2017/05/26 00:39
c0din9, 2017/03/02 13:05
genius.choi, 2017/04/06 14:14
Mike Yoon, 2017/05/27 10:20

언어별 풀이 현황
전 체 x 22
ruby x 1
기 타 x 3
python x 7
cpp x 4
javascript x 1
java x 4
cs x 1
matlab x 1