Skip to content

Go: Chapter 2 Hash Maps and Sets #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions go/Hash Maps and Sets/geometric_sequence_triplets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
func geometricSequenceTriplets(nums []int, r int) int {
// Use 'map' to ensure the default value of 0 is returned when
// accessing a key that doesn’t exist in the hash map. This effectively sets
// the default frequency of all elements to 0.
leftMap := make(map[int]int)
rightMap := make(map[int]int)
count := 0
// Populate 'rightMap' with the frequency of each element in the array.
for _, x := range nums {
rightMap[x]++
}
// Search for geometric triplets that have x as the center.
for _, x := range nums {
// Decrement the frequency of x in 'rightMap' since x is now being
// processed and is no longer to the right.
rightMap[x]--
if x%r == 0 {
count += leftMap[x/r] * rightMap[x*r]
}
// Increment the frequency of x in 'leftMap' since it'll be a part of the
// left side of the array once we iterate to the next value of x.
leftMap[x]++
}
return count
}
27 changes: 27 additions & 0 deletions go/Hash Maps and Sets/longest_chain_of_consecutive_numbers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
func longestChainOfConsecutiveNumbers(nums []int) int {
if len(nums) == 0 {
return 0
}
numSet := make(map[int]bool)
for _, num := range nums {
numSet[num] = true
}
longestChain := 0
for num := range numSet {
// If the current number is the smallest number in its chain, search for
// the length of its chain.
if !numSet[num-1] {
currentNum := num
currentChain := 1
// Continue to find the next consecutive numbers in the chain.
for numSet[currentNum+1] {
currentNum++
currentChain++
}
if currentChain > longestChain {
longestChain = currentChain
}
}
}
return longestChain
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
func longestChainOfConsecutiveNumbersBruteForce(nums []int) int {
if len(nums) == 0 {
return 0
}
longestChain := 0
// Look for chains of consecutive numbers that start from each number.
for _, num := range nums {
currentNum := num
currentChain := 1
// Continue to find the next consecutive numbers in the chain.
for contains(nums, currentNum+1) {
currentNum++
currentChain++
}
if currentChain > longestChain {
longestChain = currentChain
}
}
return longestChain
}

// In the Python code, the while loop checks (current_num +1) in nums.
// So the helper function 'contains' is needed.
func contains(nums []int, target int) bool {
for _, n := range nums {
if n == target {
return true
}
}
return false
}
11 changes: 11 additions & 0 deletions go/Hash Maps and Sets/pair_sum_unsorted.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
func pairSumUnsorted(nums []int, target int) []int {
hashmap := make(map[int]int)
for i, x := range nums {
complement := target - x
if idx, exists := hashmap[complement]; exists {
return []int{idx, i}
}
hashmap[x] = i
}
return nil
}
15 changes: 15 additions & 0 deletions go/Hash Maps and Sets/pair_sum_unsorted_two_pass.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
func pairSumUnsortedTwoPass(nums []int, target int) []int {
numMap := make(map[int]int)
// First pass: Populate the hash map with each number and its index.
for i, num := range nums {
numMap[num] = i
}
// Second pass: Check for each number's complement in the hash map.
for i, num := range nums {
complement := target - num
if idx, ok := numMap[complement]; ok && idx != i {
return []int{i, idx}
}
}
return nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, I forgot to leave here the same suggestion to return an empty list instead of nil.

Copy link
Contributor

@aikhelis aikhelis Feb 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm resolving this comment, as per our chat in Discord: Returning nil is a common and idiomatic way in Go to indicate the absence of a result, as it differentiates between "no result" and "an empty result."

We should keep 'nil' here.

}
47 changes: 47 additions & 0 deletions go/Hash Maps and Sets/verify_sudoku_board.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
func verifySudokuBoard(board [][]int) bool {
// Create hash sets for each row, column, and subgrid to keep
// track of numbers previously seen on any given row, column, or
// subgrid.
rowSets := make([]map[int]struct{}, 9)
columnSets := make([]map[int]struct{}, 9)
subgridSets := make([][]map[int]struct{}, 3)

for i := range rowSets {
rowSets[i] = make(map[int]struct{})
}
for i := range columnSets {
columnSets[i] = make(map[int]struct{})
}
for i := range subgridSets {
subgridSets[i] = make([]map[int]struct{}, 3)
for j := range subgridSets[i] {
subgridSets[i][j] = make(map[int]struct{})
}
}

for r := 0; r < 9; r++ {
for c := 0; c < 9; c++ {
num := board[r][c]
if num == 0 {
continue
}
// Check if 'num' has been seen in the current row,
// column, or subgrid.
if _, exists := rowSets[r][num]; exists {
return false
}
if _, exists := columnSets[c][num]; exists {
return false
}
if _, exists := subgridSets[r/3][c/3][num]; exists {
return false
}
// If we passed the above checks, mark this value as seen
// by adding it to its corresponding hash sets.
rowSets[r][num] = struct{}{}
columnSets[c][num] = struct{}{}
subgridSets[r/3][c/3][num] = struct{}{}
}
}
return true
}
56 changes: 56 additions & 0 deletions go/Hash Maps and Sets/zero_striping.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
func zeroStriping(matrix [][]int) {
if len(matrix) == 0 || len(matrix[0]) == 0 {
return
}
m, n := len(matrix), len(matrix[0])
// Check if the first row initially contains a zero.
firstRowHasZero := false
for c := 0; c < n; c++ {
if matrix[0][c] == 0 {
firstRowHasZero = true
break
}
}
// Check if the first column initially contains a zero.
firstColHasZero := false
for r := 0; r < m; r++ {
if matrix[r][0] == 0 {
firstColHasZero = true
break
}
}
// Use the first row and column as markers. If an element in the
// submatrix is zero, mark its corresponding row and column in the
// first row and column as 0.
for r := 1; r < m; r++ {
for c := 1; c < n; c++ {
if matrix[r][c] == 0 {
matrix[0][c] = 0
matrix[r][0] = 0
}
}
}
// Update the submatrix using the markers in the first row and
// column.
for r := 1; r < m; r++ {
for c := 1; c < n; c++ {
if matrix[0][c] == 0 || matrix[r][0] == 0 {
matrix[r][c] = 0
}
}
}
// If the first row had a zero initially, set all elements in the
// first row to zero.
if firstRowHasZero {
for c := 0; c < n; c++ {
matrix[0][c] = 0
}
}
// If the first column had a zero initially, set all elements in
// the first column to zero.
if firstColHasZero {
for r := 0; r < m; r++ {
matrix[r][0] = 0
}
}
}
30 changes: 30 additions & 0 deletions go/Hash Maps and Sets/zero_striping_hash_sets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
func zeroStripingHashSets(matrix [][]int) {
if len(matrix) == 0 || len(matrix[0]) == 0 {
return
}
m, n := len(matrix), len(matrix[0])
zeroRows := make(map[int]struct{})
zeroCols := make(map[int]struct{})
// Pass 1: Traverse through the matrix to identify the rows and
// columns containing zeros and store their indexes in the
// appropriate hash sets.
for r := 0; r < m; r++ {
for c := 0; c < n; c++ {
if matrix[r][c] == 0 {
zeroRows[r] = struct{}{}
zeroCols[c] = struct{}{}
}
}
}
// Pass 2: Set any cell in the matrix to zero if its row index is
// in 'zero_rows' or its column index is in 'zero_cols'.
for r := 0; r < m; r++ {
for c := 0; c < n; c++ {
if _, ok := zeroRows[r]; ok {
matrix[r][c] = 0
} else if _, ok := zeroCols[c]; ok {
matrix[r][c] = 0
}
}
}
}