[algorithm] 숫자가 주어지면 원래 숫자와 정확히 같은 자릿수가있는 다음 높은 숫자를 찾으십시오.

방금 면접을 폭파하고 면접 질문에서 거의 진전이 없었습니다. 누구 든지이 작업을 수행하는 방법을 알려주시겠습니까? 온라인 검색을 시도했지만 아무것도 찾을 수 없습니다.

숫자가 주어지면 원래 숫자와 정확히 같은 자릿수가있는 다음 높은 숫자를 찾으십시오. 예를 들어 : 주어진 38276은 38627을 반환합니다.

첫 번째 숫자 (오른쪽에서)보다 작은 숫자의 인덱스를 찾는 것으로 시작하고 싶었습니다. 그런 다음 하위 집합의 마지막 숫자를 회전하여 같은 숫자로 구성된 다음으로 큰 숫자이지만 멈추었습니다.

면접관은 한 번에 하나씩 숫자를 바꾸라고 제안했지만 알고리즘을 알아낼 수 없었고 20-30 분 정도 화면을 쳐다 보았습니다. 말할 필요도없이, 구직 활동을 계속해야 할 것 같습니다.

편집 : 그 가치에 대해, 나는 다음 번 인터뷰에 초대되었습니다.



답변

다음 과 같이 (자릿수는 O(n)어디에 있습니까? n)

오른쪽부터 시작하여 왼쪽 숫자가 오른쪽 숫자보다 작도록 첫 번째 숫자 쌍을 찾습니다. “digit-x”로 왼쪽 숫자를 참조합시다. digit-x의 오른쪽에있는 digit-x보다 작은 숫자를 찾아 digit-x의 바로 왼쪽에 배치하십시오. 마지막으로 남은 자릿수는 오름차순으로 정렬합니다. 이미 내림차순 이므로 숫자를 뒤집기 만하면됩니다 (digit-x의 올바른 위치에 배치 할 수 있음 O(n)) .

예를 들어 이것을 더 명확하게 만들 수 있습니다.

123456784987654321
숫자로 시작하다

123456784 987654321
         ^ 왼쪽 숫자가 오른쪽보다 작은 오른쪽에서 첫 번째 위치
         숫자 "x"는 4

123456784 987654321
              ^ 오른쪽으로 4보다 큰 가장 작은 숫자를 찾습니다.

123456785 4 98764321
        ^ 4의 왼쪽에 놓으십시오

123456785 4 12346789
123456785123446789
         ^ 5의 오른쪽으로 숫자를 정렬합니다.
         '4'는 이미 내림차순입니다. 우리가해야 할 일은
         순서를 바꾸고 '4'에 대한 올바른 장소를 찾으십시오.

정확성 증명 :

대문자를 사용하여 숫자 문자열과 숫자의 소문자를 정의합시다. 구문 AB수단 “문자열 연결 AB . <lexicographical ordering은 자릿수 문자열의 길이가 동일한 경우 정수 순서와 동일합니다.

우리의 원래 숫자 N의 형식은 AxB, x한 자리이며, B정렬 내림차순입니다.
알고리즘에서 찾은 숫자는 가장 작은 자릿수 (AyC 여기서 선택한 방식 으로 존재해야 함 , 위 참조) 이며 오름차순으로 정렬됩니다.y ∈ B> x xC

같은 숫자를 사용하는 숫자가 있다고 가정 N'합니다 AxB < N' < AyC. N'로 시작 A하거나 그렇지 않으면 그들 사이에 빠질 수 없으므로 양식으로 작성할 수 있습니다 AzD. 이제 우리의 불평등은입니다 AxB < AzD < AyC. xB < zD < yC세 자리 문자열이 모두 같은 자리를 포함하는 것과 같습니다.

그것이 사실이 되려면, 우리는 반드시 있어야합니다 x <= z <= y. 때문에 y작은 숫자입니다 > x, z그래서 하나, 그들 사이가 될 수 없습니다 z = xz = y. 말해봐 z = x. 그리고 우리의 불평등은 xB < xD < yC의미하는 B < D곳 모두 BD같은 자리가 있습니다. 그러나 B는 내림차순으로 정렬되므로 해당 자릿수보다 큰 문자열 없습니다. 따라서 우리는 가질 수 없습니다 B < D. 동일한 단계를 수행하면을 z = y가질 수 없다는 것을 알 수 있습니다 D < C.

따라서 N'존재할 수 없으므로 알고리즘이 다음으로 큰 숫자를 올바르게 찾습니다.


답변

거의 동일한 문제가 코드 걸림 문제로 나타 났으며 여기에 해결책이 있습니다.

http://code.google.com/codejam/contest/dashboard?c=186264#s=a&a=1

다음은 예제를 사용하는 방법에 대한 요약입니다.

34722641

A. 일련의 숫자를 두 개로 나누면 오른쪽 부분이 가능한 한 길어지고 순서는 줄어 듭니다.

34722 641

( 전체 숫자가 내림차순이면 숫자를 추가하지 않고는 더 큰 숫자가 없습니다.)

B.1. 첫 번째 시퀀스의 마지막 숫자를 선택하십시오.

3472(2) 641

B.2. 두 번째 시퀀스에서 가장 큰 자릿수보다 큰 숫자를 찾으십시오.

3472(2) 6(4)1

B.3. 스왑 :

3472(2) 6(4)1
->
3472(4) 6(2)1
->
34724 621

C. 두 번째 시퀀스를 오름차순으로 정렬하십시오.

34724 126

D. 완료!

34724126


답변

다음은 Python의 컴팩트하지만 부분적인 무차별 솔루션입니다.

def findnext(ii): return min(v for v in (int("".join(x)) for x in
    itertools.permutations(str(ii))) if v>ii)

C ++에서는 다음과 같이 순열을 할 수 있습니다 : https : //.com/a/9243091/1149664 (itertools의 알고리즘과 동일한 알고리즘입니다)

다음 은 Weeble 및 BlueRaja (다른 답변)가 설명 하는 최상위 답변구현입니다 . 더 좋은 것이 있는지 의심합니다.

def findnext(ii):
    iis=list(map(int,str(ii)))
    for i in reversed(range(len(iis))):
        if i == 0: return ii
        if iis[i] > iis[i-1] :
            break
    left,right=iis[:i],iis[i:]
    for k in reversed(range(len(right))):
        if right[k]>left[-1]:
           right[k],left[-1]=left[-1],right[k]
           break
    return int("".join(map(str,(left+sorted(right)))))


답변

최소한 다음은 무차별 문자열 기반 솔루션의 몇 가지 예입니다. 바로 머리 꼭대기에서 얻을 수 있었을 것입니다.

38276정렬 된 자릿수 목록 은23678

38627정렬 된 자릿수 목록 은23678

무차별 힘 증가, 정렬 및 비교

무차별 대입 솔루션을 따라 문자열로 변환하고 해당 숫자를 사용하여 가능한 모든 숫자를 무차별 대입합니다.

모두 int를 만들고 목록에 넣고 정렬하고 대상 항목 다음에 다음 항목을 가져옵니다.

이것에 30 분을 썼는데 적어도 무차별 대입 방식을 찾지 못했다면, 나는 당신도 고용하지 않을 것입니다.

비즈니스 세계에서 우아하고 느리고 어수선하지만 작업을 수행하는 솔루션은 솔루션이 아예없는 것보다 항상 더 가치가 있습니다. 사실 모든 비즈니스 소프트웨어를 우아하고 느리고 불쾌 하게 설명 합니다 .


답변

function foo(num){
 sortOld = num.toString().split("").sort().join('');
 do{
    num++;
   sortNew = num.toString().split("").sort().join('');
 }while(sortNew!==sortOld);
 return num;
}


답변

당신의 아이디어

첫 번째 숫자 (오른쪽에서)보다 작은 숫자의 인덱스를 찾는 것으로 시작하고 싶었습니다. 그런 다음 하위 집합의 마지막 숫자를 회전하여 같은 숫자로 구성된 다음으로 큰 숫자이지만 멈추었습니다.

사실 꽤 좋습니다. 마지막 숫자뿐만 아니라 현재 고려되는 것보다 중요도가 낮은 모든 숫자 만 고려해야합니다. 그 전에 도달하기 때문에, 우리는 단조로운 숫자 시퀀스를 가지고 있는데, 그것은 오른쪽 이웃보다 가장 오른쪽에있는 숫자입니다. 관련

1234675
    ^

숫자가 같은 다음 큰 숫자는

1234756

발견 된 숫자는 마지막 숫자 (교환 된 숫자 중 가장 작은 숫자)와 교환되며 나머지 숫자는 증가하는 순서로 정렬됩니다.


답변

나는 당신의 면접관이 당신을 다음과 같은쪽으로 부드럽게 밀려 고했다고 확신합니다 :

local number = 564321;

function split(str)
    local t = {};
    for i = 1, string.len(str) do
        table.insert(t, str.sub(str,i,i));
    end
    return t;
end

local res = number;
local i = 1;
while number >= res do
    local t = split(tostring(res));
    if i == 1 then
        i = #t;
    end
    t[i], t[i-1] = t[i-1], t[i];
    i = i - 1;
    res = tonumber(table.concat(t));
end

print(res);

가장 효율적이거나 우아한 솔루션 일 필요는 없지만 제공된 예제를 두 주기로 해결하고 그가 제안한대로 한 번에 하나씩 숫자를 교체합니다.