Skip to content

Iterating Strings — Tasks

Task 1: Count Runes (Easy)

Count the number of Unicode characters (not bytes) in a string.

package main

import "fmt"

// TODO: implement CountRunes
// Do NOT use len([]rune(s)) — use for range instead
func CountRunes(s string) int {
    // Use for range over the string
    // Count each iteration (each rune)
}

func main() {
    fmt.Println(CountRunes("Hello"))       // 5
    fmt.Println(CountRunes("Hello, 世界")) // 9
    fmt.Println(CountRunes("😀😁😂"))    // 3
    fmt.Println(CountRunes(""))            // 0
}

Task 2: Is Palindrome (Easy)

Check if a string is a palindrome (reads the same forwards and backwards), Unicode-safe.

package main

import "fmt"

// TODO: implement IsPalindrome
func IsPalindrome(s string) bool {
    // Convert to []rune for character access
    // Compare first and last, second and second-to-last, etc.
}

func main() {
    fmt.Println(IsPalindrome("racecar"))    // true
    fmt.Println(IsPalindrome("hello"))      // false
    fmt.Println(IsPalindrome(""))           // true
    fmt.Println(IsPalindrome("A"))          // true
    fmt.Println(IsPalindrome("上海自来水来自海上")) // true
}

Task 3: Count Vowels and Consonants (Easy)

Count vowels (a, e, i, o, u) and consonants (other letters) in a string.

package main

import (
    "fmt"
    "strings"
    "unicode"
)

// TODO: implement CharTypes
func CharTypes(s string) (vowels, consonants int) {
    // Use for range to iterate runes
    // A vowel is a letter that is in "aeiouAEIOU"
    // A consonant is any other letter
}

func main() {
    v, c := CharTypes("Hello World")
    fmt.Println("Vowels:", v)     // 3
    fmt.Println("Consonants:", c) // 7

    v, c = CharTypes("AEIOU")
    fmt.Println("Vowels:", v)     // 5
    fmt.Println("Consonants:", c) // 0
}

// Hint: strings.ContainsRune("aeiouAEIOU", r) && unicode.IsLetter(r)

Task 4: Title Case Conversion (Medium)

Convert a string to title case (first letter of each word capitalized, rest lowercase).

package main

import (
    "fmt"
    "strings"
    "unicode"
)

// TODO: implement TitleCase
func TitleCase(s string) string {
    // Use for range to iterate runes
    // Use strings.Builder to build result
    // First letter after space should be upper, rest lower
    var sb strings.Builder
    // your code here
    _ = sb
    return ""
}

func main() {
    fmt.Println(TitleCase("hello world"))         // Hello World
    fmt.Println(TitleCase("the QUICK brown FOX")) // The Quick Brown Fox
    fmt.Println(TitleCase("go programming"))      // Go Programming
}

Task 5: Extract Numbers from String (Medium)

Extract all integer numbers found in a string.

package main

import (
    "fmt"
    "unicode"
)

// TODO: implement ExtractNumbers
func ExtractNumbers(s string) []int {
    // Use for range to iterate runes
    // When you see a digit, accumulate it into a number
    // When a non-digit is seen and you were accumulating, save the number
    // Return all found numbers
}

func main() {
    fmt.Println(ExtractNumbers("abc 123 def 456 ghi"))  // [123 456]
    fmt.Println(ExtractNumbers("order #1234 for $99"))  // [1234 99]
    fmt.Println(ExtractNumbers("no numbers here"))       // []
    fmt.Println(ExtractNumbers("12 and 34"))            // [12 34]
}

Task 6: Run-Length Encoding (Medium)

Compress a string using run-length encoding: consecutive identical characters are replaced by the character and its count.

package main

import (
    "fmt"
    "strings"
)

// TODO: implement RLE
func RLE(s string) string {
    // "aaabbbcc" -> "a3b3c2"
    // "abcd" -> "a1b1c1d1" (or "abcd" if single char)
    // Use for range to iterate runes
    // Use strings.Builder for output
}

func main() {
    fmt.Println(RLE("aaabbbcc"))     // a3b3c2
    fmt.Println(RLE("aabbccdd"))     // a2b2c2d2
    fmt.Println(RLE("abcd"))         // a1b1c1d1
    fmt.Println(RLE(""))             // ""
    fmt.Println(RLE("世世界界界")) // 世2界3
}

Task 7: Caesar Cipher (Medium)

Implement Caesar cipher (shift letters by N positions, wrap around).

package main

import "fmt"

// TODO: implement Caesar
func Caesar(s string, shift int) string {
    // Shift each letter by 'shift' positions
    // 'z' + 1 wraps to 'a', 'Z' + 1 wraps to 'A'
    // Non-letters remain unchanged
    // Hint: use modular arithmetic with (r - 'a' + shift) % 26 + 'a'
}

func main() {
    fmt.Println(Caesar("Hello, World!", 3))  // Khoor, Zruog!
    fmt.Println(Caesar("Khoor, Zruog!", -3)) // Hello, World!
    fmt.Println(Caesar("xyz", 3))            // abc
    fmt.Println(Caesar("Hello 世界", 1))     // Ifmmp 世界
}

Task 8: Find All Positions of a Rune (Hard)

Find all character positions (rune indices, not byte indices) of a given rune in a string.

package main

import "fmt"

// TODO: implement FindAllPositions
// Returns rune (character) indices, not byte indices
func FindAllPositions(s string, target rune) []int {
    // Use for range — i is byte index, count separately for rune index
    // Track rune count separately from byte index
}

func main() {
    positions := FindAllPositions("Hello, World!", 'l')
    fmt.Println(positions) // [2 3 10] (rune/char indices)

    positions = FindAllPositions("Hello, 世界 Hello", 'e')
    fmt.Println(positions) // [1 13] (rune indices)

    positions = FindAllPositions("aaa", 'b')
    fmt.Println(positions) // []
}

Task 9: Word Wrap (Hard)

Wrap text at a maximum character width, breaking only at spaces.

package main

import (
    "fmt"
    "strings"
)

// TODO: implement WordWrap
// Break the text into lines of at most maxWidth characters
// Break only at spaces (do not break words)
func WordWrap(text string, maxWidth int) string {
    // Split into words
    // Group words into lines without exceeding maxWidth
    // Join lines with "\n"
    _ = strings.Builder{}
    return ""
}

func main() {
    text := "The quick brown fox jumps over the lazy dog"
    fmt.Println(WordWrap(text, 15))
    // The quick brown
    // fox jumps over
    // the lazy dog

    fmt.Println(WordWrap("Hello", 10))
    // Hello
}

Task 10: Anagram Check (Hard)

Check if two strings are anagrams of each other (same characters, different order).

package main

import "fmt"

// TODO: implement IsAnagram
// Unicode-safe: work with runes, not bytes
// Ignore spaces and case
func IsAnagram(a, b string) bool {
    // Build character frequency map for a
    // Subtract for characters in b
    // Check if all counts are zero
}

func main() {
    fmt.Println(IsAnagram("listen", "silent"))          // true
    fmt.Println(IsAnagram("hello", "world"))            // false
    fmt.Println(IsAnagram("Astronomer", "Moon starer")) // true (ignoring spaces/case)
    fmt.Println(IsAnagram("rat", "car"))                // false
}

Task 11: String Compression (Expert)

Implement basic string compression: remove consecutive duplicate characters, keeping track of their count. Return the compressed string only if it's shorter.

package main

import (
    "fmt"
    "strings"
)

// TODO: implement Compress
// "aabcccccaaa" -> "a2b1c5a3"
// Return original if compressed version is not shorter
func Compress(s string) string {
    // Use for range to iterate runes
    // Track current rune and count
    // Use strings.Builder for output
    // Compare lengths and return shorter
}

func main() {
    fmt.Println(Compress("aabcccccaaa"))  // a2b1c5a3
    fmt.Println(Compress("abcdef"))       // abcdef (not shorter)
    fmt.Println(Compress("aaaa"))         // a4
    fmt.Println(Compress(""))             // ""
}

Task 12: Unicode Category Counter (Expert)

Count characters in each Unicode category (letters, digits, punctuation, etc.).

package main

import (
    "fmt"
    "unicode"
)

type Stats struct {
    Letters     int
    Digits      int
    Spaces      int
    Punctuation int
    Symbols     int
    Other       int
}

// TODO: implement Analyze
func Analyze(s string) Stats {
    // Use for range to iterate runes
    // Use unicode package to categorize each rune
    // unicode.IsLetter, IsDigit, IsSpace, IsPunct, IsSymbol
}

func main() {
    st := Analyze("Hello, World! 42 + π ≈ 3.14")
    fmt.Printf("Letters: %d\n", st.Letters)     // 10
    fmt.Printf("Digits: %d\n", st.Digits)       // 4 (42, 3, 1, 4)
    fmt.Printf("Spaces: %d\n", st.Spaces)       // 6
    fmt.Printf("Punctuation: %d\n", st.Punctuation) // 2 (comma, exclamation, period)
    fmt.Printf("Symbols: %d\n", st.Symbols)     // includes +, ≈
    fmt.Printf("Other: %d\n", st.Other)         // includes π
}

Bonus Task 13: Longest Common Substring (Expert)

Find the longest common substring of two Unicode strings.

package main

import "fmt"

// TODO: implement LongestCommonSubstring
// Returns the longest string that appears in both a and b
// Unicode-safe (work with runes)
func LongestCommonSubstring(a, b string) string {
    // Convert both to []rune
    // Use dynamic programming
    // Track longest match
}

func main() {
    fmt.Println(LongestCommonSubstring("abcde", "bcdef"))  // "bcde"
    fmt.Println(LongestCommonSubstring("Hello World", "lo W")) // "lo W"
    fmt.Println(LongestCommonSubstring("世界你好", "你好世界")) // "你好" or "世界" (2 chars)
}

Solutions Reference

Task Key Techniques
1 for range count (no []rune)
2 []rune + two-pointer compare
3 for range + unicode.IsLetter + vowel check
4 for range + track word boundary + strings.Builder
5 for range + accumulate digit runes → int
6 for range + count consecutive runes
7 for range + modular arithmetic for shift
8 for range + separate rune counter
9 Word splitting + greedy line filling
10 Frequency map + subtract
11 Run-length encode + length compare
12 for range + unicode package categorization
13 []rune + DP table