forked from blakeembrey/code-problems
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
String permutations in Go (blakeembrey#179)
- Loading branch information
1 parent
a448e31
commit 52dd522
Showing
1 changed file
with
95 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"sort" | ||
) | ||
|
||
/**************************************************************************** | ||
Generates permutations of sortable sequence changing it in place. | ||
****************************************************************************/ | ||
|
||
// PermutationsIter returns a closure, each call to the returned function | ||
// generates the next permutations of the sequence (changing it in place). | ||
// Uses Non-recursive lexicographic order (Knuth's L-Algorithm), thus | ||
// the sequence passed as argument must be sortable. | ||
func PermutationsIter(a sort.Interface) func() bool { | ||
current := int64(0) | ||
n := a.Len() | ||
return func() bool { | ||
if current == 0 { | ||
sort.Sort(a) | ||
current++ | ||
return true | ||
} | ||
// Find largest index k such that a[k] < a[k + 1] | ||
k := -1 | ||
for j := n - 2; j >= 0; j-- { | ||
if a.Less(j, j+1) { | ||
k = j | ||
break | ||
} | ||
} | ||
if k == -1 { // if k not found, all done | ||
return false | ||
} | ||
// Find largest index l greater than k such that a[k] < a[l] | ||
l := -1 | ||
for j := n - 1; j >= k+1; j-- { | ||
if a.Less(k, j) { | ||
l = j | ||
break | ||
} | ||
} | ||
// swap a[k] <-> a[l] | ||
a.Swap(k, l) | ||
// Reverse a[k+1:n] | ||
for i, j := k+1, n-1; i < j; i, j = i+1, j-1 { | ||
a.Swap(i, j) | ||
} | ||
current++ | ||
return true | ||
} | ||
} | ||
|
||
/*************** Create a sortable type ***************/ | ||
|
||
// MyPermSeq satisfy interface sort.Interface | ||
type MyPermSeq []byte | ||
|
||
// Len of the sequence | ||
func (ps MyPermSeq) Len() int { | ||
return len(ps) | ||
} | ||
|
||
// Less implements < | ||
func (ps MyPermSeq) Less(i, j int) bool { | ||
return ps[i] < ps[j] | ||
} | ||
|
||
// Swap in place | ||
func (ps MyPermSeq) Swap(i, j int) { | ||
ps[i], ps[j] = ps[j], ps[i] | ||
} | ||
|
||
func main() { | ||
|
||
// Let's permutate ABCD in-place: output will be ordered in lexicographical order | ||
mySeq := MyPermSeq([]byte("ABCD")) | ||
next := PermutationsIter(mySeq) | ||
fmt.Println("Generating permutations for", string(mySeq), ": ") | ||
for next() { | ||
fmt.Print(string(mySeq), " ") | ||
} | ||
fmt.Println("") | ||
|
||
// Let's permutate ABBB in-place: shows algorithm handles repeated elements well | ||
mySeq = MyPermSeq([]byte("ABBB")) | ||
next = PermutationsIter(mySeq) | ||
fmt.Println("Generating permutations for", string(mySeq), ": ") | ||
for next() { | ||
fmt.Print(string(mySeq), " ") | ||
} | ||
fmt.Println("") | ||
|
||
} |