序文
Web開発に携わって以来、アルゴリズム関連の知識をほとんど学んだことがなかったのですが、今日は再帰や二分探索などの基本的なアルゴリズムについて下調べをして、感想を書いてみました。このブログを参考にして相互交流してください!
1. 再帰的アルゴリズム
例 1: フィボナッチ数列を再帰的に見つける
const readline = require("readline"); const rl = readline.createInterface({ 入力: process.stdin, 出力: process.stdout, }); /* 输入要求第几位 */ rl.on("line", function (line) { let num = Number(line); const test = (a) => { if (a === 1 || a = == 2) 1 を返す; テスト(a - 1) + テスト(a - 2); }; console.log(test(num)); });
再帰的思考:
1. 一般的なソリューション テンプレートを見つけて、このテンプレートを継続的に呼び出します (自分自身を呼び出します)。
2. このテンプレートは呼び出され続ける過程で解けるわけではありませんが、解けない問題はスタックに蓄積され続けるため、必ず問題を解ける正確な値が見つかるポイントが存在し、未解決の問題があればすぐにポストバックされます
注意点:
1. 再帰の考え方は非常に抽象的であり、コードを見ただけで最終的な計算結果を見ることは基本的に不可能であり、抽象的な思考が必要となります。
2. 共通のテンプレートが記述されていれば、次の再帰呼び出しは自発的に実行され、最終的には「山が重くて川が重くなったら逃げ道はない」と言える妥当な結果が得られます。は疑問でいっぱいですが、そこには黒い柳と花が咲く別の村があります。」
3. 再帰メソッドで記述されているのはテンプレートだけであり、このテンプレートはマクロ的には結果を直接出力「できる」が、抽象的な「できる」にすぎない。
例えば、n の階乗を n + n-1 の階乗に分解する、このような全体的な分割の考え方が必要です。
別の例として、フィボナッチ数列の各項目が最初の 2 つの項目の合計である場合、再帰テンプレートは最初の 2 つの項目の合計になります。
4. 再帰アルゴリズムには if(){return} が必要です。これはプログラムによって発見されたブレークスルー ポイントであるだけでなく、スタックがオーバーフローしないようにするために必要な操作でもあります。
5. 再帰的シーンをシミュレートするには、まず少量のコンテンツ (少数) を取得し、シーンのプロセスを分析し、テンプレートを見つけます。
6. 再帰的プロセスを調べるときは、問題が層ごとに除去されるように、再帰するたびに問題のデータセット -1 を調べる必要があります。
例2: ハノイ塔問題
ハノイの塔問題には実際には 2 つの再帰ステップが含まれており、少し複雑です。
/* ハノイの塔問題: ハノイの塔は古典的な再帰問題です。3 本の柱とさまざまなサイズのいくつかのディスクで構成されます。 最初に、すべてのディスクが最初の柱に積み重ねられ、最大から最小の順に配置されます。 目標は、すべてのディスクを 3 番目の柱に移動し、元の順序を維持することです。1 回の移動で移動できるディスクは 1 枚だけであり、大きなディスクを小さなディスクの上に置くことはできません。 */ const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, Output: process.stdout, }); /* プレート番号を入力*/ rl.on("line", function (line) { let num = Number(line); const han = (n, a, b, c) => { if (n === 0) console.log(a + "===>" + c ); //プログラムの画期的な else { //次の 3 つのステップにより、マクロの意味で必要な結果が得られます han(n - 1, a, c, b); // 最初のステップを 2 番目のステップに移動します (実際にはこのテンプレートを繰り返します) ) console.log(a + "===>" + c); // 最初のプレートの最後のプレートを 3 番目のプレートに直接挿入します han(n - 1, b, a, c);//2 番目を 3 番目に移動します (実際にはテンプレートを繰り返します) } ; han(num, "A", "B", "C"); });
問題解決のアイデア:
プレートが 2 枚しかないと仮定すると、次のテンプレート処理が得られます。 1 列目の最後のプレート (n-1) を除くすべてを 2 列目に移動し、最後のプレート (1 枚) を 3 列目に移動します。 2 列目のすべてのプレート (n-1) を 3 列目に移動します
2.二分探索法
ステーション b の対応ビデオ:なぜ二分探索はいつも間違って書かれるのですか? _哔哩哔哩_bilibili
例: 配列内の 5 に等しい数値の最初のインデックスを出力します。
let arr = [1, 2, 5, 5, 7]; const test = (array) => { // console.log(array); let l = -1; let r = array.length; while (l + 1 !== r) { let num = parseInt(l + r); if (array[num] < 5) { l = num; } else { r = num; } } if (array[r] === 5) ) { //特別な判定、本当に 5 かどうかを判定 return r; } else { return -1; //5 は存在しない } }; console.log(test(arr));
二分探索のテンプレートは上で使用されています: (疑似コード)
l = -1、r = N while l + 1 != N m = l + r / 2 (方向下取整) if isBlue(m) l = m else r = m return l または r
二分探索の考え方:
1. isBlueの条件、つまり臨界点(赤と青の境界線)を見つける
2. l または r、つまり分割線の左側または右側を出力します。
ストラテジー:
青の右端の最初の値は、isBlue の条件を満たす必要があります (条件は通常、符号未満のみです)。ドラフト上でいくつかの数値をシミュレートして、赤と青の境界条件をシミュレートして、 l または r を出力
例: 配列内で最初に一致した 5 のインデックスを出力すると、条件が <5 になる可能性があり、r を取得します。
配列内で最後に一致した 5 のインデックスを出力します。その後、<=5 を取得し、次に l を取得します。
3. 再帰と二項対立について考える
再帰と二分法はどちらもグレーな部分(解決できない問題)の考え方を含みます。
1. 再帰とは、最初に灰色の部分を拡大し、問題を積み上げ、問題を解決するポイントを見つけてから、徐々に灰色の部分を減らしていくことです
2. 2 つの点が半分ずつになり、問題が解決されるまで灰色の部分を徐々に縮小します