From 93c207ed1e3436d613bb7e6bc32efc03dd3a702e Mon Sep 17 00:00:00 2001 From: jafar75 Date: Sat, 4 May 2024 00:34:28 +0330 Subject: [PATCH] feat: add next permutation problem --- README.md | 1 + math/permutation/next_permutation.go | 37 +++++++++++++++++++++ math/permutation/next_permutation_test.go | 40 +++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 math/permutation/next_permutation.go create mode 100644 math/permutation/next_permutation_test.go diff --git a/README.md b/README.md index ade5df81a..ace320588 100644 --- a/README.md +++ b/README.md @@ -834,6 +834,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`GenerateElementSet`](./math/permutation/heaps.go#L37): No description provided. 2. [`Heaps`](./math/permutation/heaps.go#L8): Heap's Algorithm for generating all permutations of n objects +3. [`NextPermutation`](./math/permutation/next_permutation.go#8): A solution to find next permutation of an integer array in constant memory ---
diff --git a/math/permutation/next_permutation.go b/math/permutation/next_permutation.go new file mode 100644 index 000000000..62841bb3d --- /dev/null +++ b/math/permutation/next_permutation.go @@ -0,0 +1,37 @@ +// A practice to find lexicographically next greater permutation of the given array of integers. +// If there does not exist any greater permutation, then print the lexicographically smallest permutation of the given array. +// The implementation below, finds the next permutation in linear time and constant memory and returns in place +// Useful reference: https://www.geeksforgeeks.org/next-permutation/ + +package permutation + +func NextPermutation(nums []int) { + pivot := 0 + for pivot = len(nums) - 2; pivot >= 0; pivot-- { + if nums[pivot] < nums[pivot+1] { + break + } + } + if pivot < 0 { + // current permutation is the last and must be reversed totally + for l, r := 0, len(nums)-1; l < r; l, r = l+1, r-1 { + nums[l], nums[r] = nums[r], nums[l] + } + } else { + succ := 0 + for succ = len(nums) - 1; succ > pivot; succ = succ - 1 { + if nums[succ] > nums[pivot] { + break + } + } + + // Swap the pivot and successor + nums[pivot], nums[succ] = nums[succ], nums[pivot] + + // Reverse the suffix part to minimize it + for l, r := pivot+1, len(nums)-1; l < r; l, r = l+1, r-1 { + nums[l], nums[r] = nums[r], nums[l] + } + } + +} diff --git a/math/permutation/next_permutation_test.go b/math/permutation/next_permutation_test.go new file mode 100644 index 000000000..8246876b4 --- /dev/null +++ b/math/permutation/next_permutation_test.go @@ -0,0 +1,40 @@ +package permutation + +import ( + "reflect" + "testing" +) + +func TestNextPermutation(t *testing.T) { + var nextPermutationTestData = []struct { + description string + numbers []int + next []int + }{ + { + description: "Basic case", + numbers: []int{1, 2, 3}, + next: []int{1, 3, 2}, + }, + { + description: "Should reverse the whole slice", + numbers: []int{3, 2, 1}, + next: []int{1, 2, 3}, + }, + { + description: "A more complex test", + numbers: []int{2, 4, 1, 7, 5, 0}, + next: []int{2, 4, 5, 0, 1, 7}, + }, + } + for _, test := range nextPermutationTestData { + t.Run(test.description, func(t *testing.T) { + NextPermutation(test.numbers) + + if !reflect.DeepEqual(test.numbers, test.next) { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expected result:%v\nFound: %v", test.next, test.numbers) + } + }) + } +}