---
# System prepended metadata

title: 'Go Leetcode: Array & Hash Table'
tags: [go, leetcode]

---

# Go Leetcode: Array & Hash Table

###### tags: `leetcode` `go`

## Contains Duplicate
### #1
```go=
func containsDuplicate(nums []int) bool {
    // hash table
    // key -> value
    // if value > 1 return true
    idmap := make(map[int]int)
    
    // iterate through the given slice
    for i:=0; i < len(nums); i++ {
        idmap[nums[i]]++
        if idmap[nums[i]] > 1 {return true}
    }
    return false
}
```
### #2 less memory
```go=
func containsDuplicate(nums []int) bool {
    // struct comsumes less memory than integer and bool
    idmap := make(map[int]struct{})
    
    // iterate through the given slice
    for _, v := range nums {
        if _, ok := idmap[v]; ok {
            return true
        } else {
            idmap[v] = struct{}{} // weird syntax
        }
    }
    return false
}
```
### Note
- what is slice
- how to iterate through slice
- how to declare map
- how to assign empty struct
- consider what type to use


## Valid Anagram
### #1
```go=
func isAnagram(s string, t string) bool {
    
    if len(s) != len(t) {return false}
    
    hst := make(map[rune]int)
    for _, r := range s {
        hst[r]++ // init
    }
    for _, r := range t {
        if _, ok := hst[r]; ok {
            hst[r]--
            if hst[r] < 0 {return false}
        } else {
            return false
        }
    }
    return true
}
```
### Note
- what is rune
- how to iterate through string


## Two Sum
### #1
```go=
func twoSum(nums []int, target int) []int {
    hst := make(map[int]int)
    
    for i, v := range nums {
        to_find := target - v
        // find if the other piece in hash table
        if j, ok := hst[to_find]; ok {
            return []int{i, j}
        } else {
            // add self to hash table
            hst[v] = i
        }
    }
    return []int{0, 0}
}
```

## Group Anagrams
### #1 
```go=
import (
    "sort"
    "fmt"
)

func groupAnagrams(strs []string) [][]string {
    // hash each word
    hst := make(map[string][]string)
    
    for _, str := range strs {
        bytes := []byte(str)
        sort.SliceStable(bytes, func(i int, j int) bool{
            return bytes[i] < bytes[j]
        })
        key := string(bytes)
        hst[key] = append(hst[key], str)
    } 
    
    res := make([][]string, 0, len(hst))
    for _, v := range hst {
        res = append(res, v)
    }
    return res
}

```

## Top K Frequent Elements

### #1
```go=
func topKFrequent(nums []int, k int) []int {
    // hash table
    // key: num
    // value: counter
    hst := make(map[int]int)
    for _, n := range nums {
        hst[n]++
    }

    // get the indexes of k max value
    // get the index of maximum value k times
    q := []int{}
    for i:=0; i<k; i++ {
        max_idx := 0
        is_init := true
        for key, val := range hst {
            if is_init || hst[max_idx] < val {
                max_idx = key
            }
            is_init = false
        }
        // append
        q = append(q, max_idx)
        // remove from hst
        delete(hst, max_idx)
    }
    return q
}
```
### #2 custom map struct
faster but takes more mrmory
```go=
import "sort"

type Pair struct {
    Key int
    Value int
}

type PairList []Pair

func (p PairList) Len() int { return len(p) }
func (p PairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p PairList) Less(i, j int) bool { return p[i].Value > p[j].Value } // sort desc

func topKFrequent(nums []int, k int) []int {
    // hash table
    // key: num
    // value: counter
    hst := make(map[int]int)
    for _, n := range nums {
        hst[n]++
    }
    
    plist := make(PairList, len(hst))
    i := 0
    for k, v := range hst {
        plist[i].Key = k
        plist[i].Value = v
        i++
    }
    sort.Sort(plist)

    // get the indexes of k max value
    // get the index of maximum value k times
    q := []int{}
    for i:=0; i<k; i++ {
        // append
        q = append(q, plist[i].Key)
    }
    return q
}
```
### #3 faster than #2

```go=
// ...
q := []int{}
for _, item := range plist[:k] {
    // append
    q = append(q, item.Key)
}
return q
```

### #4 cleaner way to sort

```go=
func topKFrequent(nums []int, k int) []int {
    // key : value -> num : amount
    hst := make(map[int]int)
    for _, n := range nums {
        hst[n]++
    }
    
    // collect keys
    keys := []int{}
    for num, _ := range hst {
        keys = append(keys, num)
    }

    // sort keys by values in hash table
    sort.Slice(keys, func(i, j int) bool {
        return hst[keys[i]] > hst[keys[j]] // desc
    })
    
    return keys[:k]
}
```

### #5 use slice of slice as bucket
use slice of slice as bucket to collect nums
```go=
func topKFrequent(nums []int, k int) []int {
    // special case
    if len(nums) == k { return nums }
    
    // frequency map
    freqs := map[int]int{}
    for _, num := range nums {
        freqs[num]++
    }
    
    // frequency as index
    // collect numbers with same frequency
    nums_len := len(nums)
    bucket := make([][]int, nums_len+1) // index: 0, 1 ... len(nums)
    for num, freq := range freqs {
        bucket[freq] = append(bucket[freq], num)
    }
    
    res := []int{}
    for i:=nums_len; i>0; i-- {
        if len(bucket[i]) > 0 {
            res = append(res, bucket[i]...)
            if len(res) >= k { return res }
        }
    }
    return res
}
```
### #6 manual quick sort (most complicated)

```go=
func topKFrequent(nums []int, k int) []int {
    // special case
    if len(nums) == k { return nums }
    
    // frequency map
    freqs := map[int]int{}
    for _, num := range nums {
        freqs[num]++
    }
    
    keys := []int{}
    for key, _ := range freqs {
        keys = append(keys, key)
    }
    
    // quick sort
    kQuickSort(keys, freqs, k)
    
    return keys[len(keys)-k:]
}

func kQuickSort(slice []int, m map[int]int, k int) {
    if len(slice) <= 1 { return }
    
    kQuickSortRecr(slice, m , 0, len(slice)-1, k)
}

func kQuickSortRecr(slice []int, m map[int]int, start_i, end_i, k int) {
    // end condition
    if start_i >= end_i { return }
    
    // main logic
    piv_i := getPiv(start_i, end_i)
    piv_final := sort(slice, m, start_i, end_i, piv_i)
    
    // divide - DFS right first
    kQuickSortRecr(slice, m, piv_final+1, end_i, k) // right
    if len(slice) - 1 == piv_final + k { return }
    kQuickSortRecr(slice, m, start_i, piv_final-1, k) // left
}

func getPiv(l, r int) int {
    return l + (r - l) / 2
}

func sort(slice []int, m map[int]int, start_i, end_i, piv_i int) int {
    swap(slice, piv_i, end_i)
    curr_piv_i := end_i
    for true {
        for true {
            if start_i == end_i { break }
            if m[slice[start_i]] > m[slice[curr_piv_i]] {
                break
            }
            start_i++
        }
        
        for true {
            if start_i == end_i { break }
            if m[slice[end_i]] < m[slice[curr_piv_i]] {
                break
            }
            end_i--
        }
        
        if start_i == end_i { break }
        swap(slice, end_i, start_i)
    }
    if m[slice[start_i]] >= m[slice[curr_piv_i]] {
        swap(slice, start_i, curr_piv_i)
        curr_piv_i = start_i
    }
    return curr_piv_i
}

func swap(slice []int, i, j int) {
    slice[i], slice[j] = slice[j], slice[i]
}
```
### Note
- how to use `sort`
- sorting of map by key or value

## Product of Array Except Self
solution: https://www.cnblogs.com/grandyang/p/4650187.html

```go=
func productExceptSelf(nums []int) []int {
    length := len(nums)
    res := make([]int, length)
    
    // forward
    res[0] = 1
    for i:=1; i < len(nums); i++ {
        res[i] = res[i-1] * nums[i-1]
    }
    // backward
    right := nums[length-1]
    for i:=length-2; i >= 0; i-- {
        res[i] *= right
        right *= nums[i]
    }

    return res
}
```

## Encode & Decode Strings
solution: https://www.youtube.com/watch?v=B1k_sxOSgv8
```go=
package main

import (
	"fmt"
	"strconv"
)

const SEP string = ":"

func main() {
	list := []string{"#set", "666", "rat"}
	enco := encode(list)
	fmt.Println(enco)
	fmt.Println(decode(enco))
}

func encode(list []string) string {
	str := ""
	for _, w := range list {
		str += fmt.Sprintf("%d%s%s", len(w), SEP, w)
	}
	return str
}

func decode(str string) []string {
	list, i := []string{}, 0

	for i < len(str) {
		sep_i := i
		// find seperator
		for ; sep_i < len(str); sep_i++ {
			if str[sep_i] == SEP[0] {
				break
			}
		}
		// get word length
		length_str := str[i:sep_i]
		length, err := strconv.Atoi(length_str)
		if err != nil {
			panic("err")
		}

		list = append(list, str[sep_i+1:sep_i+1+length])
		i = sep_i + 1 + length
	}

	return list
}

```

### Note
- [efficient details of string append](https://shockerli.net/post/golang-concat-string/)

## Longest Consecutive 
### find start and end of sequences
```go!
func longestConsecutive(nums []int) int {
    set := make(map[int]struct{})
    for _, n := range nums {
        if _, ok := set[n]; !ok {
            set[n] = struct{}{}
        }
    }
    res := 0
    for _, n := range nums {
        // if not start number, continue
        if _, ok := set[n-1]; ok {
            continue
        }
        // else n is a start number
        end := n
        for {
            // no next, means end
            if _, ok := set[end+1]; !ok {
                break
            }
            end++
        }
        res = max(res, end-n+1)
    }
    return res
}

func max(a, b int) int {
    if a > b { return a }
    return b
}
```
### Union Find
```go=
type UnionFind struct {
    Roots map[int]int
    Lengths map[int]int
}

func (this *UnionFind) Union (a, b int) {
    root_a := this.FindRoot(a)
    root_b := this.FindRoot(b)
    if root_a != root_b {
        this.Roots[root_a] = root_b
        this.Lengths[root_b] += this.Lengths[root_a]
    }
}

func (this *UnionFind) FindRoot (a int) int {
    root := this.Roots[a]
    if root == a { return a }
    this.Roots[a] = this.FindRoot(root)
    return this.Roots[a]
}

func createUnionFind(nums []int) *UnionFind {
    roots, lengths := make(map[int]int), make(map[int]int)
    for _, n := range nums {
        roots[n] = n
        lengths[n] = 1
    }
    return &UnionFind{roots, lengths}
}

func longestConsecutive(nums []int) int {
    uf := createUnionFind(nums)
    longest := 0
    for _, n := range nums {
        if _, ok := uf.Roots[n-1]; ok {
            uf.Union(n, n-1)
        }
        if _, ok := uf.Roots[n+1]; ok {
            uf.Union(n, n+1)
        }
        // length := uf.Lengths[uf.FindRoot(n)]
        longest = max(longest, uf.Lengths[uf.FindRoot(n)])
    }
    return longest
}

func max(a, b int) int {
    if a>b { return a }
    return b
}
```
### Simliar to unionfind but faster!
```go!
func longestConsecutive(nums []int) int {
    if len(nums) == 0 {
        return 0
    }
    max := 0
    bk := make(map[int]int)
    for _, num := range nums {
        if _, ok := bk[num]; ok {
            continue
        }
        left, right := 0, 0
        if val, ok := bk[num-1]; ok {
            left = val
        }
        if val, ok := bk[num+1]; ok {
            right = val
        }
        bk[num] = left + right + 1
        
        if max < bk[num] {
            max = bk[num]
        }
        
        bk[num-left] = bk[num]
        bk[num+right] = bk[num]
    }
    return max
}
```

## Valid Sudoku

### #1
```go=
func isValidSudoku(board [][]byte) bool {

    for i:=0; i<9; i++ {
        // validate rows
        if !validSlice(board[i]) {
            return false
        }
        
        // validate cols
        buk := make([]byte, 9)
        for j:=0; j<9; j++ {
            buk[j] = board[j][i]
        }
        if !validSlice(buk) {
            return false
        }
    }
    // validate square
    r_i, c_i := 0, 0
    for r_i < 9 {
        buk := []byte{}

        for _, row := range board[r_i:r_i+3] {   
            for _, num := range row[c_i:c_i+3] {
                buk = append(buk, num)
            }
        }

        if !validSlice(buk) { return false }
        if c_i == 6 {
            c_i = 0
            r_i += 3
        } else {
            c_i += 3
        }
    }
    
    return true
}

func validSlice(s []byte) bool {
    hst := make(map[byte]struct{})
    for _, num := range s {
        if string(num) == "." { continue }
        if _, ok := hst[num]; ok {
            return false
        } else {
            hst[num] = struct{}{}
        }
    }
    return true
}
```