Skip to content

Commit

Permalink
Solve the "Reverse all the words in a sentence" problem
Browse files Browse the repository at this point in the history
  • Loading branch information
mrekucci committed Jul 28, 2015
1 parent f64213d commit 1da215e
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 22 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Arrays and Strings
| Problem | Test |
|----------------------------------------------------------|:------------:|
| [Implement run-length encoding][22] | [tests][23] |
| [Reverse all the words in a sentence][24] | [tests][25] |


[1]: http://elementsofprogramminginterviews.com
Expand All @@ -64,3 +65,5 @@ Arrays and Strings
[21]: spiralmetrix_test.go
[22]: rlecompr.go
[23]: rlecompr_test.go
[24]: reversewords.go
[25]: reversewords_test.go
14 changes: 14 additions & 0 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package epi

import "math/rand"

// intSize is the size in bits of an int.
const intSize = 32 << (^uint(0) >> 63)

Expand All @@ -12,3 +14,15 @@ const (
maxInt = int(^uint(0) >> 1)
minInt = -maxInt - 1
)

// randStr returns a string of length n constructed
// from pseudo-randomly selected characters from t.
func randStr(n int, t string) string {
q := len(t) - 1
ints := rand.New(rand.NewSource(1238)).Perm(n)
chars := make([]byte, len(ints))
for j, n := range ints {
chars[j] = t[n%q]
}
return string(chars)
}
30 changes: 30 additions & 0 deletions common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package epi

import "testing"

func TestRandStr(t *testing.T) {
for _, test := range []struct {
n int
t string
}{
{10, "abc"},
} {
if got := len(randStr(test.n, test.t)); got != test.n {
t.Errorf("len(randStr(%d, %q) = %d; want %d", test.n, test.t, got, test.n)
}
}
}

func benchRandStr(b *testing.B, size int) {
for i := 0; i < b.N; i++ {
randStr(size, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
}
}

func BenchmarkRandStr1e2(b *testing.B) { benchRandStr(b, 1e2) }
func BenchmarkRandStr1e4(b *testing.B) { benchRandStr(b, 1e4) }
func BenchmarkRandStr1e6(b *testing.B) { benchRandStr(b, 1e6) }
8 changes: 4 additions & 4 deletions nextperm.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

package epi

// reverse reverse elements of an[s:e] in an.
func reverse(an []int, s, e int) {
// reverseInts reverse elements of a[s:e] in a.
func reverseInts(a []int, s, e int) {
for e > s {
an[s], an[e] = an[e], an[s]
a[s], a[e] = a[e], a[s]
s++
e--
}
Expand Down Expand Up @@ -38,7 +38,7 @@ func NextPerm(p []int) []int {
pn[k], pn[l] = pn[l], pn[k]
// Because swapping leaves the sequence after position k in decreasing order, we
// must reverse this sub-sequence to produce its lexicographically minimal permutation.
reverse(pn, k+1, len(pn)-1)
reverseInts(pn, k+1, len(pn)-1)

return pn
}
31 changes: 31 additions & 0 deletions reversewords.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package epi

// reverseBytes reverse elements of a[s:e] in a.
func reverseBytes(a []byte, s, e int) {
for e > s {
a[s], a[e] = a[e], a[s]
s++
e--
}
}

// ReverseWords returns a new string containing the words from s in reverse order.
func ReverseWords(s string) string {
r := []byte(s)

reverseBytes(r, 0, len(s)-1) // Reverse whole sentence.
p := 0
for q := p; q < len(r); q++ { // Reverse each world in the reversed sentence.
if r[q] == ' ' {
reverseBytes(r, p, q-1) // q-1 exclude the ' ' character from reversal.
p = q + 1
}
}
reverseBytes(r, p, len(r)-1) // Reverse the last world.

return string(r)
}
43 changes: 43 additions & 0 deletions reversewords_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package epi

import "testing"

func TestReverseWords(t *testing.T) {
for _, test := range []struct {
in string
want string
}{
{},
{"a", "a"},
{"b ", " b"},
{"a b c", "c b a"},
{"a b c d", "d c b a"},
{"Alice like Bob", "Bob like Alice"},
{"The quick brown fox jumps over the lazy dog", "dog lazy the over jumps fox brown quick The"},

// Test more then one space.
{"aa bb", "bb aa"},
} {
if got := ReverseWords(test.in); got != test.want {
t.Errorf("ReverseWorlds(%q) = %q; want %q", test.in, got, test.want)
}
}
}

func benchReverseWords(b *testing.B, size int) {
b.StopTimer()
for i := 0; i < b.N; i++ {
s := randStr(size, "The quick brown fox jumps over the lazy dog") // Pangram.
b.StartTimer()
ReverseWords(s)
b.StopTimer()
}
}

func BenchmarkReverseWords1e1(b *testing.B) { benchReverseWords(b, 1e1) }
func BenchmarkReverseWords1e2(b *testing.B) { benchReverseWords(b, 1e2) }
func BenchmarkReverseWords1e3(b *testing.B) { benchReverseWords(b, 1e3) }
21 changes: 3 additions & 18 deletions rlecompr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,7 @@

package epi

import (
"math/rand"
"testing"
)

// charPerm returns pseudo-random permutation of n characters as a string.
func charPerm(n int) string {
const chartable = "abcdefghijklmnopqrstuvwxyz"
q := len(chartable) - 1
ints := rand.New(rand.NewSource(1238)).Perm(n)
chars := make([]byte, len(ints))
for j, n := range ints {
chars[j] = chartable[n%q]
}
return string(chars)
}
import "testing"

func TestRLEEncode(t *testing.T) {
for _, test := range []struct {
Expand Down Expand Up @@ -55,7 +40,7 @@ func TestRLEEncode(t *testing.T) {
func benchRLEEncode(b *testing.B, size int) {
b.StopTimer()
for i := 0; i < b.N; i++ {
s := charPerm(size)
s := randStr(size, "abcdefghijklmnopqrstuvwxyz")
b.StartTimer()
RLEEncode(s)
b.StopTimer()
Expand Down Expand Up @@ -102,7 +87,7 @@ func TestRLEDecode(t *testing.T) {
func benchRLEDecode(b *testing.B, size int) {
b.StopTimer()
for i := 0; i < b.N; i++ {
s, ok := RLEEncode(charPerm(size))
s, ok := RLEEncode(randStr(size, "abcdefghijklmnopqrstuvwxyz"))
if !ok {
b.Errorf("RLEEncode did not encode string properly")
}
Expand Down

0 comments on commit 1da215e

Please sign in to comment.