ការរាប់៖ Permutation និង Combination

មាតិកា

  1. រាប់ដោយមិនរាយបញ្ជី
  2. Rule of Product
  3. PIN និង Password៖ ការរាប់ String
  4. Factorial៖ ការរាប់លំដាប់
  5. Permutation៖ លំដាប់សំខាន់
  6. Combination៖ លំដាប់មិនសំខាន់
  7. ហេតុអ្វី Brute Force ផ្ទុះ
  8. BigInt សម្រាប់ចំនួនធំៗ
  9. Pagination និង Batching
  10. រូបមន្ត៖ Module counting
  11. សាកល្បងដោយខ្លួនឯង

1. រាប់ដោយមិនរាយបញ្ជី

តើមាន PIN 4 ខ្ទង់ខុសៗគ្នាប៉ុន្មាន? អ្នកអាចសរសេរវាទាំងអស់ចេញមក៖ 0000, 0001, 0002 ហើយបន្តទៅទៀត។ វាអាចធ្វើបាន ប៉ុន្តែយឺត ហើយចំពោះសំណួរធំជាងនេះ ("password 8 តួអក្សរមានប៉ុន្មាន?") វាមិនអាចធ្វើទៅរួចទេ។ ការរាប់គឺជាជំនាញគណិតវិទ្យាក្នុងការទទួលបាន ចំនួន នៃលទ្ធភាព ដោយមិនចាំបាច់បង្កើតបញ្ជីឡើយ។

អ្នកសរសេរកម្មវិធីត្រូវការវាញឹកញាប់ជាងអ្វីដែលអ្នកស្មាន៖

  • តើទ្រង់ទ្រាយ password មួយរឹងមាំប៉ុនណា ហើយអ្នកវាយប្រហារត្រូវការពេលប៉ុន្មាន?
  • តើ form ដែលមាន dropdown ប្រាំ ពិតជាមាន test case ប៉ុន្មាន?
  • តើតារាងត្រូវការប៉ុន្មានទំព័រ ប្រសិនបើវាបង្ហាញម្តង 10 ជួរ?
  • តើ loop "សាកល្បងគ្រប់ការផ្សំ" នឹងចប់នៅថ្ងៃនេះ ឬក្រោយពេលព្រះអាទិត្យរលត់?

សំណួរចុងក្រោយភ្ជាប់ដោយផ្ទាល់ទៅនឹង Function, ការលូតលាស់ និង Logarithm និង សញ្ញា Big-O។ ការរាប់ប្រាប់អ្នកថា n ធំប៉ុនណា។ Big-O ប្រាប់ថាវាធ្វើអ្វីដល់ កូដរបស់អ្នក។

2. Rule of Product

ច្បាប់តែមួយនៅពីក្រោយស្ទើរតែគ្រប់យ៉ាងក្នុងជំពូកនេះគឺ rule of product៖ ប្រសិនបើអ្នកធ្វើជម្រើសជាច្រើនបន្តបន្ទាប់គ្នា ចំនួនលទ្ធផលសរុប គឺជាចំនួនជម្រើសនៃការជ្រើសរើសនីមួយៗ គុណ គ្នា។

ហាងកាហ្វេតូចមួយផ្តល់ឈុតអាហារថ្ងៃត្រង់៖

  • មុខម្ហូបមេ 3 (បាយឆា មី អាម៉ុក)
  • ភេសជ្ជៈ 2 (តែទឹកកក កាហ្វេ)
  • បង្អែម 4
const mains = 3;
const drinks = 2;
const desserts = 4;

console.log(mains * drinks * desserts); // 24

មានឈុតអាហារថ្ងៃត្រង់ខុសៗគ្នា 24។ ហេតុអ្វីគុណ មិនមែនបូក? ជ្រើសបាយឆាមុន៖ វាអាចទៅជាមួយភេសជ្ជៈ 2 ហើយភេសជ្ជៈនីមួយៗអាចទៅជាមួយបង្អែម 4 ដូច្នេះបាយឆាតែមួយមុខមាន 8 ឈុត។ មីមាន 8 ទៀត អាម៉ុកមាន 8 ទៀត៖ 8 + 8 + 8 = 24។ ការគុណគ្រាន់តែជាផ្លូវកាត់នៃការបូកម្តងហើយម្តងទៀតនោះ។

ប្រើ ការបូក នៅពេលជម្រើសជាជម្រើសជំនួស ("មុខម្ហូបមេ ឬ ភេសជ្ជៈ") និង ការគុណ នៅពេលអ្នកធ្វើរឿងមួយ ហើយបន្ទាប់មក រឿងមួយទៀត។

គំនិតដូចគ្នានេះរាប់ form ។ ទំព័រចុះឈ្មោះដែលមាន dropdown ប្រទេស (200 ជម្រើស) dropdown ភាសា (10 ជម្រើស) និងប៊ូតុង radio ផែនការ (3 ជម្រើស) មាន 200 * 10 * 3 = 6,000 ការផ្សំនៃ input។ គ្មាននរណាសាកល្បងទាំងអស់ដោយដៃទេ ប៉ុន្តែឥឡូវអ្នកដឹងទំហំនៃបញ្ហាហើយ។

3. PIN និង Password៖ ការរាប់ String

String ដែលមានប្រវែងថេរ ដែលគ្រប់ទីតាំងត្រូវបានបំពេញដោយឯករាជ្យ ពីសំណុំនិមិត្តសញ្ញាតែមួយ គឺជា rule of product ក្នុងទម្រង់សាមញ្ញបំផុត។ ប្រសិនបើមាននិមិត្តសញ្ញា s ដើម្បីជ្រើសរើស និងទីតាំង L ចំនួននោះគឺ៖

s * s * s * ... (L times)  =  s ^ L

^ នៅទីនេះមានន័យថា "ស្វ័យគុណ" ដែល JavaScript សរសេរជា **។ នៅទីនេះ s ** L មានន័យថា "គុណ s នឹងខ្លួនវា L ដង"។ PIN 4 ខ្ទង់មាន 10 និមិត្តសញ្ញា (0-9) និង 4 ទីតាំង៖

console.log(10 ** 4); // 10000
console.log(10 ** 6); // 1000000

ដូច្នេះមាន PIN 4 ខ្ទង់ចំនួន 10,000 និង PIN 6 ខ្ទង់ចំនួន 1,000,000។ ការបន្ថែម ពីរខ្ទង់ធ្វើឲ្យចន្លោះធំជាងមុន 100 ដង ពីព្រោះទីតាំងថ្មីនីមួយៗ គុណចំនួននឹង 10។

នេះជា alphabet របស់ password ដែលនិយមប្រើ៖

Alphabetនិមិត្តសញ្ញា
ខ្ទង់10
អក្សរតូច26
អក្សរតូច + អក្សរធំ52
អក្សរ + ខ្ទង់62
គ្រប់គ្រាប់ចុច ASCII ដែលអាចបោះពុម្ពបានលើក្តារចុចប្រហែល 94

Password 8 តួអក្សរដែលធ្វើពីអក្សរ និងខ្ទង់ មាន 62 ** 8 លទ្ធភាព។ តោះគណនាវា៖

console.log(62 ** 8); // 218340105584896
console.log(26 ** 8); // 208827064576

នោះប្រហែល 218 ទ្រីលាន ប្រៀបធៀបនឹង 209 ពាន់លាន។ ការអនុញ្ញាតឲ្យមានអក្សរធំ និងខ្ទង់ ធ្វើឲ្យចន្លោះធំជាងមុនប្រហែល 1,000 ដង។ ជាទូទៅ ការបន្ថែម ប្រវែង ជួយច្រើនជាងការបន្ថែម និមិត្តសញ្ញា ពីព្រោះប្រវែងគឺជា exponent។

4. Factorial៖ ការរាប់លំដាប់

ឥឡូវជាសំណួរផ្សេង។ អ្នកមានមិត្តភក្តិ 3 នាក់ គឺដារា សុភា និងវីរៈ ហើយអ្នកចង់ឲ្យពួកគេឈរតម្រៀបជួរថតរូប។ តើមានលំដាប់ប៉ុន្មាន?

  • មាន 3 ជម្រើសសម្រាប់អ្នកឈរទីមួយ។
  • បន្ទាប់មកនៅសល់ 2 នាក់សម្រាប់កន្លែងទីពីរ។
  • បន្ទាប់មកនៅសល់ 1 នាក់សម្រាប់កន្លែងចុងក្រោយ។

Rule of product៖ 3 * 2 * 1 = 6។ លំដាប់ទាំងប្រាំមួយគឺ DSV, DVS, SDV, SVD, VDS, VSD។

ការគុណចំនួនមួយនឹងគ្រប់ចំនួនគត់ដែលតូចជាងវារហូតដល់ 1 ត្រូវបានហៅថា factorial សរសេរជា n! ហើយអានថា "n factorial"៖

nn!ការគណនា
01កំណត់ជា 1 (មានវិធីតែមួយក្នុងការតម្រៀបអ្វីទាំងអស់)
111
222 * 1
363 * 2 * 1
4244 * 3 * 2 * 1
51205 * 4 * 3 * 2 * 1
103,628,800

សូមកត់សម្គាល់ថាវាលូតលាស់លឿនប៉ុនណា។ មនុស្សដប់នាក់អាចឈរតម្រៀបជួរបានជាងនៅ 3.6 លានលំដាប់ខុសៗគ្នា។ យើងនឹងសរសេរ factorial នៅក្នុងរូបមន្ត នៅចុងជំពូកនេះ។

5. Permutation៖ លំដាប់សំខាន់

ការប្រណាំងមួយមានអ្នករត់ 8 នាក់ ហើយ 3 នាក់ដំបូងទទួលបានមាស ប្រាក់ និងសំរិទ្ធ។ តើអាចមាន podium ខុសៗគ្នាប៉ុន្មាន?

  • 8 ជម្រើសសម្រាប់មាស។
  • នៅសល់ 7 សម្រាប់ប្រាក់។
  • នៅសល់ 6 សម្រាប់សំរិទ្ធ។
console.log(8 * 7 * 6); // 336

នេះគឺជា permutation៖ ការជ្រើសរើសធាតុ k ពី n ដែល លំដាប់ សំខាន់ (មាស ប្រាក់ សំរិទ្ធ ខុសពី សំរិទ្ធ ប្រាក់ មាស)។ អ្នកគុណតែ k តួដំបូងនៃ factorial៖

P(n, k) = n * (n-1) * ... * (n-k+1)   =   n! / (n-k)!

P(8, 3) = 8! / 5! = 336។ / (n-k)! គ្រាន់តែលុបកន្ទុយនៃ ការគុណវែងដែលអ្នកមិនត្រូវការចោល។

នៅពេល k ស្មើនឹង n (តម្រៀបគ្រប់គ្នា) អ្នកទទួលបាន factorial ធម្មតា៖ P(5, 5) = 5! = 120។

ការប្រើប្រាស់ជាក់ស្តែង៖ ចំនួនវិធីក្នុងការចាត់ថ្នាក់លទ្ធផលស្វែងរក ចាត់កៅអី ឬ ជ្រើសរើសប្រធាន អនុប្រធាន និងហិរញ្ញិកពីក្រុមមួយ។

6. Combination៖ លំដាប់មិនសំខាន់

ឥឡូវជាឆ្នោត។ អ្នកជ្រើសលេខ 6 ពី 49 ហើយលំដាប់ដែលអ្នកជ្រើសមិន សំខាន់ទេ។ ការជ្រើស 3, 17, 22, 30, 41, 48 គឺជាសំបុត្រដូចគ្នានឹង 48, 41, 30, 22, 17, 3។

នេះគឺជា combination៖ ការជ្រើសរើសធាតុ k ពី n ដែលលំដាប់ មិន សំខាន់។ វាត្រូវបានសរសេរជា C(n, k) ហើយអានថា "n choose k"។

តើយើងទទួលបានវាដោយរបៀបណា? ចាប់ផ្តើមពី permutation ដែលរាប់គ្រប់លំដាប់ ដោយឡែកពីគ្នា បន្ទាប់មកចែកនឹងចំនួនវិធីតម្រៀបធាតុ k ដែលបានជ្រើស (k!) ពីព្រោះលំដាប់ទាំងនោះរាប់ជាការជ្រើសរើសតែមួយដូចគ្នា៖

C(n, k) = P(n, k) / k!  =  n! / (k! * (n-k)!)

ការត្រួតពិនិត្យតូចមួយ៖ ជ្រើសមនុស្ស 2 នាក់ពី A, B, C, D។

Permutations: AB BA AC CA AD DA BC CB BD DB CD DC   (12)
Combinations: AB AC AD BC BD CD                      (6)

P(4, 2) = 12 ហើយ 12 / 2! = 6។ គូនីមួយៗត្រូវបានរាប់ពីរដង ម្តងក្នុងមួយ លំដាប់ ដូច្នេះការចែកនឹង 2 ដោះស្រាយបាន។

សំណួរលំដាប់សំខាន់ទេ?ឈ្មោះរូបមន្ត
Podium 3 នាក់ពីអ្នករត់ 8 នាក់បាទ/ចាសPermutationP(8,3) = 336
ជ្រើសក្រុម 3 នាក់ពីមនុស្ស 8 នាក់ទេCombinationC(8,3) = 56
ឆ្នោត៖ លេខ 6 ពី 49ទេCombinationC(49,6) = 13,983,816
PIN 4 ខ្ទង់បាទ/ចាស អនុញ្ញាតឲ្យដដែលPower10 ** 4

ការសាកល្បងសាមញ្ញ៖ តើការប្តូរការជ្រើសពីរ បង្កើតលទ្ធផលផ្សេងឬទេ? បើ បាទ/ចាស វាជា permutation។ បើទេ វាជា combination។

Combination ក៏លេចឡើងក្នុងការធ្វើតេស្តដែរ៖ ប្រសិនបើអ្នកមាន feature 20 ហើយចង់ តេស្តគ្រប់ គូ របស់វាជាមួយគ្នា អ្នកត្រូវការតេស្តគូ C(20, 2) = 190។ វាក៏រាប់ "ការចាប់ដៃ" ដែរ៖ ក្នុងកិច្ចប្រជុំមនុស្ស n នាក់ដែលគ្រប់គ្នា ជំរាបសួរគ្នា មានការចាប់ដៃ C(n, 2) ដែលជា n * (n - 1) / 2។ នោះគឺជារូបរាងដូចគ្នាបេះបិទនឹង nested loop ក្នុង សញ្ញា Big-O ដែលជា មូលហេតុដែល nested loop ត្រូវបានហៅថា O(n²)។

7. ហេតុអ្វី Brute Force ផ្ទុះ

Brute force មានន័យថាសាកល្បងគ្រប់លទ្ធភាពរហូតដល់មួយដំណើរការ។ ការរាប់ ប្រាប់អ្នកថាតើវាប្រាកដនិយមឬអត់។ ឧបមាថាកុំព្យូទ័រអាចពិនិត្យការទាយមួយ ពាន់លាន (1,000,000,000) ក្នុងមួយវិនាទី។ យើងប្រើចំនួនខាងលើ៖

អ្វីដែលអ្នកកំពុងទាយលទ្ធភាពពេលវេលាក្នុងល្បឿន 1 ពាន់លាន/វិនាទី
PIN 4 ខ្ទង់10,0000.00001 វិនាទី
អក្សរតូច 8 (26⁸)ប្រហែល 209 ពាន់លានប្រហែល 3.5 នាទី
អក្សរ + ខ្ទង់ 8 (62⁸)ប្រហែល 218 ទ្រីលានប្រហែល 2.5 ថ្ងៃ
តួអក្សរដែលអាចបោះពុម្ពបាន 12 (94¹²)ប្រហែល 4.8 x 10²³ប្រហែល 15 លានឆ្នាំ
តម្រៀបធាតុ 15 (15!)1.3 ទ្រីលានប្រហែល 22 នាទី
តម្រៀបធាតុ 20 (20!)2.4 x 10¹⁸ប្រហែល 77 ឆ្នាំ

គួរញែករូបរាងនៃការលូតលាស់ទាំងពីរចេញពីគ្នា។

  • Exponential ដូច s ** L៖ តួអក្សរបន្ថែមនីមួយៗគុណការងារ នឹង s។ ប្រវែងគឺជាមិត្តរបស់អ្នក ក្នុងនាមជាអ្នកការពារ។
  • Factorial ដូច n!៖ ធាតុបន្ថែមនីមួយៗគុណការងារនឹង n ថ្មី។ នេះលូតលាស់លឿនជាង exponential ទៅទៀត។

នេះគឺជាមូលហេតុពិតដែល PIN 4 ខ្ទង់លើទូរស័ព្ទត្រូវបានការពារដោយ "រង់ចាំ 30 វិនាទីបន្ទាប់ពីព្យាយាមច្រើនដង" មិនមែនដោយទំហំរបស់វាទេ។ ជាមួយនឹងលទ្ធភាពតែ 10,000 ទំហំតែម្យ៉ាងមិនអាចការពារវាបានទេ។ ការពន្យារពេលទើបអាច។

ក៏សូមកត់សម្គាល់ជួរ factorial ដែរ៖ "សាកល្បងគ្រប់លំដាប់" ល្អសម្រាប់ធាតុ 10 ហើយ គ្មានសង្ឃឹមសម្រាប់ 20។ បញ្ហាដូចជាការរកផ្លូវខ្លីបំផុតដែលដើរកាត់ទីក្រុងច្រើន ជួបជញ្ជាំងនេះ ហើយនោះជាមូលហេតុមួយដែលអ្នកសរសេរកម្មវិធីបង្កើត algorithm ឆ្លាតជាងជំនួសឲ្យ brute force។ អ្នកនឹងជួបការគិតបែបនេះម្តងទៀតក្នុង ស៊េរី Data Structures & Algorithms ដែលបានគ្រោងទុក។

8. BigInt សម្រាប់ចំនួនធំៗ

ឥឡូវជាបញ្ហាជាក់ស្តែង។ សាកល្បង factorial នៃ 25 ជាមួយចំនួនធម្មតា៖

let result = 1;
for (let i = 2; i <= 25; i++) {
  result *= i;
}
console.log(result); // 1.5511210043330986e+25

JavaScript បោះពុម្ពវាជា scientific notation ហើយវាលែងត្រឹមត្រូវពិតប្រាកដទៀតហើយ។ ដូចដែលអ្នកបានឃើញក្នុង Integer, Overflow និងភាពជាក់លាក់ number ធម្មតាត្រឹមត្រូវពិតប្រាកដតែរហូតដល់ Number.MAX_SAFE_INTEGER ដែល ជា 9007199254740991 (ប្រហែល 9 ក្វាទ្រីលាន)។ បញ្ហារាប់ហួសវា យ៉ាងលឿន៖ 18! នៅតែសមទាំងអស់ ប៉ុន្តែ 19! និងលើសពីនេះមិនសមទេ។

ចម្លើយគឺ BigInt ជាប្រភេទចំនួនដែលអាចធំបានតាមដែលអង្គចងចាំអនុញ្ញាត។ អ្នកសរសេរ BigInt literal ដោយដាក់ n ក្រោយខ្ទង់ ហើយអ្នកមិនអាច លាយវាជាមួយចំនួនធម្មតាបានទេ៖

let result = 1n;
for (let i = 2n; i <= 25n; i++) {
  result *= i;
}
console.log(result); // 15511210043330985984000000n

ច្បាប់ដែលត្រូវចងចាំ៖

  • 5n គឺជា BigInt, 5 គឺជា number។ 5n + 5 បោះ TypeError។ បំប្លែង ដោយ BigInt(5) ឬ Number(5n)។
  • / លើ BigInt ទម្លាក់សំណល់៖ 7n / 2n គឺ 3n។
  • ** ដំណើរការ៖ 10n ** 30n ត្រឹមត្រូវពិតប្រាកដ។
  • console.log បោះពុម្ព n នៅចុងសម្រាប់ BigInt ប៉ុន្តែ String(x) និង template string (${x}) មិនរួមបញ្ចូលវាទេ។

Function រាប់របស់យើងនឹងត្រឡប់ BigInt ដើម្បីឲ្យចម្លើយនៅត្រឹមត្រូវពិតប្រាកដ។ ប្រសិនបើ អ្នកចង់បានតែទំហំប្រហាក់ប្រហែល ប្រើ Number(x) ហើយទទួលយកការបង្គត់ខ្លះ។

9. Pagination និង Batching

ការរាប់ក៏គ្របដណ្តប់ការងារធម្មតាមួយដែរ៖ តើបញ្ជីត្រូវការប៉ុន្មានទំព័រ? តារាងបង្ហាញ 10 ជួរក្នុងមួយទំព័រ ហើយ API ត្រឡប់ 95 ជួរ។

console.log(95 / 10);            // 9.5
console.log(Math.ceil(95 / 10)); // 10

Math.ceil បង្គត់ ឡើង។ អ្នកត្រូវការដប់ទំព័រ ពីព្រោះទំព័រចុងក្រោយផ្ទុក 5 ជួរដែលនៅសល់។ ការបង្គត់ចុះនឹងបាត់ 5 ជួរនោះ ហើយការបង្គត់ទៅជិតបំផុត នឹងផ្តល់ 10 នៅទីនេះ ប៉ុន្តែ 9 សម្រាប់ 94 ជួរ (9.4) ដែលនឹង ខុស។ ច្បាប់គឺសាមញ្ញ៖ pages = ceil(items / pageSize)។

Edge case ដែលគួរតេស្ត៖

itemspageSizeលទ្ធផលមូលហេតុ
951010ទំព័រចុងក្រោយមិនពេញ
1001010ពេញសមរម្យ
1011011ធាតុមួយហៀរចេញ
0100គ្មានទំព័រ (សម្រេចចិត្តថាតើ UI របស់អ្នកចង់បាន 1 ឬអត់)

រូបមន្តដូចគ្នាបំបែកការងារជា batch។ ការផ្ញើអ៊ីមែល 2,500 ដោយមាន ដែនកំណត់ 100 ក្នុងមួយ request ត្រូវការ Math.ceil(2500 / 100) = 25 request។ ការបញ្ចូលជួរ database 10,001 ជាក្រុមៗ 1,000 ត្រូវការ 11 ក្រុម ហើយ ក្រុមចុងក្រោយស្ទើរតែទទេ។ ការធ្វើ ceil ខុសគឺជា off-by-one bug បុរាណ ដែលធាតុពីរបីចុងក្រោយមិនដែលត្រូវបានដំណើរការដោយស្ងាត់ៗ។

ទំព័រ p (រាប់ចាប់ពី 1) ចាប់ផ្តើមនៅ index (p - 1) * pageSize៖

const items = Array.from({ length: 95 }, (_, i) => i + 1);
const pageSize = 10;
const page = 10;

const start = (page - 1) * pageSize; // 90
console.log(items.slice(start, start + pageSize)); // [ 91, 92, 93, 94, 95 ]

10. រូបមន្ត៖ Module counting

បង្កើត src/counting.js ក្នុងគម្រោង mathlab របស់អ្នក។ គ្រប់ function ដែល អាចផលិតចម្លើយធំត្រឡប់ BigInt។

// src/counting.js — រាប់អ្វីៗដោយមិនរាយបញ្ជី។

export function factorial(n) {
  if (!Number.isInteger(n) || n < 0) {
    throw new RangeError("factorial needs a whole number >= 0");
  }
  let result = 1n;
  for (let i = 2n; i <= BigInt(n); i++) {
    result *= i;
  }
  return result;
}

// ការជ្រើសមានលំដាប់៖ n * (n-1) * ... * (n-k+1)
export function permutations(n, k = n) {
  if (k > n) return 0n;
  let result = 1n;
  for (let i = 0; i < k; i++) {
    result *= BigInt(n - i);
  }
  return result;
}

// ការជ្រើសគ្មានលំដាប់ ("n choose k")។ ការចែកគ្រប់ជំហានរក្សា
// តម្លៃកណ្តាលឲ្យជាចំនួនគត់ត្រឹមត្រូវ។
export function combinations(n, k) {
  if (k > n) return 0n;
  const small = Math.min(k, n - k);
  let result = 1n;
  for (let i = 1; i <= small; i++) {
    result = (result * BigInt(n - small + i)) / BigInt(i);
  }
  return result;
}

// តើមាន string ប៉ុន្មានដែលមានតួអក្សរ `length` ពី alphabet ទំហំនេះ។
export function passwordSpace(alphabetSize, length) {
  return BigInt(alphabetSize) ** BigInt(length);
}

// តើត្រូវការប៉ុន្មានទំព័រដើម្បីបង្ហាញ totalItems ដោយ pageSize ក្នុងមួយទំព័រ?
export function pageCount(totalItems, pageSize) {
  if (pageSize <= 0) throw new RangeError("pageSize must be positive");
  return Math.ceil(totalItems / pageSize);
}

កំណត់សម្គាល់ខ្លះអំពីការរចនា៖

  • permutations(n, k = n) គុណតែ k តួ ដូច្នេះវាមិនដែលគណនា n! ទាំងមូលរួចចែកទេ។
  • combinations ប្រើ min(k, n - k) ពីព្រោះ C(49, 6) ស្មើនឹង C(49, 43) ហើយការធ្វើ 6 ជំហានខ្លីជាង 43។ នៅគ្រប់ជំហាន លទ្ធផលដែលកំពុងដំណើរការ គឺជាចំនួន combination ដោយខ្លួនវាផ្ទាល់ ដូច្នេះការចែកតែងតែត្រឹមត្រូវ។
  • pageCount ត្រឡប់ចំនួនធម្មតា៖ ចំនួនទំព័រគឺតូច។

ឥឡូវបន្ថែម export ទៅ src/index.js៖

export * from "./counting.js";

បន្ទាប់មកបន្ថែមកូដនេះទៅ demo.js (ឬឯកសារថ្មី) ហើយដំណើរការ node demo.js៖

import {
  factorial, permutations, combinations, passwordSpace, pageCount,
} from "./src/index.js";

console.log(factorial(5));            // 120n
console.log(factorial(25));           // 15511210043330985984000000n
console.log(permutations(8, 3));      // 336n
console.log(combinations(5, 2));      // 10n
console.log(combinations(49, 6));     // 13983816n
console.log(passwordSpace(10, 4));    // 10000n
console.log(passwordSpace(62, 8));    // 218340105584896n
console.log(passwordSpace(94, 12));   // 475920314814253376475136n
console.log(pageCount(95, 10));       // 10
console.log(pageCount(101, 10));      // 11

ចម្លើយ 12 តួអក្សរខ្ពស់ជាង Number.MAX_SAFE_INTEGER ឆ្ងាយ ដូច្នេះ number ធម្មតាមិនអាចបង្ហាញវាបានត្រឹមត្រូវពិតប្រាកដទេ។ នោះហើយជាតម្លៃរបស់ BigInt។

អ្នកក៏អាចប៉ាន់ស្មានថាការវាយប្រហារ brute force ចំណាយពេលប៉ុន្មានដែរ៖

const guessesPerSecond = 1e9;
const seconds = Number(passwordSpace(62, 8)) / guessesPerSecond;
console.log(seconds / 3600 / 24); // about 2.53 (days)

Number(...) បំប្លែង BigInt ដើម្បីឲ្យយើងអាចចែកនឹងចំនួនធម្មតា។ ការបង្គត់បន្តិចបន្តួចមិនអីទេ ពីព្រោះយើងចង់បានតែការប៉ាន់ស្មាន។

11. សាកល្បងដោយខ្លួនឯង

  1. ឈុតអាហារថ្ងៃត្រង់។ ហាងកាហ្វេបន្ថែមមុខម្ហូបមេទីបួន និងភេសជ្ជៈទីបី។ ដោយប្រើ rule of product តើឥឡូវមានឈុតអាហារថ្ងៃត្រង់ប៉ុន្មាន? ពិនិត្យដោយកូដ។
  2. ដំឡើង PIN។ ប្រើ passwordSpace ដើម្បីប្រៀបធៀប PIN 4 ខ្ទង់ 6 ខ្ទង់ និង 8 ខ្ទង់។ តើខ្ទង់បន្ថែមពីរគ្រប់ដងគុណចន្លោះដោយកត្តាប៉ុន្មាន? បន្ទាប់មកគណនាថា 8 ខ្ទង់ត្រូវចំណាយពេលប៉ុន្មាន ក្នុងល្បឿនមួយពាន់លានការទាយ ក្នុងមួយវិនាទី។
  3. Permutation ឬ combination? សម្រាប់ករណីនីមួយៗ ប្រាប់ថាវាជាអ្វី បន្ទាប់មកគណនា ដោយ mathlab៖ (ក) ជ្រើសសិស្ស 3 នាក់ក្នុងចំណោម 10 នាក់ដើម្បីបង្កើតគណៈកម្មការ (ខ) ចាត់សិស្ស 3 នាក់ក្នុងចំណោម 10 នាក់ជាប្រធានក្រុម អនុប្រធានក្រុម និង លេខាធិការ (គ) ជ្រើសបៀ 5 សន្លឹកពីឈុតបៀ 52 សន្លឹក។ ពិនិត្យថា (ខ) គឺ 3! = 6 ដងនៃ (ក) ពិតប្រាកដ។
  4. Symmetry។ បោះពុម្ព combinations(10, 3) និង combinations(10, 7)។ ហេតុអ្វី វាស្មើគ្នា? (ណែនាំ៖ ការជ្រើស 3 ដើម្បីដាក់បញ្ចូល គឺដូចគ្នានឹងការជ្រើស 7 ដើម្បីទុកចោល។)
  5. Pagination។ សរសេរ pageSlice(items, page, pageSize) ដែលត្រឡប់ ធាតុសម្រាប់មួយទំព័រ ដោយប្រើ pageCount ដើម្បីបដិសេធលេខទំព័រដែល ខ្ពស់ពេក។ តេស្តជាមួយធាតុ 95 ដោយ 10 ក្នុងមួយទំព័រ ទំព័រ 1, 10 និង 11។
  6. តើ Number ចុះចាញ់នៅពេលណា? រក n តូចបំផុតដែល Number(factorial(n)) > Number.MAX_SAFE_INTEGER។ Loop n ឡើងលើ ហើយឈប់នៅពេលលក្ខខណ្ឌជា true។ អ្នកគួររកឃើញថាវាគឺ 19។

ការរាប់បានប្រាប់អ្នកថាមានលទ្ធភាពប៉ុន្មាន។ ជំពូកបន្ទាប់សួរសំណួរ គួរឲ្យចាប់អារម្មណ៍ជាង៖ តើនីមួយៗ ទំនង ប៉ុនណា? បន្តជាមួយ មូលដ្ឋានគ្រឹះប្រូបាប ដែល randomInt expected value និង birthday paradox ពឹងលើការរាប់ទាំងនេះ ពិតប្រាកដ។

ទិញកាហ្វេជូនខ្ញុំ

ចូលចិត្តមេរៀននេះមែនទេ? សូមពិចារណាទិញកាហ្វេជូនខ្ញុំមួយកែវ ដើម្បីគាំទ្រការបង្កើតមាតិកាឥតគិតថ្លៃបន្ថែមទៀត!