diff --git a/go.mod b/go.mod index 9e38376..adecd14 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,6 @@ require ( require ( github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // indirect ) diff --git a/go.sum b/go.sum index 0aa4e6a..3151c8d 100644 --- a/go.sum +++ b/go.sum @@ -9,5 +9,9 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= diff --git a/solutions/0/q22/solution.go b/solutions/0/q22/solution.go new file mode 100644 index 0000000..4389b45 --- /dev/null +++ b/solutions/0/q22/solution.go @@ -0,0 +1,27 @@ +package q22 + +func gen(n, lvl, used int, buf []byte, ret []string) []string { + if buf == nil { + buf = make([]byte, 0, n*2) + } + if len(buf) == n*2 { + return append(ret, string(buf)) + } + + if used < n { + buf = append(buf, '(') + ret = gen(n, lvl+1, used+1, buf, ret) + buf = buf[:len(buf)-1] + } + if lvl > 0 { + buf = append(buf, ')') + ret = gen(n, lvl-1, used, buf, ret) + } + return ret +} + +func generateParenthesis(n int) []string { + return gen(n, 0, 0, nil, nil) +} + +var _ = generateParenthesis diff --git a/solutions/0/q25/solution.go b/solutions/0/q25/solution.go new file mode 100644 index 0000000..118c3a0 --- /dev/null +++ b/solutions/0/q25/solution.go @@ -0,0 +1,51 @@ +package q25 + +type ListNode struct { + Val int + Next *ListNode +} + +func reverse(begin *ListNode, k int) (newHead, newTail *ListNode) { + tail := begin + for range k - 1 { + if tail.Next == nil { + return begin, tail // no enough nodes + } + tail = tail.Next + } + + // Reverse + cur := begin + prev := tail.Next + for range k - 1 { + t := cur.Next + cur.Next = prev + prev, cur = cur, t + } + cur.Next = prev + return cur, begin +} + +func reverseKGroup(head *ListNode, k int) *ListNode { + if k < 2 { + return head + } + + var ret, prevTail *ListNode + p := head + for p != nil { + newHead, newTail := reverse(p, k) + if ret == nil { + ret = newHead + } + if prevTail != nil { + prevTail.Next = newHead + } + prevTail = newTail + p = newTail.Next + } + + return ret +} + +var _ = reverseKGroup diff --git a/solutions/0/q42/solution.go b/solutions/0/q42/solution.go new file mode 100644 index 0000000..ed790a1 --- /dev/null +++ b/solutions/0/q42/solution.go @@ -0,0 +1,36 @@ +package q42 + +func trap(height []int) int { + water := 0 + mid := 0 + + // From left + maxHeight, stash := 0, 0 + for i, h := range height { + if h >= maxHeight { + maxHeight = h + water += stash + stash = 0 + mid = i + } else { + stash += maxHeight - h + } + } + + // From right + maxHeight, stash = 0, 0 + for i := len(height) - 1; i >= mid; i-- { + h := height[i] + if h >= maxHeight { + maxHeight = h + water += stash + stash = 0 + } else { + stash += maxHeight - h + } + } + + return water +} + +var _ = trap diff --git a/solutions/0/q5/solution.go b/solutions/0/q5/solution.go new file mode 100644 index 0000000..6228213 --- /dev/null +++ b/solutions/0/q5/solution.go @@ -0,0 +1,37 @@ +package q5 + +// Note: Although it can be done in O(N) with, e.g., Manacher's algorithm, the +// input size is small enough to brute-force. + +func expand(s string, l, r int) (int, int) { + for l > 0 && r < len(s)-1 && s[l-1] == s[r+1] { + l-- + r++ + } + return l, r +} + +func longestPalindrome(s string) string { + maxLen, mL, mR := 0, 0, 0 + + for c := range len(s) { + l, r := expand(s, c, c) + len_ := r - l + 1 + if len_ > maxLen { + maxLen, mL, mR = len_, l, r + } + } + + for c := range len(s) - 1 { + if s[c] == s[c+1] { + l, r := expand(s, c, c+1) + len_ := r - l + 1 + if len_ > maxLen { + maxLen, mL, mR = len_, l, r + } + } + } + return s[mL : mR+1] +} + +var _ = longestPalindrome diff --git a/solutions/0/q50/solution.go b/solutions/0/q50/solution.go new file mode 100644 index 0000000..2e88b24 --- /dev/null +++ b/solutions/0/q50/solution.go @@ -0,0 +1,25 @@ +package q50 + +func myPow(x float64, n int) float64 { + neg := n < 0 + if neg { + n = -n + } + + var ret float64 = 1 + for n > 0 { + v, p := x, 1 + for p*2 < n { + p *= 2 + v *= v + } + n -= p + ret *= v + } + if neg { + return 1 / ret + } + return ret +} + +var _ = myPow diff --git a/solutions/0/q56/solution.go b/solutions/0/q56/solution.go new file mode 100644 index 0000000..920f87a --- /dev/null +++ b/solutions/0/q56/solution.go @@ -0,0 +1,20 @@ +package q56 + +import "slices" + +func merge(intervals [][]int) [][]int { + slices.SortFunc(intervals, func(a, b []int) int { return a[0] - b[0] }) + + p := 0 + for i := 1; i < len(intervals); i++ { + if intervals[p][1] >= intervals[i][0] { + intervals[p][1] = max(intervals[p][1], intervals[i][1]) + } else { + p++ + intervals[p][0], intervals[p][1] = intervals[i][0], intervals[i][1] + } + } + return intervals[:min(p+1, len(intervals))] +} + +var _ = merge diff --git a/solutions/0/q82/solution.go b/solutions/0/q82/solution.go new file mode 100644 index 0000000..a40254d --- /dev/null +++ b/solutions/0/q82/solution.go @@ -0,0 +1,29 @@ +package q82 + +type ListNode struct { + Val int + Next *ListNode +} + +func deleteDuplicates(head *ListNode) *ListNode { + root := ListNode{} + last := &root + + c := head + for c != nil { + if c.Next != nil && c.Next.Val == c.Val { + dupVal := c.Val + for c != nil && c.Val == dupVal { + c = c.Next + } + continue + } + last.Next = c + last = c + c = c.Next + last.Next = nil + } + return root.Next +} + +var _ = deleteDuplicates diff --git a/solutions/1/q105/solution.go b/solutions/1/q105/solution.go new file mode 100644 index 0000000..b645da6 --- /dev/null +++ b/solutions/1/q105/solution.go @@ -0,0 +1,35 @@ +package q105 + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func bld(preorder []int, inorder map[int]int, pL, pR, iL, iR int) *TreeNode { + if pL == pR { + return nil + } + + val := preorder[pL] + p := inorder[val] // position of val in "inorder" + + left := bld(preorder, inorder, pL+1, pL+1+p-iL, iL, p) + right := bld(preorder, inorder, pL+1+p-iL, pR, p+1, iR) + + return &TreeNode{ + Val: val, + Left: left, + Right: right, + } +} + +func buildTree(preorder []int, inorder []int) *TreeNode { + iIdx := make(map[int]int, len(inorder)) + for i := range inorder { + iIdx[inorder[i]] = i + } + return bld(preorder, iIdx, 0, len(preorder), 0, len(preorder)) +} + +var _ = buildTree diff --git a/solutions/1/q114/solution.go b/solutions/1/q114/solution.go new file mode 100644 index 0000000..b52d640 --- /dev/null +++ b/solutions/1/q114/solution.go @@ -0,0 +1,35 @@ +package q114 + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func fl(node *TreeNode) (head, tail *TreeNode) { + if node == nil { + return nil, nil + } + head, tail = node, node + + lhead, ltail := fl(node.Left) + rhead, rtail := fl(node.Right) + + if lhead != nil { + node.Left = nil + node.Right = lhead + tail = ltail + } + + if rhead != nil { + tail.Right = rhead + tail = rtail + } + return +} + +func flatten(root *TreeNode) { + fl(root) +} + +var _ = flatten diff --git a/solutions/1/q127/solution.go b/solutions/1/q127/solution.go new file mode 100644 index 0000000..0899383 --- /dev/null +++ b/solutions/1/q127/solution.go @@ -0,0 +1,63 @@ +package q127 + +// Ideas for improvement: use a hashmap to index strings instead of an O(n^2) +// comparison and neighbor matrix; use bidirectional BFS. + +func reachable(a, b string) bool { + diff := false + for i := range len(a) { + if a[i] != b[i] { + if diff { + return false + } + diff = true + } + } + return diff // exactly one different char +} + +func ladderLength(beginWord string, endWord string, wordList []string) int { + target := -1 + neighbors := make([][]int, len(wordList)) + + for i := range wordList { + if target == -1 && wordList[i] == endWord { + target = i + } + for j := i + 1; j < len(wordList); j++ { + if reachable(wordList[i], wordList[j]) { + neighbors[i] = append(neighbors[i], j) + neighbors[j] = append(neighbors[j], i) + } + } + } + if target == -1 { + return 0 + } + + seen := make([]bool, len(wordList)) + queue := make([][2]int, 0, len(wordList)) // index, steps + for i := range wordList { + if reachable(beginWord, wordList[i]) { + seen[i] = true + queue = append(queue, [2]int{i, 2}) + } + } + for ; len(queue) > 0; queue = queue[1:] { + id, step := queue[0][0], queue[0][1] + if id == target { + return step + } + + for _, n := range neighbors[id] { + if !seen[n] { + seen[n] = true + queue = append(queue, [2]int{n, step + 1}) + } + } + } + + return 0 +} + +var _ = ladderLength diff --git a/solutions/1/q133/solution.go b/solutions/1/q133/solution.go new file mode 100644 index 0000000..00111a9 --- /dev/null +++ b/solutions/1/q133/solution.go @@ -0,0 +1,39 @@ +package q133 + +type Node struct { + Val int + Neighbors []*Node +} + +func cloneGraph(node *Node) *Node { + if node == nil { + return nil + } + seen := map[*Node]*Node{} + + queue := []*Node{node} + for ; len(queue) > 0; queue = queue[1:] { + cur := queue[0] + if _, ok := seen[cur]; ok { + continue + } + cloned := &Node{ + Val: cur.Val, + Neighbors: []*Node{}, + } + seen[cur] = cloned + for _, n := range cur.Neighbors { + if nCloned, ok := seen[n]; ok { + // Link + cloned.Neighbors = append(cloned.Neighbors, nCloned) + nCloned.Neighbors = append(nCloned.Neighbors, cloned) + } else { + // Add to queue + queue = append(queue, n) + } + } + } + return seen[node] +} + +var _ = cloneGraph diff --git a/solutions/1/q137/solution.go b/solutions/1/q137/solution.go new file mode 100644 index 0000000..6e7c50c --- /dev/null +++ b/solutions/1/q137/solution.go @@ -0,0 +1,22 @@ +package q137 + +func singleNumber(nums []int) int { + bitCounts := make([]uint8, 32) + for _, num := range nums { + num32 := int32(num) + for i := range 32 { + if num32|1< 0 { + b.WriteString(fields[len(fields)-1]) + } + for i := len(fields) - 2; i >= 0; i-- { + b.WriteByte(' ') + b.WriteString(fields[i]) + } + + return b.String() +} + +var _ = reverseWords diff --git a/solutions/1/q155/solution.go b/solutions/1/q155/solution.go new file mode 100644 index 0000000..043fa1d --- /dev/null +++ b/solutions/1/q155/solution.go @@ -0,0 +1,44 @@ +package q155 + +type stackElem struct { + val, min int +} + +type MinStack struct { + stack []stackElem +} + +func Constructor() MinStack { + return MinStack{} +} + +func (s *MinStack) Push(val int) { + minVal := val + if len(s.stack) > 0 { + minVal = min(minVal, s.GetMin()) + } + s.stack = append(s.stack, stackElem{ + val: val, min: minVal, + }) +} + +func (s *MinStack) Pop() { + s.stack = s.stack[:len(s.stack)-1] +} + +func (s *MinStack) Top() int { + return s.stack[len(s.stack)-1].val +} + +func (s *MinStack) GetMin() int { + return s.stack[len(s.stack)-1].min +} + +/** + * Your MinStack object will be instantiated and called as such: + * obj := Constructor(); + * obj.Push(val); + * obj.Pop(); + * param_3 := obj.Top(); + * param_4 := obj.GetMin(); + */ diff --git a/solutions/1/q172/solution.go b/solutions/1/q172/solution.go new file mode 100644 index 0000000..045345e --- /dev/null +++ b/solutions/1/q172/solution.go @@ -0,0 +1,21 @@ +package q172 + +// Note: actually, counting 5 alone is enough since 2 certainly occurs more than 5. + +func trailingZeroes(n int) int { + count2, count5 := 0, 0 + for i := 2; i <= n; i++ { + num := i + for num%2 == 0 { + num /= 2 + count2++ + } + for num%5 == 0 { + num /= 5 + count5++ + } + } + return min(count2, count5) +} + +var _ = trailingZeroes diff --git a/solutions/1/q198/solution.go b/solutions/1/q198/solution.go new file mode 100644 index 0000000..c72252e --- /dev/null +++ b/solutions/1/q198/solution.go @@ -0,0 +1,13 @@ +package q198 + +func rob(nums []int) int { + if len(nums) > 1 { + nums[1] = max(nums[0], nums[1]) + } + for i := 2; i < len(nums); i++ { + nums[i] = max(nums[i-2]+nums[i], nums[i-1]) + } + return nums[len(nums)-1] +} + +var _ = rob diff --git a/solutions/11/q1161/solution.go b/solutions/11/q1161/solution.go new file mode 100644 index 0000000..6aa3884 --- /dev/null +++ b/solutions/11/q1161/solution.go @@ -0,0 +1,43 @@ +package q1161 + +import "math" + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func maxLevelSum(root *TreeNode) int { + type qElem struct { + node *TreeNode + level int + } + queue := make([]qElem, 0, 256) + queue = append(queue, qElem{root, 1}) + + maxSum, maxLvl := math.MinInt, 0 + sum, lvl := 0, 1 + for ; len(queue) > 0; queue = queue[1:] { + cur := &queue[0] + if cur.level != lvl { + if sum > maxSum { + maxSum, maxLvl = sum, lvl + } + sum, lvl = 0, cur.level + } + sum += cur.node.Val + if cur.node.Left != nil { + queue = append(queue, qElem{cur.node.Left, cur.level + 1}) + } + if cur.node.Right != nil { + queue = append(queue, qElem{cur.node.Right, cur.level + 1}) + } + } + if sum > maxSum { + return lvl + } + return maxLvl +} + +var _ = maxLevelSum diff --git a/solutions/13/q1339/solution.go b/solutions/13/q1339/solution.go new file mode 100644 index 0000000..627f178 --- /dev/null +++ b/solutions/13/q1339/solution.go @@ -0,0 +1,45 @@ +package q1339 + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func sumSumTrees(node *TreeNode) int { + if node == nil { + return 0 + } + node.Val += sumSumTrees(node.Left) + sumSumTrees(node.Right) + return node.Val +} + +func findNearest(node *TreeNode, target int) int { + if node == nil { + return -1 + } + ret := node.Val + l, r := findNearest(node.Left, target), findNearest(node.Right, target) + if abs(l-target) < abs(ret-target) { + ret = l + } + if abs(r-target) < abs(ret-target) { + ret = r + } + return ret +} + +func abs(n int) int { + if n < 0 { + return -n + } + return n +} + +func maxProduct(root *TreeNode) int { + totalSum := sumSumTrees(root) + nearest := findNearest(root, totalSum/2) + return nearest * (totalSum - nearest) % (1e9 + 7) +} + +var _ = maxProduct diff --git a/solutions/19/q1975/solution.go b/solutions/19/q1975/solution.go new file mode 100644 index 0000000..0c576c7 --- /dev/null +++ b/solutions/19/q1975/solution.go @@ -0,0 +1,40 @@ +package q1975 + +import "math" + +func abs(i int) int { + if i < 0 { + return -i + } + return i +} + +func maxMatrixSum(matrix [][]int) int64 { + var sum int64 + min_ := math.MaxInt + hasZero := false + nNeg := 0 + + for i := range matrix { + for _, num := range matrix[i] { + if num < 0 { + nNeg++ + } + if num == 0 { + hasZero = true + } + num = abs(num) + sum += int64(num) + if num < min_ { + min_ = num + } + } + } + + if hasZero || nNeg%2 == 0 { + return sum + } + return sum - 2*int64(min_) +} + +var _ = maxMatrixSum diff --git a/solutions/2/q207/solution.go b/solutions/2/q207/solution.go new file mode 100644 index 0000000..a7a223e --- /dev/null +++ b/solutions/2/q207/solution.go @@ -0,0 +1,37 @@ +package q207 + +func canFinish(numCourses int, prerequisites [][]int) bool { + nDeps := make([]int, numCourses) + revDeps := make([][]int, numCourses) + + for i := range prerequisites { + course, prereq := prerequisites[i][0], prerequisites[i][1] + nDeps[course]++ + revDeps[prereq] = append(revDeps[prereq], course) + } + + queue := []int{} + for i := range numCourses { + if nDeps[i] == 0 && len(revDeps) > 0 { + queue = append(queue, i) + } + } + for ; len(queue) > 0; queue = queue[1:] { + course := queue[0] + for _, r := range revDeps[course] { + nDeps[r]-- + if nDeps[r] == 0 { + queue = append(queue, r) + } + } + } + + for _, n := range nDeps { + if n > 0 { + return false + } + } + return true +} + +var _ = canFinish diff --git a/solutions/2/q212/solution.go b/solutions/2/q212/solution.go new file mode 100644 index 0000000..665cd7b --- /dev/null +++ b/solutions/2/q212/solution.go @@ -0,0 +1,89 @@ +package q212 + +type TrieNode struct { + children [26]*TrieNode + word *string +} + +func trieIdx(char byte) int8 { + if char < 'a' || char > 'z' { + return -1 + } + return int8(char - 'a') +} + +func allocator(bulkSize int) func() *TrieNode { + var v []TrieNode + p := 0 + + return func() *TrieNode { + if v == nil || p == bulkSize { + v = make([]TrieNode, bulkSize) + p = 0 + } + p++ + return &v[p-1] + } +} + +func buildTrie(words []string) *TrieNode { + alloc := allocator(128) + root := alloc() + for _, word := range words { + p := root + for i := range len(word) { + idx := trieIdx(word[i]) + if idx < 0 { + continue + } + if p.children[idx] == nil { + p.children[idx] = alloc() + } + p = p.children[idx] + } + p.word = &word + } + return root +} + +type Coord [2]int8 + +func find(board [][]byte, coord Coord, trie *TrieNode, found *[]string) { + if coord[0] < 0 || coord[1] < 0 || + int(coord[0]) >= len(board) || int(coord[1]) >= len(board[0]) { + return + } + c := board[coord[0]][coord[1]] + idx := trieIdx(c) + if idx == -1 || trie.children[idx] == nil { + return + } + // Mark visited + board[coord[0]][coord[1]] = '.' + + trie = trie.children[idx] + if trie.word != nil { + *found = append(*found, *trie.word) + trie.word = nil // dedup + } + + find(board, Coord{coord[0] + 1, coord[1]}, trie, found) + find(board, Coord{coord[0] - 1, coord[1]}, trie, found) + find(board, Coord{coord[0], coord[1] + 1}, trie, found) + find(board, Coord{coord[0], coord[1] - 1}, trie, found) + board[coord[0]][coord[1]] = c +} + +func findWords(board [][]byte, words []string) []string { + trie := buildTrie(words) + found := []string{} + + for row := range board { + for col := range board[0] { + find(board, Coord{int8(row), int8(col)}, trie, &found) + } + } + return found +} + +var _ = findWords diff --git a/solutions/2/q221/solution.go b/solutions/2/q221/solution.go new file mode 100644 index 0000000..f08d92a --- /dev/null +++ b/solutions/2/q221/solution.go @@ -0,0 +1,26 @@ +package q221 + +func maximalSquare(matrix [][]byte) int { + w, h := len(matrix[0]), len(matrix) + + maxSq := make([]int16, w+h) + maxV := make([]int16, w) + ret := 0 + for y := range h { + var maxH int16 + for x := range w { + if matrix[y][x] == '0' { + maxH, maxV[x], maxSq[x-y+h] = 0, 0, 0 + continue + } + + maxH++ + maxV[x]++ + maxSq[x-y+h] = min(maxH, maxV[x], maxSq[x-y+h]+1) + ret = max(ret, int(maxSq[x-y+h])) + } + } + return ret * ret +} + +var _ = maximalSquare diff --git a/solutions/2/q230/solution.go b/solutions/2/q230/solution.go new file mode 100644 index 0000000..6f4e362 --- /dev/null +++ b/solutions/2/q230/solution.go @@ -0,0 +1,35 @@ +package q230 + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func findKth(node *TreeNode, k, current int) (int, *int) { + if node == nil { + return current, nil + } + + current, ret := findKth(node.Left, k, current) + if ret != nil { + return current, ret + } + + current += 1 + if current == k { + return current, &node.Val + } + + return findKth(node.Right, k, current) +} + +func kthSmallest(root *TreeNode, k int) int { + _, kth := findKth(root, k, 0) + if kth == nil { + return 0 + } + return *kth +} + +var _ = kthSmallest diff --git a/solutions/3/q322/solution.go b/solutions/3/q322/solution.go new file mode 100644 index 0000000..81e85af --- /dev/null +++ b/solutions/3/q322/solution.go @@ -0,0 +1,31 @@ +package q322 + +// Note: The cache size only needs to be min(max(coins), amount). + +func coinChange(coins []int, amount int) int { + if amount == 0 { + return 0 + } + + cache := make([]int, amount+1) + cache[0] = amount + 1 + for p := 1; p < len(cache); p *= 2 { + copy(cache[p:], cache[:p]) // fill with MAX+1 + } + cache[0] = 0 + + for i := 1; i < len(cache); i++ { + for _, c := range coins { + if (i - c) < 0 { + continue + } + cache[i] = min(cache[i], cache[i-c]+1) + } + } + if cache[amount] > amount { + return -1 + } + return cache[amount] +} + +var _ = coinChange diff --git a/solutions/4/q433/solution.go b/solutions/4/q433/solution.go new file mode 100644 index 0000000..cd8b84e --- /dev/null +++ b/solutions/4/q433/solution.go @@ -0,0 +1,71 @@ +package q433 + +import "slices" + +func canMutate(a, b string) bool { + diff := false + for i := range len(a) { + if a[i] != b[i] { + if diff { + return false + } + diff = true + } + } + return diff // exactly one mutation +} + +func minMutation(startGene string, endGene string, bank []string) int { + reachables := make([][]int, len(bank)) + initial := []int{} + target := -1 + for i := range len(bank) - 1 { + for j := i + 1; j < len(bank); j++ { + if canMutate(bank[i], bank[j]) { + reachables[i] = append(reachables[i], j) + reachables[j] = append(reachables[j], i) + } + } + } + for i := range bank { + if bank[i] == endGene { + target = i + } + if canMutate(startGene, bank[i]) { + if i == target { + return 1 + } + initial = append(initial, i) + } + } + if target == -1 { + return -1 + } + + type qElem struct { + path []int + } + queue := make([]qElem, 0, len(initial)*2) + for _, i := range initial { + queue = append(queue, qElem{path: []int{i}}) + } + + for ; len(queue) > 0; queue = queue[1:] { + cur := queue[0].path + last := cur[len(cur)-1] + next := reachables[last] + for _, n := range next { + if n == target { + return len(cur) + 1 + } + if slices.Contains(cur, n) { + continue + } + queue = append(queue, qElem{path: append(cur, n)}) + } + } + + return -1 +} + +var _ = minMutation diff --git a/solutions/4/q452/solution.go b/solutions/4/q452/solution.go new file mode 100644 index 0000000..e93b6b2 --- /dev/null +++ b/solutions/4/q452/solution.go @@ -0,0 +1,23 @@ +package q452 + +import "slices" + +func findMinArrowShots(points [][]int) int { + slices.SortFunc(points, func(a, b []int) int { return a[0] - b[0] }) + arrows := 1 + prev := points[0] + + for i := 1; i < len(points); i++ { + cur := points[i] + if cur[0] > prev[1] { + arrows++ + prev = cur + continue + } + prev[0] = max(prev[0], cur[0]) + prev[1] = min(prev[1], cur[1]) + } + return arrows +} + +var _ = findMinArrowShots