add new solutions

This commit is contained in:
kanna5 2026-01-05 16:48:03 +09:00
parent d798d5e8c9
commit 886b5e0a8e
Signed by: kkyy
GPG key ID: 06332F3965E9B0CF
34 changed files with 1164 additions and 0 deletions

View file

@ -0,0 +1,39 @@
package q12
import "strings"
var mapping = []struct {
string
int
}{
{"I", 1},
{"IV", 4},
{"V", 5},
{"IX", 9},
{"X", 10},
{"XL", 40},
{"L", 50},
{"XC", 90},
{"C", 100},
{"CD", 400},
{"D", 500},
{"CM", 900},
{"M", 1000},
}
func intToRoman(num int) string {
b := &strings.Builder{}
for i := len(mapping) - 1; i >= 0; i-- {
for num >= mapping[i].int {
num -= mapping[i].int
b.WriteString(mapping[i].string)
}
if num == 0 {
break
}
}
return b.String()
}
var _ = intToRoman

View file

@ -0,0 +1,26 @@
package q19
type ListNode struct {
Val int
Next *ListNode
}
func removeNthFromEnd(head *ListNode, n int) *ListNode {
stub := &ListNode{Next: head}
probe := stub
for range n {
probe = probe.Next
}
prev := stub
for probe.Next != nil {
probe = probe.Next
prev = prev.Next
}
prev.Next = prev.Next.Next
return stub.Next
}
var _ = removeNthFromEnd

View file

@ -0,0 +1,20 @@
package q3
func lengthOfLongestSubstring(s string) int {
seen := make([]bool, 256)
maxLen := 0
l := 0
for r := range len(s) {
c := s[r]
for seen[c] {
seen[s[l]] = false
l++
}
seen[c] = true
maxLen = max(maxLen, r-l+1)
}
return maxLen
}
var _ = lengthOfLongestSubstring

View file

@ -0,0 +1,46 @@
package q33
func findK(nums []int) int {
if len(nums) < 2 || nums[0] < nums[len(nums)-1] {
return 0
}
l, r := 0, len(nums)
for l < r && nums[l] > nums[r-1] {
m := (l + r) / 2
if nums[m] > nums[r-1] {
l = m + 1
} else {
r = m + 1
l++
}
}
return len(nums) - l
}
func translate(n, k, i int) int {
if i < k {
return n + i - k
}
return i - k
}
func search(nums []int, target int) int {
k := findK(nums)
l, r := 0, len(nums)
for l < r {
m := (l + r) / 2
mt := translate(len(nums), k, m)
if nums[mt] == target {
return mt
} else if nums[mt] > target {
r = m
} else {
l = m + 1
}
}
return -1
}
var _ = search

View file

@ -0,0 +1,26 @@
package q34
func find(nums []int, target int) int {
l, r := 0, len(nums)
for l < r {
m := (l + r) / 2
switch {
case nums[m] < target:
l = m + 1
default:
r = m
}
}
return l
}
func searchRange(nums []int, target int) []int {
pos := find(nums, target)
if pos < 0 || pos >= len(nums) || nums[pos] != target {
return []int{-1, -1}
}
pos2 := find(nums[pos:], target+1)
return []int{pos, pos + pos2 - 1}
}
var _ = searchRange

View file

@ -0,0 +1,30 @@
package q39
import "slices"
func mkCombs(candidates []int, target int, buf []int, ret [][]int) [][]int {
if target == 0 {
cp := make([]int, len(buf))
copy(cp, buf)
return append(ret, buf)
}
if len(candidates) == 0 || candidates[0] > target {
return ret
}
for i := 0; candidates[0]*i <= target; i++ {
ret = mkCombs(candidates[1:], target-i*candidates[0], buf, ret)
buf = append(buf, candidates[0])
}
return ret
}
func combinationSum(candidates []int, target int) [][]int {
slices.Sort(candidates)
ret := make([][]int, 0, 150)
buf := make([]int, target/candidates[0]+1)
return mkCombs(candidates, target, buf[:0], ret)
}
var _ = combinationSum

View file

@ -0,0 +1,34 @@
package q46
func recurse(nums []int, offset int, buf []int, seen []bool, ret [][]int) [][]int {
if offset == len(nums) {
a := make([]int, len(buf))
copy(a, buf)
return append(ret, a)
}
for i := range nums {
if seen[i] {
continue
}
seen[i] = true
buf[offset] = nums[i]
ret = recurse(nums, offset+1, buf, seen, ret)
seen[i] = false
}
return ret
}
func permute(nums []int) [][]int {
totalLen := 1
for i := range len(nums) {
totalLen *= i + 1
}
ret := make([][]int, 0, totalLen)
buf := make([]int, len(nums))
seen := make([]bool, len(nums))
return recurse(nums, 0, buf, seen, ret)
}
var _ = permute

View file

@ -0,0 +1,21 @@
package q48
func rotateCell(matrix [][]int, x, y int) {
t := matrix[y][x]
for range 4 {
nextX, nextY := len(matrix)-1-y, x
matrix[nextY][nextX], t = t, matrix[nextY][nextX]
x, y = nextX, nextY
}
}
func rotate(matrix [][]int) {
w := len(matrix)
for y := range w / 2 {
for x := y; x < w-y-1; x++ {
rotateCell(matrix, x, y)
}
}
}
var _ = rotate

View file

@ -0,0 +1,22 @@
package q49
import "slices"
func groupAnagrams(strs []string) [][]string {
groups := map[string][]string{}
for i := range strs {
byt := []byte(strs[i])
slices.Sort(byt)
sorted := string(byt)
groups[sorted] = append(groups[sorted], strs[i])
}
ret := make([][]string, 0, len(groups))
for _, g := range groups {
ret = append(ret, g)
}
return ret
}
var _ = groupAnagrams

View file

@ -0,0 +1,40 @@
package q54
import "math"
var dirs = [4][2]int{
{1, 0}, // right
{0, 1}, // down
{-1, 0}, // left
{0, -1}, // up
}
const VISITED = math.MinInt
func spiralOrder(matrix [][]int) []int {
w, h := len(matrix[0]), len(matrix)
cnt := w * h
ret := make([]int, cnt)
x, y := 0, 0
dir := 0
vect := dirs[dir]
for i := range cnt {
ret[i] = matrix[y][x]
matrix[y][x] = VISITED
// Can move?
nextX, nextY := x+vect[0], y+vect[1]
if nextX < 0 || nextY < 0 || nextX == w || nextY == h || matrix[nextY][nextX] == VISITED {
dir = (dir + 1) % 4
vect = dirs[dir]
nextX, nextY = x+vect[0], y+vect[1]
}
x, y = nextX, nextY
}
return ret
}
var _ = spiralOrder

View file

@ -0,0 +1,30 @@
package q57
func insert(intervals [][]int, newInterval []int) [][]int {
ret := make([][]int, 0, len(intervals)+1)
i := 0
for ; i < len(intervals) && intervals[i][0] <= newInterval[0]; i++ {
ret = append(ret, intervals[i])
}
if len(ret) > 0 && ret[len(ret)-1][1] >= newInterval[0] {
ret[len(ret)-1][1] = max(ret[len(ret)-1][1], newInterval[1])
} else {
ret = append(ret, newInterval)
}
for ; i < len(intervals); i++ {
last := ret[len(ret)-1]
next := intervals[i]
if last[1] >= next[0] {
last[1] = max(last[1], next[1])
} else {
ret = append(ret, next)
}
}
return ret
}
var _ = insert

View file

@ -0,0 +1,27 @@
package q6
import "strings"
func convert(s string, numRows int) string {
loopLen := numRows + max(0, numRows-2)
rows := make([][]byte, numRows)
for i := range numRows {
rows[i] = make([]byte, 0, (len(s)/loopLen+1)*2)
}
for i := range len(s) {
row := i % loopLen
if row >= numRows {
row = numRows - row%numRows - 2
}
rows[row] = append(rows[row], s[i])
}
b := strings.Builder{}
for i := range rows {
_, _ = b.Write(rows[i])
}
return b.String()
}
var _ = convert

View file

@ -0,0 +1,35 @@
package q61
type ListNode struct {
Val int
Next *ListNode
}
func rotateRight(head *ListNode, k int) *ListNode {
if head == nil {
return nil
}
n := 1
p := head
for p.Next != nil {
p = p.Next
n++
}
tail := p
k %= n
if k == 0 {
return head
}
tail.Next = head
p = head
for range n - k - 1 {
p = p.Next
}
newHead := p.Next
p.Next = nil
return newHead
}
var _ = rotateRight

View file

@ -0,0 +1,21 @@
package q64
func minPathSum(grid [][]int) int {
w, h := len(grid[0]), len(grid)
for y := 1; y < h; y++ {
grid[y][0] += grid[y-1][0]
}
for x := 1; x < w; x++ {
grid[0][x] += grid[0][x-1]
}
for y := 1; y < h; y++ {
for x := 1; x < w; x++ {
grid[y][x] += min(grid[y-1][x], grid[y][x-1])
}
}
return grid[h-1][w-1]
}
var _ = minPathSum

View file

@ -0,0 +1,32 @@
package q71
import "strings"
func simplifyPath(path string) string {
b := strings.Builder{}
fields := strings.FieldsFunc(path, func(r rune) bool { return r == '/' })
p := 0
for i := range fields {
switch fields[i] {
case ".":
continue
case "..":
p = max(p-1, 0)
default:
fields[p] = fields[i]
p++
}
}
for i := range p {
b.WriteByte('/')
b.WriteString(fields[i])
}
if p == 0 {
return "/"
}
return b.String()
}
var _ = simplifyPath

View file

@ -0,0 +1,24 @@
package q73
func setZeroes(matrix [][]int) {
zRows := make([]bool, len(matrix))
zCols := make([]bool, len(matrix[0]))
for r := range matrix {
for c := range matrix[0] {
if matrix[r][c] == 0 {
zRows[r] = true
zCols[c] = true
}
}
}
for r := range matrix {
for c := range matrix[0] {
if zRows[r] || zCols[c] {
matrix[r][c] = 0
}
}
}
}
var _ = setZeroes

View file

@ -0,0 +1,51 @@
package q77
var (
allocBuf []int
allocP int
)
func alloc(sz int) []int {
if allocBuf == nil || allocP+sz > 8192 {
allocP = 0
allocBuf = make([]int, 8192)
}
ret := allocBuf[allocP : allocP+sz]
allocP += sz
return ret
}
func combine(n int, k int) [][]int {
buf := alloc(k)
for i := range buf {
buf[i] = i + 1
}
sz := 1
for i := 1; i <= k; i++ {
sz = sz * (n - i + 1) / i
}
ret := make([][]int, 0, sz)
for {
t := alloc(k)
copy(t, buf)
ret = append(ret, t)
if buf[0] == n-k+1 {
break
}
buf[k-1]++
i := k - 1
for ; i > 0 && buf[i] > n-(k-1-i); i-- {
buf[i-1]++
}
for i++; i < k; i++ {
buf[i] = buf[i-1] + 1
}
}
return ret
}
var _ = combine

View file

@ -0,0 +1,61 @@
package q79
func search(board [][]byte, word string, prefixLen, row, col int) bool {
if row < 0 || col < 0 || row >= len(board) || col >= len(board[0]) {
return false
}
if word[prefixLen] != board[row][col] {
return false
}
if prefixLen+1 == len(word) {
return true
}
c := board[row][col]
board[row][col] = '#'
yes := false ||
search(board, word, prefixLen+1, row, col+1) ||
search(board, word, prefixLen+1, row, col-1) ||
search(board, word, prefixLen+1, row+1, col) ||
search(board, word, prefixLen+1, row-1, col)
board[row][col] = c
return yes
}
func exist(board [][]byte, word string) bool {
w, h := len(board[0]), len(board)
if len(word) > w*h {
return false
}
charFreq := make([]int, 26*2)
idx := func(b byte) byte {
if b >= 'a' {
return b - 'a' + 26
}
return b - 'A'
}
for row := range board {
for col := range board[0] {
charFreq[idx(board[row][col])]++
}
}
for i := range len(word) {
ii := idx(word[i])
charFreq[ii]--
if charFreq[ii] < 0 {
return false
}
}
for row := range board {
for col := range board[0] {
if search(board, word, 0, row, col) {
return true
}
}
}
return false
}
var _ = exist

View file

@ -0,0 +1,30 @@
package q86
type ListNode struct {
Val int
Next *ListNode
}
func partition(head *ListNode, x int) *ListNode {
stub := &ListNode{Next: head}
before := stub
for before.Next != nil && before.Next.Val < x {
before = before.Next
}
for p := before.Next; p != nil && p.Next != nil; {
if p.Next.Val < x {
move := p.Next
p.Next = move.Next
move.Next = before.Next
before.Next = move
before = move
} else {
p = p.Next
}
}
return stub.Next
}
var _ = partition

View file

@ -0,0 +1,25 @@
package q92
type ListNode struct {
Val int
Next *ListNode
}
func reverseBetween(head *ListNode, left int, right int) *ListNode {
stub := &ListNode{Next: head}
before := stub
for range left - 1 {
before = before.Next
}
curr := before.Next
for range right - left {
move := curr.Next
curr.Next = move.Next
move.Next = before.Next
before.Next = move
}
return stub.Next
}
var _ = reverseBetween

View file

@ -0,0 +1,39 @@
package q98
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func isValid(node *TreeNode) (bool, int, int) {
if node.Left == nil && node.Right == nil {
return true, node.Val, node.Val
}
minv, maxv := node.Val, node.Val
if node.Left != nil {
valid, lmin, lmax := isValid(node.Left)
if !valid || lmax >= node.Val {
return false, 0, 0
}
minv = lmin
}
if node.Right != nil {
valid, rmin, rmax := isValid(node.Right)
if !valid || rmin <= node.Val {
return false, 0, 0
}
maxv = rmax
}
return true, minv, maxv
}
func isValidBST(root *TreeNode) bool {
valid, _, _ := isValid(root)
return valid
}
var _ = isValidBST

View file

@ -0,0 +1,27 @@
package q128
func longestConsecutive(nums []int) int {
set := make(map[int]struct{}, len(nums))
for _, n := range nums {
set[n] = struct{}{}
}
longest := 0
for n := range set {
if _, ok := set[n-1]; ok {
continue
}
r := n
for {
if _, ok := set[r+1]; ok {
r++
} else {
break
}
}
longest = max(longest, r-n+1)
}
return longest
}
var _ = longestConsecutive

View file

@ -0,0 +1,37 @@
package q130
func markI(board [][]byte, x, y int) {
w, h := len(board[0]), len(board)
if x < 0 || y < 0 || x >= w || y >= h || board[y][x] != 'O' {
return
}
board[y][x] = 'I'
markI(board, x, y+1)
markI(board, x, y-1)
markI(board, x+1, y)
markI(board, x-1, y)
}
func solve(board [][]byte) {
for i := range len(board) {
markI(board, 0, i)
markI(board, len(board[0])-1, i)
}
for i := range len(board[0]) {
markI(board, i, 0)
markI(board, i, len(board)-1)
}
for y := range board {
for x := range board[0] {
switch board[y][x] {
case 'O':
board[y][x] = 'X'
case 'I':
board[y][x] = 'O'
}
}
}
}
var _ = solve

View file

@ -0,0 +1,34 @@
package q138
type Node struct {
Val int
Next *Node
Random *Node
}
func copyRandomList(head *Node) *Node {
idx := make(map[*Node]*Node, 256)
p := head
for p != nil {
newNode := *p // copy
idx[p] = &newNode
p = p.Next
}
p = head
for p != nil {
newNode := idx[p]
if newNode.Next != nil {
newNode.Next = idx[newNode.Next]
}
if newNode.Random != nil {
newNode.Random = idx[newNode.Random]
}
p = p.Next
}
return idx[head]
}
var _ = copyRandomList

View file

@ -0,0 +1,28 @@
package q139
func wordBreak(s string, wordDict []string) bool {
possible := make([]bool, len(s)+1)
possible[0] = true
for l := range possible {
if !possible[l] {
continue
}
for i := range wordDict {
newLen := len(wordDict[i]) + l
if newLen > len(s) {
continue
}
if possible[newLen] {
continue
}
if s[l:newLen] == wordDict[i] {
possible[newLen] = true
}
}
}
return possible[len(s)]
}
var _ = wordBreak

View file

@ -0,0 +1,18 @@
package q153
func findMin(nums []int) int {
l, r := 0, len(nums)
for l < r && nums[l] > nums[r-1] {
m := (l + r) / 2
if nums[m] > nums[r-1] {
l = m + 1
} else {
r = m + 1
l++
}
}
return nums[l]
}
var _ = findMin

View file

@ -0,0 +1,24 @@
package q162
// Important constraint: nums[i] != nums[i + 1]
func findPeakElement(nums []int) int {
l, r := 0, len(nums)
for l < r {
m := (l + r) / 2
lLower := m == 0 || nums[m-1] < nums[m]
rLower := m == len(nums)-1 || nums[m+1] < nums[m]
if lLower && rLower {
return m
}
if !lLower { // left side is higher
r = m
} else {
l = m + 1
}
}
return -1
}
var _ = findPeakElement

View file

@ -0,0 +1,63 @@
package q211
type TrieNode struct {
word bool
next [26]*TrieNode
}
func (n *TrieNode) hasMatch(pattern string, offset int) bool {
if n == nil {
return false
}
if offset == len(pattern) {
return n.word
}
c := pattern[offset]
if c != '.' {
return n.next[toIdx(c)].hasMatch(pattern, offset+1)
}
// Wildcard character
for _, t := range n.next {
if t != nil && t.hasMatch(pattern, offset+1) {
return true
}
}
return false
}
func toIdx(b byte) int8 { return int8(b - 'a') }
type WordDictionary struct{ root *TrieNode }
func Constructor() WordDictionary {
return WordDictionary{
root: &TrieNode{},
}
}
func (d *WordDictionary) AddWord(word string) {
curr := d.root
for i := range len(word) {
c := word[i]
idx := toIdx(c)
if curr.next[idx] == nil {
curr.next[idx] = &TrieNode{}
}
curr = curr.next[idx]
}
curr.word = true
}
func (d *WordDictionary) Search(word string) bool {
return d.root.hasMatch(word, 0)
}
/**
* Your WordDictionary object will be instantiated and called as such:
* obj := Constructor();
* obj.AddWord(word);
* param_2 := obj.Search(word);
*/

View file

@ -0,0 +1,31 @@
package q236
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
if root == nil {
return nil
}
if root == p || root == q {
return root
}
l := lowestCommonAncestor(root.Left, p, q)
r := lowestCommonAncestor(root.Right, p, q)
switch {
case l == nil && r == nil:
return nil
case l != nil && r != nil:
return root
case l != nil:
return l
}
return r
}
var _ = lowestCommonAncestor

View file

@ -0,0 +1,50 @@
package q2975
import "slices"
func maximizeSquareArea(m int, n int, hFences []int, vFences []int) int {
slices.Sort(hFences)
slices.Sort(vFences)
nHFences := len(hFences) + 2
lengths := make(map[int]struct{}, nHFences*(nHFences-1)/2)
for i := -1; i < len(hFences); i++ {
a := 1
if i >= 0 {
a = hFences[i]
}
for j := i + 1; j <= len(hFences); j++ {
b := m
if j < len(hFences) {
b = hFences[j]
}
lengths[b-a] = struct{}{}
}
}
maxEdge := -1
for i := -1; i < len(vFences); i++ {
a := 1
if i >= 0 {
a = vFences[i]
}
for j := i + 1; j <= len(vFences); j++ {
b := n
if j < len(vFences) {
b = vFences[j]
}
if _, ok := lengths[b-a]; ok {
maxEdge = max(maxEdge, b-a)
}
}
}
if maxEdge == -1 {
return -1
}
maxEdge %= 1e9 + 7
return (maxEdge * maxEdge) % (1e9 + 7)
}
var _ = maximizeSquareArea

View file

@ -0,0 +1,21 @@
package q300
func lengthOfLIS(nums []int) int {
maxSeqLen := make([]int, len(nums))
maxSeqLen[0] = 1
globalMax := 1
for i := 1; i < len(nums); i++ {
locMax := 0
for j := 0; j < i; j++ {
if nums[j] < nums[i] {
locMax = max(locMax, maxSeqLen[j])
}
}
maxSeqLen[i] = locMax + 1
globalMax = max(globalMax, maxSeqLen[i])
}
return globalMax
}
var _ = lengthOfLIS

View file

@ -0,0 +1,42 @@
package q3047
import "slices"
func intersectingSquareArea(bl1, tr1, bl2, tr2 []int) int64 {
l1, r1, l2, r2 := bl1[0], tr1[0], bl2[0], tr2[0]
iW := max(0, min(r1, r2)-max(l1, l2))
l1, r1, l2, r2 = bl1[1], tr1[1], bl2[1], tr2[1]
iH := max(0, min(r1, r2)-max(l1, l2))
edge := min(iW, iH)
return int64(edge * edge)
}
func largestSquareArea(bottomLeft [][]int, topRight [][]int) int64 {
squares := make([]int, len(bottomLeft))
for i := range squares {
squares[i] = i
}
slices.SortFunc(squares, // bottom-up order
func(a, b int) int { return bottomLeft[a][1] - bottomLeft[b][1] })
var largest int64
for i := range squares {
for j := i + 1; j < len(squares); j++ {
yI, yJ := topRight[squares[i]][1], bottomLeft[squares[j]][1]
if yJ >= yI {
break
}
largest = max(largest, intersectingSquareArea(
bottomLeft[squares[i]], topRight[squares[i]],
bottomLeft[squares[j]], topRight[squares[j]],
))
}
}
return largest
}
var _ = largestSquareArea

View file

@ -0,0 +1,44 @@
package q427
type Node struct {
Val bool
IsLeaf bool
TopLeft *Node
TopRight *Node
BottomLeft *Node
BottomRight *Node
}
func mkTree(grid [][]int, x, y, w int) *Node {
if w == 1 {
return &Node{
Val: grid[y][x] == 1,
IsLeaf: true,
}
}
subtreeW := w / 2
node := &Node{
TopLeft: mkTree(grid, x, y, subtreeW),
TopRight: mkTree(grid, x+subtreeW, y, subtreeW),
BottomLeft: mkTree(grid, x, y+subtreeW, subtreeW),
BottomRight: mkTree(grid, x+subtreeW, y+subtreeW, subtreeW),
}
if !node.TopLeft.IsLeaf || !node.TopRight.IsLeaf || !node.BottomLeft.IsLeaf || !node.BottomRight.IsLeaf {
return node
}
if node.TopLeft.Val && node.TopRight.Val && node.BottomLeft.Val && node.BottomRight.Val ||
!node.TopLeft.Val && !node.TopRight.Val && !node.BottomLeft.Val && !node.BottomRight.Val {
return &Node{
Val: node.TopLeft.Val,
IsLeaf: true,
}
}
return node
}
func construct(grid [][]int) *Node {
return mkTree(grid, 0, 0, len(grid))
}
var _ = construct

View file

@ -0,0 +1,66 @@
package q986
import "slices"
type listElem struct {
x int
listId int8 // 0, 1
isStart bool
}
func intervalIntersection(firstList [][]int, secondList [][]int) [][]int {
locations := make([]listElem, 0, len(firstList)*2+len(secondList)*2)
for i := range firstList {
locations = append(
locations,
listElem{x: firstList[i][0], listId: 0, isStart: true},
listElem{x: firstList[i][1], listId: 0, isStart: false},
)
}
for i := range secondList {
locations = append(
locations,
listElem{x: secondList[i][0], listId: 1, isStart: true},
listElem{x: secondList[i][1], listId: 1, isStart: false},
)
}
slices.SortFunc(locations, func(a, b listElem) int {
if a.x != b.x {
return a.x - b.x
}
if a.isStart {
return -1
}
return 1
})
ret := [][]int{}
start := 0
isA, isB := false, false
for _, loc := range locations {
if loc.isStart {
start = loc.x
switch loc.listId {
case 0:
isA = true
default:
isB = true
}
} else {
if isA && isB {
ret = append(ret, []int{start, loc.x})
}
switch loc.listId {
case 0:
isA = false
default:
isB = false
}
}
}
return ret
}
var _ = intervalIntersection