番号を指定して、元の番号とまったく同じ数字のセットを持つ次に大きい番号を見つけます


226

私はインタビューを爆撃しただけで、インタビューの質問についてはほとんど進展がありませんでした。誰でもこれを行う方法を教えてもらえますか?オンラインで検索してみましたが、何も見つかりませんでした。

数値を指定して、元の数値とまったく同じ数字のセットを持つ次に大きい数値を見つけます。例:38276が返される38627を返す

まず、1桁よりも小さい最初の桁(右から)のインデックスを見つけることから始めました。次に、サブセットの最後の数字を同じ数字で構成される次に大きい数字になるようにローテーションしましたが、行き詰まりました。

インタビュアーは、数字を1つずつ交換することも提案しましたが、アルゴリズムを理解できず、画面を20〜30分間見つめただけです。言うまでもなく、私は就職活動を続ける必要があると思います。

編集:その価値のために、私は次のインタビューのラウンドに招待されました


15
それについてあまり考えずに始めれば、少なくとも力ずくで数字のすべての順列を計算し、入力数より大きい最小数を取得することになります
BrokenGlass

13
C ++ではnext_permutation;-)を使用できます
thedayturns

9
参考までに、問題についてほとんど考えていなくても、約15分で解決した方法です。最初に、一連の数字のすべての可能な順列を作成し、並べ替えて表示するブルートフォースアルゴリズムを作成する5分を費やしました。リストからパターンが現れるまで5分間かけデータを調べ(短時間で確認したところ、ここでO(n)で承認されたソリューションが明らかになった)、次にO(n)アルゴリズムのコーディングに5分間費やしました。
ベン・リー

1
一般に、これは困ったときにこの種の問題を解決するためのアルゴリズムを思いつくための悪い方法ではありません-小さめのサンプルにブルートフォースを使用して大量のデータを作成し、それを使用してパターンをより簡単に確認できます。
ベン・リー

19
私も指摘したいのです、これを行う効率的な方法が本当にわからない場合は、インタビューを失敗させる確かな方法は何もありません(そして、ビジネスの世界では、製品の締め切りを見逃す確実な方法です)。 。行き詰まったときは、あきらめるのではなく、力ずくで強制して、「TODO:パフォーマンスのためのリファクタリング」などのコメントを付けるべきです。私が面接をしていて誰かがそうしたとしても、必ずしも失敗するわけではない。少なくとも彼らはうまくいくものを思いついたし、それが見つからなくても、もっと良いものがそこにあることを認めた。
ベン・リー

回答:


272

次のようにO(n)n桁数は)で行うことができます。

右から始めて、左の桁が右の桁よりも小さくなるような最初の桁のペアを見つけます。左の桁を「digit-x」で参照してみましょう。digit-xの右側にあるdigit-xより大きい最小の数値を見つけ、digit-xのすぐ左側に配置します。最後に、残りの数字を昇順で並べ替えます。それらは既に降順であるため、逆にするだけです(digit-xは保存して、の正しい場所に配置できますO(n)

例はこれをより明確にします:

123456784987654321
数字で始める

123456784 987654321
         ^左から1桁目が右よりも小さい、右から1桁目  
         数字の「x」は4

123456784 987654321
              ^ 4より大きい最小の数字を右側に見つける

123456785 4 98764321
        ^ 4の左側に配置します

123456785 4 12346789
123456785123446789
         ^数字を5の右側に並べ替えます。 
         「4」はすでに降順でした。必要なのは 
         それらの順序を逆にして、「4」の正しい場所を見つけます

正当性の証明:

大文字を使用して数字列と数字の小文字を定義しましょう。構文AB手段「の文字列を連結AしてB<は辞書順です。これは、数字列の長さが等しい場合の整数順と同じです。

元の番号Nはの形式AxBで、xは1桁で、B降順で並べ替えられています。
アルゴリズムで見つかった数値はAyCで、y ∈ Bは最小桁> x x選択された方法により存在する必要があります。上記を参照)でC昇順で並べ替えられます。

N'そのような(同じ数字を使用した)いくつかの数があると仮定しAxB < N' < AyCます。 N'始まる必要がありますAか、他我々は形でそれを書くことができますので、それは、それらの間に入ることができませんでしたAzD。これで不等式はAxB < AzD < AyCになります。これは、xB < zD < yC3つの数字列すべてに同じ数字が含まれている場合と同じです。

これが真実であるためには、が必要x <= z <= yです。以来y最も小さい数字で> xzそのいずれかで、それらの間にできませんz = xz = y。言ってくださいz = x。そして、私たちの不平等はあるxB < xD < yC意味、B < Dどこの両方BD同じ数字を持っています。ただし、Bは降順でソートされるため、それよりも大きい数字の文字列はありません。したがって、私たちは持つことができませんB < D。同じステップをたどると、もしそうならz = y、私たちは持つことができないことがわかりますD < C

したがってN'、存在することはできません。つまり、アルゴリズムは次に大きい数を正しく検出します。


7
素敵な解決策!一つ質問があります。「xより大きい最小の数字」はyだと言う。xとyを交換してから、x.index + 1-> endを逆にできますか?
ケント

8
番号99999はどうなりますか?
Sterex、2012

19
@Sterex、それは99999だけではありません。数字がすでに降順で完全に並べ替えられている数は最大です(たとえば、98765にも解がありません)。アルゴリズムのステップ1が失敗するので、これはプログラムで簡単に検出できます(「左の桁が右の桁よりも小さい」というような連続する数字のペアはありません)。
ベン・リー

3
:@TMN:あなたは8の左に9を移動したいので9は、8よりも大きい場合9 832:9の右に、その後のソートすべて9238
BlueRaja -ダニーPflughoeft

4
あなたが変更する必要があります動作するようにあなたのソリューションのための@Kent 4より大きい最小の桁見つけるにする4より大きい最小の桁見つける権利を。それ以外の場合、たとえば、1234567849876 55 4321は1234567851234 54 6789(1234567851234 45 6789 ではなく)になります。nitpick :-)
osundblad

94

ほぼ同一の問題がCode Jamの問題として表示され、ここに解決策があります:

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

次に、例を使用したメソッドの概要を示します。

34722641

A.数字のシーケンスを2つに分割し、右の部分が可能な限り長くなるようにします。

34722 641

(数値全体が降順の場合、数字を追加しない限り、大きな数値を作成することはできません。)

B.1。最初のシーケンスの最後の桁を選択します。

3472(2) 641

B.2。それよりも大きい2番目のシーケンスの最小桁を見つけます。

3472(2) 6(4)1

B.3。それらを交換してください:

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

C. 2番目のシーケンスを昇順でソートします。

34724 126

D.できました!

34724126

1
入力ミス:「-> 34721 621」は「-> 34724 621」である必要があると思いますか?
bjnord

1
@bjnord良いキャッチ。修繕。どうやってそれを管理したのかわからない-それは次の行で正しかった。
Weeble

+1ベストアンサーはこちら。直感的で高速。(これは私がこれを紙で作成したときに私が考えたものでもあります;))
Muhd '13 / 07/13

1
@Neel-ステップCでは、ソートしたい数字は降順です。ただし、ステップBで入れ替えた数字は除きます。実際に並べ替えるには、逆にして入れ替えた数字を正しい位置に入れるだけです。これがBlueRajaの説明です。
Weeble 2013

1
@Dhavaldave問題は何ですか?ステップAでは、「12」と「3」を取得します。ステップBでは、「13」と「2」を取得します。ステップCでは何も変化しません。ステップDでは、「132」を取得します。答えが得られない唯一のケースは、数値がすでに可能な最大値である場合です(例: "321")。その場合、ステップAで「」と「321」が表示され、スプリットの左側で空のシーケンスを続行することはできません。
Weeble 2013

14

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://stackoverflow.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)))))

誰かがこれを更新できる可能性はありますか?それが示すように、Python 3では動作しないようですtype 'map' has no len()。2行目をに変更しiis=list(map(int,str(ii)))ます。そして、誰かがif i == 0: return iiラインを説明できますか?111や531などの入力で動作するのはなぜですか?ありがとう。
Bowen Liu

python 3で「list()をiis = ...」に追加して修正しました。ケース111と531には解決策はありませんが、私の実装はそれらに対して111と531を返します。あなたはそれをあなたが見つけたものの例外に変更することができます。
Johan Lundberg、

ありがとう。私は実際には他の方向にループするので、i == 0で混乱しましたが、私の状況ではそうなりますi == len(iis)
ボーウェン・リウ

8

少なくとも、ブルートフォースの文字列ベースのソリューションの例をいくつか示します。頭上からすぐに思いつくはずです。

38276ソートされた数字のリストは23678

38627ソートされた数字のリストは23678

ブルートフォースインクリメント、並べ替え、比較

ブルートフォースソリューションに沿って文字列に変換され、それらの数字を使用してすべての可能な数値がブルートフォースになります。

それらすべてからintを作成し、リストに入れてソートし、ターゲットエントリの次のエントリを取得します。

あなたがこれに30分を費やし、少なくともブルートフォースアプローチを思い付かなかったとしたら、私もあなたを雇わないでしょう。

ビジネスの世界では、洗練されておらず、遅くて不格好なソリューションですが、仕事を成し遂げるソリューションは、ソリューションがないよりも常に価値があります。実際、すべてのビジネスソフトウェアは、洗練されていない、不格好なものです。


1
さて、私の最初のコメントは、「私はそれを強引に強制することはできましたが...」でした。本当にアルゴリズムの解決策がない場合、私は一種失望のだ
BHAN

4
私がインタビュアーだったら、力ずくのアプローチにはあまり満足しません。
アハマドY.サレー

@benjamin han、アルゴリズムによる解決策があります。結果が見つかるまで、数字を右から順番に入れ替えてください。以前にすべての順列を計算する必要はありません。
dantuch 2012

7
確かにブルートフォース、例えばよりもはるかに良い解決策がありますardendertat.com/2012/01/02/...
BrokenGlass

@BrokenGlass間違いなくはるかに優れたソリューション。私はそのアイデアを思いついたばかりで、アルゴリズムを投稿しました。
onit

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

私はこの解決策を思いつきました。ご不明な点がございましたら、お問い合わせください。
Ashikodi

4

あなたの案

まず、1桁よりも小さい最初の桁(右から)のインデックスを見つけることから始めました。次に、サブセットの最後の数字を同じ数字で構成される次に大きい数字になるようにローテーションしましたが、行き詰まりました。

実際にはかなり良いです。最後の数字だけでなく、現在考えられているよりも重要度の低いすべての数字を考慮する必要があります。それが到達する前から、私たちは数字の単調なシーケンスを持っています、それはその右隣よりも小さい右端の数字です。よろしく

1234675
    ^

同じ数字を持つ次に大きい数は

1234756

見つかった数字は最後の数字(考慮される数字の最小の数字)に交換され、残りの数字は昇順で配置されます。


4

あなたのインタビュアーが次のようなことに向かってあなたをそっと押し付けようとしていたと私はかなり確信しています:

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);

必ずしも最も効率的またはエレガントなソリューションではありませんが、提供された例を2サイクルで解決し、彼が提案したように一度に1つずつ桁を交換します。


2

数を取り、それを数字に分割します。したがって、5桁の数字の場合、5桁になります:abcde

ここでdとeを入れ替えて元の数値と比較します。それが大きい場合は、答えがあります。

大きくない場合は、eとcを入れ替えます。比較して、それがより小さいスワップdとeである場合(再帰に注意)、最小値を取ります。

大きな数が見つかるまで続けます。再帰を使用すると、約9行のスキーム、または20行のc#として機能します。


2

それは非常に興味深い質問です。

これが私のJavaバージョンです。他の寄稿者のコメントを確認する前に、パターンを理解してコードを完全に完了するまで約3時間かかります。私の考えが他の人とまったく同じであることをうれしく思います。

O(n)ソリューション。正直なところ、時間が15分しかなく、ホワイトボードで完全なコード仕上げが必要な場合は、このインタビューに失敗します。

ここに私の解決策のいくつかの興味深いポイントがあります:

  • 並べ替えは避けてください。
  • 文字列操作を完全に回避する
  • O(logN)スペースの複雑さを実現

私はコードに詳細なコメントを入れ、Big Oを各ステップに入れました。

  public int findNextBiggestNumber(int input  )   {
    //take 1358642 as input for example.
    //Step 1: split the whole number to a list for individual digital   1358642->[2,4,6,8,5,3,1]
    // this step is O(n)
    int digitalLevel=input;

    List<Integer> orgNumbersList=new ArrayList<Integer>()   ;

    do {
        Integer nInt = new Integer(digitalLevel % 10);
        orgNumbersList.add(nInt);

        digitalLevel=(int) (digitalLevel/10  )  ;


    } while( digitalLevel >0)    ;
    int len= orgNumbersList.size();
    int [] orgNumbers=new int[len]  ;
    for(int i=0;i<len;i++){
        orgNumbers[i ]  =  orgNumbersList.get(i).intValue();
    }
    //step 2 find the first digital less than the digital right to it
    // this step is O(n)


    int firstLessPointer=1;
    while(firstLessPointer<len&&(orgNumbers[firstLessPointer]>orgNumbers[ firstLessPointer-1 ])){
        firstLessPointer++;
    }
     if(firstLessPointer==len-1&&orgNumbers[len-1]>=orgNumbers[len-2]){
         //all number is in sorted order like 4321, no answer for it, return original
         return input;
     }

    //when step 2 step finished, firstLessPointer  pointing to number 5

     //step 3 fristLessPointer found, need to find  to  first number less than it  from low digital in the number
    //This step is O(n)
    int justBiggerPointer=  0 ;

    while(justBiggerPointer<firstLessPointer&& orgNumbers[justBiggerPointer]<orgNumbers[firstLessPointer]){
        justBiggerPointer++;
    }
    //when step 3 finished, justBiggerPointer  pointing to 6

    //step 4 swap the elements  of justBiggerPointer and firstLessPointer .
    // This  is O(1) operation   for swap

   int tmp=  orgNumbers[firstLessPointer] ;

    orgNumbers[firstLessPointer]=  orgNumbers[justBiggerPointer]  ;
     orgNumbers[justBiggerPointer]=tmp ;


     // when step 4 finished, the list looks like        [2,4,5,8,6,3,1]    the digital in the list before
     // firstLessPointer is already sorted in our previous operation
     // we can return result from this list  but  in a differrent way
    int result=0;
    int i=0;
    int lowPointer=firstLessPointer;
    //the following pick number from list from  the position just before firstLessPointer, here is 8 -> 5 -> 4 -> 2
    //This Operation is O(n)
    while(lowPointer>0)        {
        result+= orgNumbers[--lowPointer]* Math.pow(10,i);
        i++;
    }
    //the following pick number from list   from position firstLessPointer
    //This Operation is O(n)
    while(firstLessPointer<len)        {
        result+= orgNumbers[firstLessPointer++ ]* Math.pow(10,i);
        i++;
    }
     return  result;

}

Intelljで実行した結果は次のとおりです。

959879532-->959892357
1358642-->1362458
1234567-->1234576
77654321-->77654321
38276-->38627
47-->74

ケース123の場合、何が答えになりますか?それは132を来るSHOLDしながら、実際にu'llコードが出力を生成しません
Dhavalデイブ

2

@BlueRajaのアルゴリズムのJavaScript実装。

var Bar = function(num){ 
  num = num.toString();
  var max = 0;
  for(var i=num.length-2; i>0; i--){
    var numArray = num.substr(i).split("");
    max = Math.max.apply(Math,numArray);
    if(numArray[0]<max){
        numArray.sort(function(a,b){return a-b;});
        numArray.splice(-1);
        numArray = numArray.join("");
        return Number(num.substr(0,i)+max+numArray);
    }
  }
  return -1;
};

1

解決策(Javaの場合)は次のようになります(ここにいる友達がもっと良い方法を見つけることができると思います):
数字が大きくなるまで、文字列の末尾から数字を入れ替えます。
つまり、最初に下の桁を上に移動し始めます。次に、次の高い数字をヒットするまで、次の高い数字などを移動します。
次に残りを並べ替えます。あなたの例では次のようになります:

38276 --> 38267 (smaller) --> 38627 Found it    
    ^        ^                  ^        

 public static int nextDigit(int number){
    String num = String.valueOf(number);        
    int stop = 0;       
    char [] chars = null;
    outer:
        for(int i = num.length() - 1; i > 0; i--){          
            chars = num.toCharArray();
            for(int j = i; j > 0; j--){
                char temp = chars[j];
                chars[j] = chars[j - 1];
                chars[j - 1] = temp;
                if(Integer.valueOf(new String(chars)) > number){
                    stop = j;                   
                    break outer;                                
                }               
            }               
        }

    Arrays.sort(chars, stop, chars.length); 
    return Integer.valueOf(new String(chars));
}

@yi_H:出力は63872.Why、それは何であるべきですか?
Cratylus

さて..次の高い数字?:)それが要件でしたね。
Karoly Horvath

@BlueRaja-Danny Pflughoeft:ありがとうございます。コードを次のように変更しました:最小桁を前に移動し(これにより高い数値が得られます)、残りを並べ替えます
Cratylus

1

C ++でプログラミングしている場合は、以下を使用できますnext_permutation

#include <algorithm>
#include <string>
#include <iostream>

int main(int argc, char **argv) {
  using namespace std; 
   string x;
   while (cin >> x) {
    cout << x << " -> ";
    next_permutation(x.begin(),x.end());
    cout << x << "\n";
  }
  return 0;
}

入力するとどうなります100か?:-)
jweyrich 2013年

1

この質問に答えるとき、ブルートフォースアルゴリズムについて何も知りませんでしたので、別の角度からアプローチしました。私は、number_given + 1から使用可能な最大数(3桁の数値の場合は999、4桁の場合は9999など)まで、この数値を再配置できる可能性のあるソリューション全体を検索することにしました。私は、各解の数をソートし、それをパラメーターとして与えられたソートされた数と比較することで、言葉でパリンドロームを見つけるようなこのようなことをしました。次に、ソリューションの配列の最初のソリューションを返しました。これが次の可能な値になるためです。

Rubyのコードは次のとおりです。

def PermutationStep(num)

    a = []
    (num.to_s.length).times { a.push("9") }
    max_num = a.join('').to_i
    verify = num.to_s.split('').sort
    matches = ((num+1)..max_num).select {|n| n.to_s.split('').sort == verify }

    if matches.length < 1
      return -1
    else
      matches[0]
    end
end

このソリューションの時間の複雑さは何ですか?
Nitish Upreti 2014

@ Myth17私はそれをテストしたことがないので、私にはわかりません。あなたががそれを把握したい場合は、この記事をチェックアウト:stackoverflow.com/questions/9958299/...
エレミヤマッカーディ

1

PHPコード

function NextHigherNumber($num1){
$num = strval($num1);
$max = 0;
for($i=(strlen($num)-2); $i>=0; $i--){
    $numArrayRaw = substr($num, $i);
    $numArray = str_split($numArrayRaw);
    $max = max($numArray);
    if ($numArray[0] < $max){
        sort( $numArray, SORT_NUMERIC );
        array_pop($numArray);
        $numarrstr = implode("",$numArray);
        $rt = substr($num,0,$i) . $max . $numarrstr;
        return $rt;
    }
}
return "-1";
}
echo NextHigherNumber(123);

0

私はこれを2つの数値でテストしただけです。彼らが働いていました。昨年12月に退職するまで8年間ITマネージャーとして、私は3つのことを気にしました:1)正確さ:それがうまくいけば、それは常に良いことです。2)速度:ユーザーが許容できる必要があります。3)明快さ:私はあなたほど賢くないかもしれませんが、私はあなたに支払っています。何をしているかを英語で説明してください。

オマール、今後の幸運を祈ります。

Sub Main()

Dim Base(0 To 9) As Long
Dim Test(0 To 9) As Long

Dim i As Long
Dim j As Long
Dim k As Long
Dim ctr As Long

Const x As Long = 776914648
Dim y As Long
Dim z As Long

Dim flag As Boolean

' Store the digit count for the original number in the Base vector.
    For i = 0 To 9
        ctr = 0
        For j = 1 To Len(CStr(x))
            If Mid$(CStr(x), j, 1) = i Then ctr = ctr + 1
        Next j
        Base(i) = ctr
    Next i

' Start comparing from the next highest number.
    y = x + 1
    Do

' Store the digit count for the each new number in the Test vector.
        flag = False
        For i = 0 To 9
            ctr = 0
            For j = 1 To Len(CStr(y))
                If Mid$(CStr(y), j, 1) = i Then ctr = ctr + 1
            Next j
            Test(i) = ctr
        Next i

' Compare the digit counts.
        For k = 0 To 9
            If Test(k) <> Base(k) Then flag = True
        Next k

' If no match, INC and repeat.
        If flag = True Then
            y = y + 1
            Erase Test()
        Else
            z = y ' Match.
        End If

    Loop Until z > 0

    MsgBox (z), , "Solution"

End Sub


0

これが私のコードです、これはこの例の修正版です

図書館:

class NumPermExample
{
    // print N! permutation of the characters of the string s (in order)
    public  static void perm1(String s, ArrayList<String> perm)
    {
        perm1("", s);
    }

    private static void perm1(String prefix, String s, ArrayList<String> perm)
    {
        int N = s.length();
        if (N == 0)
        {
            System.out.println(prefix);
            perm.add(prefix);
        }
        else
        {
            for (int i = 0; i < N; i++)
                perm1(prefix + s.charAt(i), s.substring(0, i)
                    + s.substring(i+1, N));
        }

    }

    // print N! permutation of the elements of array a (not in order)
    public static void perm2(String s, ArrayList<String> perm)
    {
       int N = s.length();
       char[] a = new char[N];
       for (int i = 0; i < N; i++)
           a[i] = s.charAt(i);
       perm2(a, N);
    }

    private static void perm2(char[] a, int n, ArrayList<String> perm)
    {
        if (n == 1)
        {
            System.out.println(a);
            perm.add(new String(a));
            return;
        }

        for (int i = 0; i < n; i++)
        {
            swap(a, i, n-1);
            perm2(a, n-1);
            swap(a, i, n-1);
        }
    }  

    // swap the characters at indices i and j
    private static void swap(char[] a, int i, int j)
    {
        char c;
        c = a[i]; a[i] = a[j]; a[j] = c;
    }

    // next higher permutation
    public static int nextPermutation (int number)
    {
        ArrayList<String> perm = new ArrayList<String>();

        String cur = ""+number;

        int nextPerm = 0;

        perm1(cur, perm);

        for (String s : perm)
        {
            if (Integer.parseInt(s) > number
                        && (nextPerm == 0 ||
                            Integer.parseInt(s) < nextPerm))
            {
                nextPerm = Integer.parseInt(s);
            }
        }

            return nextPerm;
    }
}

テスト:

public static void main(String[] args) 
{
    int a = 38276;

    int b = NumPermExample.nextPermutation(a);

    System.out.println("a: "+a+", b: "+b);
}

0

指定されたn桁の数字に9を追加します。次に、それが制限(最初の(n + 1)桁の数字)内にあるかどうかを確認します。そうである場合は、新しい番号の数字が元の番号の数字と同じかどうかを確認します。両方の条件が満たされるまで、9の追加を繰り返します。数が制限を超えたら、アルゴを停止します。

この方法では、矛盾するテストケースを思い付くことができませんでした。


1
それは機能しますが、非常にゆっくりです。これは、これを線形時間で解くことができる指数時間アルゴリズムです。
インタージェイ2013年

0

Pythonを使用した別のソリューション:

def PermutationStep(num):
    if sorted(list(str(num)), reverse=True) == list(str(num)):
        return -1
    ls = list(str(num))
    n = 0
    inx = 0
    for ind, i in enumerate(ls[::-1]):
        if i < n:
            n = i
            inx = -(ind + 1)
            break
        n = i
    ls[inx], ls[inx + 1] = ls[inx + 1], ls[inx]

    nl = ls[inx::-1][::-1]
    ln = sorted(ls[inx+1:])
    return ''.join(nl) + ''.join(ln)

print PermutationStep(23514)

出力:

23541

0
public static void findNext(long number){

        /* convert long to string builder */    

        StringBuilder s = new StringBuilder();
        s.append(number);
        int N = s.length();
        int index=-1,pivot=-1;

/* from tens position find the number (called pivot) less than the number in right */ 

        for(int i=N-2;i>=0;i--){

             int a = s.charAt(i)-'0';
             int b = s.charAt(i+1)-'0';

             if(a<b){
                pivot = a;
                index =i;
                break;
            }
        }

      /* if no such pivot then no solution */   

        if(pivot==-1) System.out.println(" No such number ")

        else{   

     /* find the minimum highest number to the right higher than the pivot */

            int nextHighest=Integer.MAX_VALUE, swapIndex=-1;

            for(int i=index+1;i<N;i++){

            int a = s.charAt(i)-'0';

            if(a>pivot && a<nextHighest){
                    nextHighest = a;
                    swapIndex=i;
                }
            }


     /* swap the pivot and next highest number */

            s.replace(index,index+1,""+nextHighest);
            s.replace(swapIndex,swapIndex+1,""+pivot);

/* sort everything to right of pivot and replace the sorted answer to right of pivot */

            char [] sort = s.substring(index+1).toCharArray();
            Arrays.sort(sort);

            s.replace(index+1,N,String.copyValueOf(sort));

            System.out.println("next highest number is "+s);
        }

    }

0

以下は、数値のすべての順列を生成するコードです。最初にString.valueOf(integer)を使用して、その整数を文字列に変換する必要があります。

/**
 * 
 * Inserts a integer at any index around string.
 * 
 * @param number
 * @param position
 * @param item
 * @return
 */
public String insertToNumberStringAtPosition(String number, int position,
        int item) {
    String temp = null;
    if (position >= number.length()) {
        temp = number + item;
    } else {
        temp = number.substring(0, position) + item
                + number.substring(position, number.length());
    }
    return temp;
}

/**
 * To generate permutations of a number.
 * 
 * @param number
 * @return
 */
public List<String> permuteNumber(String number) {
    List<String> permutations = new ArrayList<String>();
    if (number.length() == 1) {
        permutations.add(number);
        return permutations;
    }
    // else
    int inserterDig = (int) (number.charAt(0) - '0');
    Iterator<String> iterator = permuteNumber(number.substring(1))
            .iterator();
    while (iterator.hasNext()) {
        String subPerm = iterator.next();
        for (int dig = 0; dig <= subPerm.length(); dig++) {
            permutations.add(insertToNumberStringAtPosition(subPerm, dig,
                    inserterDig));
        }
    }
    return permutations;
}

0
#include<bits/stdc++.h>
using namespace std;
int main() 
{
    int i,j,k,min,len,diff,z,u=0,f=0,flag=0;
    char temp[100],a[100]`enter code here`,n;
    min=9999;
    //cout<<"Enter the number\n";
    cin>>a;
    len=strlen(a);
    for(i=0;i<len;i++)
    {
        if(a[i]<a[i+1]){flag=1;break;}
    }
    if(flag==0){cout<<a<<endl;}
    else
    {
        for(i=len-1;i>=0;i--)if(((int)a[i-1])<((int)a[i]))break;
        for(k=0;k<i-1;k++)cout<<a[k];
        for(j=i;j<len;j++)
        {
            if(((int)a[j]-48)-((int)a[i-1]-48)>0)
            {
                diff=((int)a[j]-48)-((int)a[i-1]-48);
                if(diff<min){n=a[j];min=diff;}
            }
        }
        cout<<n;
        for(z=i-1;z<len;z++)
        {
            temp[u]=a[z];
            u++;
        }
        temp[u]='\0';
        sort(temp,temp+strlen(temp));
        for(z=0;z<strlen(temp);z++){if(temp[z]==n&&f==0){f=1;continue;}cout<<temp[z];}
    }
    return 0;
}

0

さらに別のJava実装で、そのまま実行でき、テストを完了します。このソリューションは、古き良き動的プログラミングを使用したO(n)の空間と時間です。

ブルートフォースが必要な場合、2種類のブルートフォースがあります。

  1. すべてのものを並べ替え、次にminを高くする:O(n!)

  2. この実装に似ていますが、DPの代わりに、indexToIndexOfNextSmallerLeftマップを設定するステップをブルートフォーシングすると、O(n ^ 2)で実行されます。


import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class NextHigherSameDigits {

    public long next(final long num) {
        final char[] chars = String.valueOf(num).toCharArray();
        final int[] digits = new int[chars.length];
        for (int i = 0; i < chars.length; i++) {
            digits[i] = Character.getNumericValue(chars[i]);
        }

        final Map<Integer, Integer> indexToIndexOfNextSmallerLeft = new HashMap<>();
        indexToIndexOfNextSmallerLeft.put(1, digits[1] > digits[0] ? 0 : null);
        for (int i = 2; i < digits.length; i++) {
            final int left = digits[i - 1];
            final int current = digits[i];
            Integer indexOfNextSmallerLeft = null;
            if (current > left) {
                indexOfNextSmallerLeft = i - 1;
            } else {
                final Integer indexOfnextSmallerLeftOfLeft = indexToIndexOfNextSmallerLeft.get(i - 1);
                final Integer nextSmallerLeftOfLeft = indexOfnextSmallerLeftOfLeft == null ? null : 
                    digits[indexOfnextSmallerLeftOfLeft];

                if (nextSmallerLeftOfLeft != null && current > nextSmallerLeftOfLeft) {
                    indexOfNextSmallerLeft = indexOfnextSmallerLeftOfLeft;
                } else {
                    indexOfNextSmallerLeft = null;
                }
            }

            indexToIndexOfNextSmallerLeft.put(i, indexOfNextSmallerLeft);
        }

        Integer maxOfindexOfNextSmallerLeft = null;
        Integer indexOfMinToSwapWithNextSmallerLeft = null;
        for (int i = digits.length - 1; i >= 1; i--) {
            final Integer indexOfNextSmallerLeft = indexToIndexOfNextSmallerLeft.get(i);
            if (maxOfindexOfNextSmallerLeft == null ||
                    (indexOfNextSmallerLeft != null && indexOfNextSmallerLeft > maxOfindexOfNextSmallerLeft)) {

                maxOfindexOfNextSmallerLeft = indexOfNextSmallerLeft;
                if (maxOfindexOfNextSmallerLeft != null && (indexOfMinToSwapWithNextSmallerLeft == null || 
                        digits[i] < digits[indexOfMinToSwapWithNextSmallerLeft])) {

                    indexOfMinToSwapWithNextSmallerLeft = i;
                }
            }
        }

        if (maxOfindexOfNextSmallerLeft == null) {
            return -1;
        } else {
            swap(digits, indexOfMinToSwapWithNextSmallerLeft, maxOfindexOfNextSmallerLeft);
            reverseRemainingOfArray(digits, maxOfindexOfNextSmallerLeft + 1);
            return backToLong(digits);
        }
    }

    private void reverseRemainingOfArray(final int[] digits, final int startIndex) {
        final int[] tail = Arrays.copyOfRange(digits, startIndex, digits.length);
        for (int i = tail.length - 1; i >= 0; i--) {
            digits[(digits.length - 1)  - i] = tail[i];                 
        }
    }

    private void swap(final int[] digits, final int currentIndex, final int indexOfNextSmallerLeft) {
        int temp = digits[currentIndex];
        digits[currentIndex] = digits[indexOfNextSmallerLeft];
        digits[indexOfNextSmallerLeft] = temp;
    }

    private long backToLong(int[] digits) {     
        StringBuilder sb = new StringBuilder();
        for (long i : digits) {
            sb.append(String.valueOf(i));
        }

        return Long.parseLong(sb.toString());
    }

    @Test
    public void test() {
        final long input1 =    34722641;
        final long expected1 = 34724126;
        final long output1 = new NextHigherSameDigits().next(input1);
        assertEquals(expected1, output1);

        final long input2 =    38276;
        final long expected2 = 38627;
        final long output2 = new NextHigherSameDigits().next(input2);
        assertEquals(expected2, output2);

        final long input3 =    54321;
        final long expected3 = -1;
        final long output3 = new NextHigherSameDigits().next(input3);
        assertEquals(expected3, output3);

        final long input4 =    123456784987654321L;
        final long expected4 = 123456785123446789L;
        final long output4 = new NextHigherSameDigits().next(input4);
        assertEquals(expected4, output4);

        final long input5 =    9999;
        final long expected5 = -1;
        final long output5 = new NextHigherSameDigits().next(input5);
        assertEquals(expected5, output5);
    }

}

0

最も右側のビット0に続いて1を見つけ、この最も右側のビット0を1に反転する必要があります。

たとえば、入力が487、つまりバイナリで111100111であるとします。

私たちはそれに続く1を持つ最も右の0を反転します

111101111を取得します

しかし、1が増えて0が1つ減ったので、フリップビットの右側にある1の数を1減らし、0ビットの数を1増やします。

111101011-バイナリ491

int getNextNumber(int input)
{
    int flipPosition=0;
    int trailingZeros=0;
    int trailingOnes=0;
    int copy = input;

    //count trailing zeros
    while(copy != 0 && (copy&1) == 0 )
    {
        ++trailingZeros;

        //test next bit
        copy = copy >> 1;
    }

    //count trailing ones
    while(copy != 0 && (copy&1) == 1 )
    {
        ++trailingOnes;

        //test next bit
        copy = copy >> 1;
    }

    //if we have no 1's (i.e input is 0) we cannot form another pattern with 
    //the same number of 1's which will increment the input, or if we have leading consecutive
    //ones followed by consecutive 0's up to the maximum bit size of a int
    //we cannot increase the input whilst preserving the original no of 0's and
    //1's in the bit pattern
    if(trailingZeros + trailingOnes  == 0 || trailingZeros + trailingOnes == 31)
        return -1;

    //flip first 0 followed by a 1 found from the right of the bit pattern
    flipPosition = trailingZeros + trailingOnes+1;
    input |= 1<<(trailingZeros+trailingOnes);

    //clear fields to the right of the flip position
    int mask = ~0 << (trailingZeros+trailingOnes);
    input &= mask;

    //insert a bit pattern to the right of the flip position that will contain
    //one less 1 to compensate for the bit we switched from 0 to 1
    int insert = flipPosition-1;
    input |= insert;

    return input;
}

0
int t,k,num3,num5;
scanf("%d",&t);
int num[t];
for(int i=0;i<t;i++){
    scanf("%d",&num[i]);   
}
for(int i=0;i<t;i++){
    k=(((num[i]-1)/3)+1); 
    if(k<0)
        printf("-1");
    else if(num[i]<3 || num[i]==4 || num[i]==7)
        printf("-1");
    else{
        num3=3*(2*num[i] - 5*k);
        num5=5*(3*k -num[i]);
        for(int j=0;j<num3;j++)
            printf("5");
        for(int j=0;j<num5;j++)
            printf("3");
    }
    printf("\n");
}

0

ここにJava実装があります

public static int nextHigherNumber(int number) {
    Integer[] array = convertToArray(number);
    int pivotIndex = pivotMaxIndex(array);
    int digitInFirstSequence = pivotIndex -1;
    int lowerDigitIndexInSecondSequence = lowerDigitIndex(array[digitInFirstSequence], array, pivotIndex);
    swap(array, digitInFirstSequence, lowerDigitIndexInSecondSequence);
    doRercursiveQuickSort(array, pivotIndex, array.length - 1);
    return arrayToInteger(array);
}

public static Integer[] convertToArray(int number) {
    int i = 0;
    int length = (int) Math.log10(number);
    int divisor = (int) Math.pow(10, length);
    Integer temp[] = new Integer[length + 1];

    while (number != 0) {
        temp[i] = number / divisor;
        if (i < length) {
            ++i;
        }
        number = number % divisor;
        if (i != 0) {
            divisor = divisor / 10;
        }
    }
    return temp;
}

private static int pivotMaxIndex(Integer[] array) {
    int index = array.length - 1;
    while(index > 0) {
        if (array[index-1] < array[index]) {
            break;
        }
        index--;
    }       
    return index;
}

private static int lowerDigitIndex(int number, Integer[] array, int fromIndex) {
    int lowerMaxIndex = fromIndex;
    int lowerMax = array[lowerMaxIndex];
    while (fromIndex < array.length - 1) {
        if (array[fromIndex]> number && lowerMax > array[fromIndex]) {
            lowerMaxIndex = fromIndex; 
        }
        fromIndex ++;
    }
    return lowerMaxIndex;
}

public static int arrayToInteger(Integer[] array) {
    int number = 0;
    for (int i = 0; i < array.length; i++) {
        number+=array[i] * Math.pow(10, array.length-1-i);
    }
    return number;
}

これがユニットテストです

@Test
public void nextHigherNumberTest() {
    assertThat(ArrayUtils.nextHigherNumber(34722641), is(34724126));
    assertThat(ArrayUtils.nextHigherNumber(123), is(132));
}

0

これは非常に古い質問であることはわかっていますが、それでもc#で簡単なコードを見つけることができませんでした。これはインタビューに参加している人を助けるかもしれません。

class Program
{
    static void Main(string[] args)
    {

        int inputNumber = 629;
        int i, currentIndexOfNewArray = 0;

        int[] arrayOfInput = GetIntArray(inputNumber);
        var numList = arrayOfInput.ToList();

        int[] newArray = new int[arrayOfInput.Length];

        do
        {
            int temp = 0;
            int digitFoundAt = 0;
            for (i = numList.Count; i > 0; i--)
            {
                if (numList[i - 1] > temp)
                {
                    temp = numList[i - 1];
                    digitFoundAt = i - 1;
                }
            }

            newArray[currentIndexOfNewArray] = temp;
            currentIndexOfNewArray++;
            numList.RemoveAt(digitFoundAt);
        } while (arrayOfInput.Length > currentIndexOfNewArray);



        Console.WriteLine(GetWholeNumber(newArray));

        Console.ReadKey();


    }

    public static int[] GetIntArray(int num)
    {
        IList<int> listOfInts = new List<int>();
        while (num > 0)
        {
            listOfInts.Add(num % 10);
            num = num / 10;
        }
        listOfInts.Reverse();
        return listOfInts.ToArray();
    }

    public static double GetWholeNumber(int[] arrayNumber)
    {
        double result = 0;
        double multiplier = 0;
        var length = arrayNumber.Count() - 1;
        for(int i = 0; i < arrayNumber.Count(); i++)
        {
            multiplier = Math.Pow(10.0, Convert.ToDouble(length));
            result += (arrayNumber[i] * multiplier);
            length = length - 1;
        }

        return result;
    }
}

0

Javascriptを使用した非常にシンプルな実装で、同じ数字の次に大きい数字

/*
Algorithm applied
I) Traverse the given number from rightmost digit, keep traversing till you find a digit which is smaller than the previously traversed digit. For example, if the input number is “534976”, we stop at 4 because 4 is smaller than next digit 9. If we do not find such a digit, then output is “Not Possible”.

II) Now search the right side of above found digit ‘d’ for the smallest digit greater than ‘d’. For “534976″, the right side of 4 contains “976”. The smallest digit greater than 4 is 6.

III) Swap the above found two digits, we get 536974 in above example.

IV) Now sort all digits from position next to ‘d’ to the end of number. The number that we get after sorting is the output. For above example, we sort digits in bold 536974. We get “536479” which is the next greater number for input 534976.

*/

function findNext(arr)
{
  let i;
  //breaking down a digit into arrays of string and then converting back that array to number array
  let arr1=arr.toString().split('').map(Number) ;
  //started to loop from the end of array 
  for(i=arr1.length;i>0;i--)
  {
    //looking for if the current number is greater than the number next to it
    if(arr1[i]>arr1[i-1])
    {// if yes then we break the loop it so that we can swap and sort
      break;}
  }

  if(i==0)
  {console.log("Not possible");}

   else
  {
   //saving that big number and smaller number to the left of it
   let smlNum =arr1[i-1];
    let bigNum =i;
   /*now looping again and checking if we have any other greater number, if we have one AFTER big number and smaller number to the right. 
     A greater number that is of course greater than that smaller number but smaller than the first number we found.
     Why are doing this? Because that is an algorithm to find next higher number with same digits. 
   */
    for(let j=i+1;j<arr1.length;j++)
      {//What if there are no digits afters those found numbers then of course loop will not be initiated otherwise...
        if(arr1[j]> smlNum && arr1[j]<arr1[i])
        {// we assign that other found number here and replace it with the one we found before
          bigNum=j;

        }
      } //now we are doing swapping of places the small num and big number , 3rd part of alogorithm
    arr1[i-1]=arr1[bigNum];
          arr1[bigNum]=smlNum;
    //returning array 
    //too many functions applied sounds complicated right but no, here is the  trick
    //return arr first then apply each function one by one to see output and then further another func to that output to match your needs
    // so here after swapping , 4th part of alogorithm is to sort the array right after the 1st small num we found
    // to do that first we simple take part of array, we splice it and then we apply sort fucntion, then check output (to check outputs, pls use chrome dev console)
    //and then  simply the rest concat and join to main one digit again.
     return arr1.concat((arr1.splice(i,arr1.length)).sort(function(a, b){return a-b})).join('');



    // Sorry to make it too long but its fun explaining things in much easier ways as much as possible!!
  }

}


findNext(1234);

コメントがたくさんあるので、テキストエディターにコピーできる方がいいです。ありがとう!


0

良い答えはたくさんありますが、適切なJava実装は見つかりませんでした。これが私の2セントです。

public void findNext(int[] nums) {
    int i = nums.length - 1;
    // nums[i - 1] will be the first non increasing number
    while (i > 0 && nums[i] <= nums[i - 1]) {
        i--;
    }
    if (i == 0) {
        System.out.println("it has been the greatest already");
    } else {
        // Find the smallest digit in the second sequence that is larger than it:
        int j = nums.length - 1;
        while (j >= 0 && nums[j] < nums[i - 1]) {
            j--;
        }
        swap(nums, i - 1, j);
        Arrays.sort(nums, i, nums.length);
        System.out.println(Arrays.toString(nums));
    }
}

public void swap(int[] nums, int i, int j) {
    int tmp = nums[i];
    nums[i] = nums[j];
    nums[j] = tmp;
}

0
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<string.h>
#include<sstream>
#include<iostream>

using namespace std;
int compare (const void * a, const void * b)
{
    return *(char*)a-*(char*)b;
}

/*-----------------------------------------------*/

int main()
{
    char number[200],temp;
    cout<<"please enter your number?"<<endl;
    gets(number);
    int n=strlen(number),length;
    length=n;
    while(--n>0)
    {
        if(number[n-1]<number[n])
        {
            for(int i=length-1;i>=n;i--)
            {
                if(number[i]>number[n-1])
                {
                    temp=number[i];
                    number[i]=number[n-1];
                    number[n-1]=temp;
                    break;
                }
            }
            qsort(number+n,length-n,sizeof(char),compare);
            puts(number); 
            return 0;
        }
    }
    cout<<"sorry itz the greatest one :)"<<endl;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.