add new solutions

This commit is contained in:
kanna5 2026-01-05 16:48:03 +09:00
parent 9c2c959a9b
commit 9a10695e8c
Signed by: kkyy
GPG key ID: 06332F3965E9B0CF
29 changed files with 1074 additions and 2 deletions

4
go.mod
View file

@ -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
)

4
go.sum
View file

@ -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=

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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<<i == num32 {
bitCounts[i] = (bitCounts[i] + 1) % 3
}
}
}
var ret int32
for i := range 32 {
if bitCounts[i] != 0 {
ret |= 1 << i
}
}
return int(ret)
}
var _ = singleNumber

View file

@ -0,0 +1,112 @@
package q146
type lruNode struct {
key, val int
prev, next *lruNode
}
type LRUCache struct {
cap int
index map[int]*lruNode
head, tail *lruNode
nodes []lruNode
p int
}
func Constructor(capacity int) LRUCache {
return LRUCache{
cap: capacity,
index: make(map[int]*lruNode, capacity),
nodes: make([]lruNode, capacity),
}
}
func (c *LRUCache) alloc() *lruNode {
if c.p < len(c.nodes) {
c.p++
return &c.nodes[c.p-1]
}
return nil
}
func (c *LRUCache) touch(node *lruNode) {
if node.prev == nil {
return
}
if c.tail == node {
c.tail = node.prev
} else {
node.next.prev = node.prev
}
node.prev.next = node.next
node.prev = nil
node.next = c.head
c.head.prev = node
c.head = node
}
func (c *LRUCache) evict() *lruNode {
if len(c.index) < c.cap {
return nil
}
node := c.tail
delete(c.index, node.key)
if node.prev == nil {
c.head, c.tail = nil, nil
} else {
c.tail = node.prev
c.tail.next = nil
}
return node
}
func (c *LRUCache) Get(key int) int {
node := c.index[key]
if node == nil {
return -1
}
c.touch(node)
return node.val
}
func (c *LRUCache) Put(key int, value int) {
if c.cap == 0 {
return
}
node := c.index[key]
if node != nil {
node.val = value
c.touch(node)
return
}
node = c.alloc()
if node == nil {
node = c.evict()
*node = lruNode{} // clear
}
node.key, node.val = key, value
c.index[key] = node
node.next = c.head
if c.head != nil {
c.head.prev = node
}
c.head = node
if c.tail == nil {
c.tail = node
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* obj := Constructor(capacity);
* param_1 := obj.Get(key);
* obj.Put(key,value);
*/

View file

@ -0,0 +1,19 @@
package q151
import "strings"
func reverseWords(s string) string {
b := strings.Builder{}
fields := strings.Fields(s)
if len(fields) > 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

View file

@ -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();
*/

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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