diff --git a/solutions/0/q23/solution.go b/solutions/0/q23/solution.go new file mode 100644 index 0000000..168d7e0 --- /dev/null +++ b/solutions/0/q23/solution.go @@ -0,0 +1,52 @@ +package q23 + +import "container/heap" + +type ListNode struct { + Val int + Next *ListNode +} + +type MinNodeHp []*ListNode + +func (m *MinNodeHp) Len() int { return len(*m) } +func (m *MinNodeHp) Less(i int, j int) bool { return (*m)[i].Val < (*m)[j].Val } +func (m *MinNodeHp) Push(x any) { *m = append(*m, x.(*ListNode)) } +func (m *MinNodeHp) Swap(i int, j int) { (*m)[i], (*m)[j] = (*m)[j], (*m)[i] } + +func (m *MinNodeHp) Pop() any { + *m = (*m)[:len(*m)-1] + return nil +} + +var _ heap.Interface = &MinNodeHp{} + +func mergeKLists(lists []*ListNode) *ListNode { + hp := make(MinNodeHp, 0, len(lists)) + for i := range lists { + if lists[i] != nil { + hp = append(hp, lists[i]) + } + } + heap.Init(&hp) + + head := &ListNode{} + tail := head + + for len(hp) > 0 { + tail.Next = hp[0] + tail = tail.Next + + hp[0] = hp[0].Next + if hp[0] == nil { + heap.Remove(&hp, 0) + } else { + heap.Fix(&hp, 0) + } + } + + tail.Next = nil + return head.Next +} + +var _ = mergeKLists diff --git a/solutions/0/q62/solution.go b/solutions/0/q62/solution.go new file mode 100644 index 0000000..7d08c03 --- /dev/null +++ b/solutions/0/q62/solution.go @@ -0,0 +1,15 @@ +package q62 + +func uniquePaths(m int, n int) int { + buf := make([]int, n) + buf[0] = 1 + + for range m { + for c := 1; c < n; c++ { + buf[c] += buf[c-1] + } + } + return buf[n-1] +} + +var _ = uniquePaths diff --git a/solutions/0/q94/solution.go b/solutions/0/q94/solution.go new file mode 100644 index 0000000..f86701c --- /dev/null +++ b/solutions/0/q94/solution.go @@ -0,0 +1,25 @@ +package q94 + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func traversal(node *TreeNode, ret *[]int) { + if node == nil { + return + } + traversal(node.Left, ret) + *ret = append(*ret, node.Val) + traversal(node.Right, ret) +} + +func inorderTraversal(root *TreeNode) []int { + // left, center, right + ret := []int{} + traversal(root, &ret) + return ret +} + +var _ = inorderTraversal diff --git a/solutions/1/q142/solution.go b/solutions/1/q142/solution.go new file mode 100644 index 0000000..fb53a3e --- /dev/null +++ b/solutions/1/q142/solution.go @@ -0,0 +1,32 @@ +package q142 + +type ListNode struct { + Val int + Next *ListNode +} + +func detectCycle(head *ListNode) *ListNode { + p1, p2 := head, head + for p1 != nil && p2 != nil { + p1 = p1.Next + p2 = p2.Next + if p2 != nil { + p2 = p2.Next + } + if p1 == p2 { + break + } + } + if p2 == nil { + return nil + } + + p1 = head + for p1 != p2 { + p1 = p1.Next + p2 = p2.Next.Next + } + return p1 +} + +var _ = detectCycle diff --git a/solutions/10/q1004/solution.go b/solutions/10/q1004/solution.go new file mode 100644 index 0000000..3d07b36 --- /dev/null +++ b/solutions/10/q1004/solution.go @@ -0,0 +1,26 @@ +package q1004 + +func longestOnes(nums []int, k int) int { + flipped := 0 + curLen, maxLen := 0, 0 + tail := 0 + + for i := range nums { + curLen++ + if nums[i] == 0 { + flipped++ + + for flipped > k { + if nums[tail] == 0 { + flipped-- + } + tail++ + curLen-- + } + } + maxLen = max(maxLen, curLen) + } + return maxLen +} + +var _ = longestOnes diff --git a/solutions/11/q1143/solution.go b/solutions/11/q1143/solution.go new file mode 100644 index 0000000..231fa6e --- /dev/null +++ b/solutions/11/q1143/solution.go @@ -0,0 +1,24 @@ +package q1143 + +// Note: Can be compressed to only len(text1) extra space. + +func longestCommonSubsequence(text1 string, text2 string) int { + commonSeqLen := make([][]int, len(text1)+1) + for i := range commonSeqLen { + commonSeqLen[i] = make([]int, len(text2)+1) + } + + for i1 := 1; i1 <= len(text1); i1++ { + for i2 := 1; i2 <= len(text2); i2++ { + if text1[i1-1] == text2[i2-1] { + commonSeqLen[i1][i2] = commonSeqLen[i1-1][i2-1] + 1 + } else { + commonSeqLen[i1][i2] = max(commonSeqLen[i1-1][i2], commonSeqLen[i1][i2-1]) + } + } + } + + return commonSeqLen[len(text1)][len(text2)] +} + +var _ = longestCommonSubsequence diff --git a/solutions/12/q1268/solution.go b/solutions/12/q1268/solution.go new file mode 100644 index 0000000..5216606 --- /dev/null +++ b/solutions/12/q1268/solution.go @@ -0,0 +1,38 @@ +package q1268 + +import "slices" + +func prefixSearch(products []string, prefix string) []string { + ret := make([]string, 0, 3) + pfLen := len(prefix) + + l, r := 0, len(products) + for l < r { + m := (l + r) / 2 + if products[m][:min(len(products[m]), pfLen)] >= prefix { + r = m + } else { + l = m + 1 + } + } + for ; l < len(products) && len(products[l]) >= pfLen && products[l][:pfLen] == prefix; l++ { + ret = append(ret, products[l]) + if len(ret) == 3 { + break + } + } + + return ret +} + +func suggestedProducts(products []string, searchWord string) [][]string { + slices.Sort(products) + ret := make([][]string, 0, len(searchWord)) + + for i := range len(searchWord) { + ret = append(ret, prefixSearch(products, searchWord[:i+1])) + } + return ret +} + +var _ = suggestedProducts diff --git a/solutions/12/q1292/solution.go b/solutions/12/q1292/solution.go new file mode 100644 index 0000000..98f94b0 --- /dev/null +++ b/solutions/12/q1292/solution.go @@ -0,0 +1,51 @@ +package q1292 + +func pfSum(mat [][]int) [][]int { + w, h := len(mat[0])+1, len(mat)+1 + pfs := make([][]int, h) + for i := range pfs { + pfs[i] = make([]int, w) + } + + for y := 1; y < h; y++ { + for x := 1; x < w; x++ { + pfs[y][x] = mat[y-1][x-1] + pfs[y][x-1] + pfs[y-1][x] - pfs[y-1][x-1] + } + } + return pfs +} + +func sumOfSquare(pfs [][]int, x, y, w int) int { + return pfs[y+w][x+w] - pfs[y][x+w] - pfs[y+w][x] + pfs[y][x] +} + +func hasSquare(pfs [][]int, edgeLen, threshold int) bool { + w, h := len(pfs[0])-1, len(pfs)-1 + for y := range h - edgeLen + 1 { + for x := range w - edgeLen + 1 { + if sumOfSquare(pfs, x, y, edgeLen) <= threshold { + return true + } + } + } + return false +} + +func maxSideLength(mat [][]int, threshold int) int { + pfs := pfSum(mat) + w, h := len(pfs[0]), len(pfs) + maxAllowed := min(w, h) + + l, r := 0, maxAllowed+1 + for l+1 < r { + m := (l + r) / 2 + if hasSquare(pfs, m, threshold) { + l = m + } else { + r = m + } + } + return l +} + +var _ = maxSideLength diff --git a/solutions/13/q1318/solution.go b/solutions/13/q1318/solution.go new file mode 100644 index 0000000..34e30f8 --- /dev/null +++ b/solutions/13/q1318/solution.go @@ -0,0 +1,28 @@ +package q1318 + +func minFlips(a int, b int, c int) int { + aorb := a | b + flips := 0 + + p := 1 + for p <= aorb || p <= c { + switch { + case c|p == c && aorb|p != aorb: + flips++ // c has the bit + + case c|p != c && aorb|p == aorb: + if a|p == a { + flips++ // a has the bit + } + if b|p == b { + flips++ // b has the bit + } + } + + p <<= 1 + } + + return flips +} + +var _ = minFlips diff --git a/solutions/13/q1372/solution.go b/solutions/13/q1372/solution.go new file mode 100644 index 0000000..d2297e2 --- /dev/null +++ b/solutions/13/q1372/solution.go @@ -0,0 +1,34 @@ +package q1372 + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func zigZagLen(node *TreeNode, isLeft bool, curLen int) int { + if node == nil { + return 0 + } + var l, r int + if isLeft { + l = zigZagLen(node.Left, true, 1) + r = zigZagLen(node.Right, false, curLen+1) + } else { + l = zigZagLen(node.Left, true, curLen+1) + r = zigZagLen(node.Right, false, 1) + } + return max(curLen, l, r) +} + +func longestZigZag(root *TreeNode) int { + if root == nil { + return 0 + } + return max( + zigZagLen(root.Left, true, 1), + zigZagLen(root.Right, false, 1), + ) +} + +var _ = longestZigZag diff --git a/solutions/14/q1448/solution.go b/solutions/14/q1448/solution.go new file mode 100644 index 0000000..1ae93a8 --- /dev/null +++ b/solutions/14/q1448/solution.go @@ -0,0 +1,28 @@ +package q1448 + +import "math" + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func gn(node *TreeNode, curMax int) int { + if node == nil { + return 0 + } + self := 0 + if node.Val >= curMax { + self = 1 + } + + curMax = max(curMax, node.Val) + return self + gn(node.Left, curMax) + gn(node.Right, curMax) +} + +func goodNodes(root *TreeNode) int { + return gn(root, math.MinInt) +} + +var _ = goodNodes diff --git a/solutions/14/q1456/solution.go b/solutions/14/q1456/solution.go new file mode 100644 index 0000000..dfa5d6f --- /dev/null +++ b/solutions/14/q1456/solution.go @@ -0,0 +1,27 @@ +package q1456 + +func isVowel(b byte) bool { + switch b { + case 'a', 'e', 'i', 'o', 'u': + return true + } + return false +} + +func maxVowels(s string, k int) int { + maxV := 0 + curr := 0 + for i := range len(s) { + if isVowel(s[i]) { + curr++ + } + if i >= k && isVowel(s[i-k]) { + curr-- + } + + maxV = max(curr, maxV) + } + return maxV +} + +var _ = maxVowels diff --git a/solutions/14/q1466/solution.go b/solutions/14/q1466/solution.go new file mode 100644 index 0000000..c7968cf --- /dev/null +++ b/solutions/14/q1466/solution.go @@ -0,0 +1,67 @@ +package q1466 + +import "math" + +func walk(connections [][2][]int, minFlips []int32, node int) { + mf := minFlips[node] + + // Walk no-flip-needed + for _, n := range connections[node][1] { + if mf < minFlips[n] { + minFlips[n] = mf + walk(connections, minFlips, n) + } + } + + // Walk flip-needed + for _, n := range connections[node][0] { + if mf+1 < minFlips[n] { + minFlips[n] = mf + 1 + walk(connections, minFlips, n) + } + } +} + +func collect(connections [][2][]int, minFlips []int32, node int, visited []bool) int32 { + mf := minFlips[node] + var sum int32 + + for _, n := range connections[node][1] { + if !visited[n] && mf == minFlips[n] { + visited[n] = true + sum += collect(connections, minFlips, n, visited) - mf + } + } + + for _, n := range connections[node][0] { + if !visited[n] && mf+1 == minFlips[n] { + visited[n] = true + sum += collect(connections, minFlips, n, visited) - mf + } + } + + return sum + mf +} + +func minReorder(n int, connections [][]int) int { + conns := make([][2][]int, n) + for i := range connections { + from, to := connections[i][0], connections[i][1] + conns[from][0] = append(conns[from][0], to) + conns[to][1] = append(conns[to][1], from) + } + + minFlips := make([]int32, n) // minimum flips to reach node n + minFlips[0] = math.MaxInt32 + for i := 1; i < len(minFlips); i *= 2 { + copy(minFlips[i:], minFlips[:i]) + } + minFlips[0] = 0 + + walk(conns, minFlips, 0) + + visited := make([]bool, n) + return int(collect(conns, minFlips, 0, visited)) +} + +var _ = minReorder diff --git a/solutions/14/q1493/solution.go b/solutions/14/q1493/solution.go new file mode 100644 index 0000000..72196d4 --- /dev/null +++ b/solutions/14/q1493/solution.go @@ -0,0 +1,24 @@ +package q1493 + +func longestSubarray(nums []int) int { + prev, cur := 0, 0 + longest := 0 + has0 := false + for _, a := range nums { + if a == 1 { + cur++ + } + longest = max(longest, prev+cur) + if a == 0 { + prev, cur = cur, 0 + has0 = true + } + } + + if !has0 { + longest-- + } + return longest +} + +var _ = longestSubarray diff --git a/solutions/16/q1657/solution.go b/solutions/16/q1657/solution.go new file mode 100644 index 0000000..d56a282 --- /dev/null +++ b/solutions/16/q1657/solution.go @@ -0,0 +1,30 @@ +package q1657 + +import "slices" + +func closeStrings(word1 string, word2 string) bool { + if len(word1) != len(word2) { + return false + } + + charCount1, charCount2 := make([]int, 26), make([]int, 26) + for i := range len(word1) { + charCount1[word1[i]-'a']++ + charCount2[word2[i]-'a']++ + } + + for i := range charCount1 { + if charCount1[i] == 0 && charCount2[i] != 0 { + return false + } + if charCount1[i] != 0 && charCount2[i] == 0 { + return false + } + } + + slices.Sort(charCount1) + slices.Sort(charCount2) + return slices.Equal(charCount1, charCount2) +} + +var _ = closeStrings diff --git a/solutions/16/q1679/solution.go b/solutions/16/q1679/solution.go new file mode 100644 index 0000000..a1fc1a1 --- /dev/null +++ b/solutions/16/q1679/solution.go @@ -0,0 +1,26 @@ +package q1679 + +import "slices" + +func maxOperations(nums []int, k int) int { + slices.Sort(nums) + + nOps := 0 + l, r := 0, len(nums)-1 + for l < r { + sum := nums[l] + nums[r] + switch { + case sum == k: + nOps++ + l++ + r-- + case sum > k: + r-- + default: + l++ + } + } + return nOps +} + +var _ = maxOperations diff --git a/solutions/18/q1877/solution.go b/solutions/18/q1877/solution.go new file mode 100644 index 0000000..164aafc --- /dev/null +++ b/solutions/18/q1877/solution.go @@ -0,0 +1,16 @@ +package q1877 + +import "slices" + +func minPairSum(nums []int) int { + slices.Sort(nums) + n := len(nums) + + maxSum := 0 + for i := range n / 2 { + maxSum = max(maxSum, nums[i]+nums[n-1-i]) + } + return maxSum +} + +var _ = minPairSum diff --git a/solutions/18/q1895/solution.go b/solutions/18/q1895/solution.go new file mode 100644 index 0000000..28b60a6 --- /dev/null +++ b/solutions/18/q1895/solution.go @@ -0,0 +1,59 @@ +package q1895 + +func isMagicSq(grid [][]int, x, y, w int) bool { + diag1Sum := 0 + diag2Sum := 0 + for i := range w { + ax, ay := x+i, y+i + diag1Sum += grid[ay][ax] + ax = x + w - 1 - i + diag2Sum += grid[ay][ax] + } + if diag1Sum != diag2Sum { + return false + } + + // horizontal + for dy := range w { + sum := 0 + for dx := range w { + sum += grid[y+dy][x+dx] + } + if sum != diag1Sum { + return false + } + } + // vertical + for dx := range w { + sum := 0 + for dy := range w { + sum += grid[y+dy][x+dx] + } + if sum != diag1Sum { + return false + } + } + + return true +} + +func largestMagicSquare(grid [][]int) int { + k := 1 + gW, gH := len(grid[0]), len(grid) + +Outer: + for w := 2; w <= min(gW, gH); w++ { + for y := range gH - w + 1 { + for x := range gW - w + 1 { + if isMagicSq(grid, x, y, w) { + k = w + continue Outer + } + + } + } + } + return k +} + +var _ = largestMagicSquare diff --git a/solutions/19/q1926/solution.go b/solutions/19/q1926/solution.go new file mode 100644 index 0000000..84a4883 --- /dev/null +++ b/solutions/19/q1926/solution.go @@ -0,0 +1,40 @@ +package q1926 + +const ( + EMPTY byte = '.' + WALL byte = '+' +) + +func nearestExit(maze [][]byte, entrance []int) int { + queue := make([][3]int, 0, len(maze)) // row, col, step + queue = append(queue, [3]int{entrance[0], entrance[1], 0}) + maze[entrance[0]][entrance[1]] = WALL // mark as visited + + var add = func(r, c, s int) bool { + if r < 0 || c < 0 || r >= len(maze) || c >= len(maze[0]) || maze[r][c] != EMPTY { + return false + } + + if r == 0 || c == 0 || r == len(maze)-1 || c == len(maze[0])-1 { + return true // found + } + + maze[r][c] = WALL + queue = append(queue, [3]int{r, c, s}) + return false + } + + for ; len(queue) > 0; queue = queue[1:] { + cur := queue[0] + r, c, s := cur[0], cur[1], cur[2] + if add(r, c+1, s+1) || + add(r, c-1, s+1) || + add(r+1, c, s+1) || + add(r-1, c, s+1) { + return s + 1 + } + } + return -1 +} + +var _ = nearestExit diff --git a/solutions/19/q1984/solution.go b/solutions/19/q1984/solution.go new file mode 100644 index 0000000..e13814e --- /dev/null +++ b/solutions/19/q1984/solution.go @@ -0,0 +1,17 @@ +package q1984 + +import ( + "math" + "slices" +) + +func minimumDifference(nums []int, k int) int { + slices.Sort(nums) + minDiff := math.MaxInt + for i := 0; i < len(nums)-k+1; i++ { + minDiff = min(nums[i+k-1]-nums[i], minDiff) + } + return minDiff +} + +var _ = minimumDifference diff --git a/solutions/2/q216/solution.go b/solutions/2/q216/solution.go new file mode 100644 index 0000000..bab5103 --- /dev/null +++ b/solutions/2/q216/solution.go @@ -0,0 +1,37 @@ +package q216 + +// k numbers sum up to n + +func calc(k int, buf []int, offset int, remSum int, ret [][]int) [][]int { + if offset == k-1 && remSum > 0 && remSum < 10 { + buf[offset] = remSum + cp := make([]int, len(buf)) + copy(cp, buf) + return append(ret, cp) + } + + remK := k - offset + minI := 1 + if offset > 0 { + minI = buf[offset-1] + 1 + } + maxI := 9 - remK + 1 + + for i := minI; i <= maxI; i++ { + minSum := (i + i + remK - 1) * remK / 2 + maxSum := (19 - remK) * remK / 2 + if remSum < minSum || remSum > maxSum { + continue + } + + buf[offset] = i + ret = calc(k, buf, offset+1, remSum-i, ret) + } + return ret +} + +func combinationSum3(k int, n int) [][]int { + return calc(k, make([]int, k), 0, n, [][]int{}) +} + +var _ = combinationSum3 diff --git a/solutions/20/q2095/solution.go b/solutions/20/q2095/solution.go new file mode 100644 index 0000000..a425c6d --- /dev/null +++ b/solutions/20/q2095/solution.go @@ -0,0 +1,22 @@ +package q2095 + +type ListNode struct { + Val int + Next *ListNode +} + +func deleteMiddle(head *ListNode) *ListNode { + stub := &ListNode{Next: head} + + fast, slow := stub, stub + for fast.Next != nil && fast.Next.Next != nil { + fast = fast.Next.Next + slow = slow.Next + } + if slow.Next != nil { + slow.Next = slow.Next.Next + } + return stub.Next +} + +var _ = deleteMiddle diff --git a/solutions/21/q2130/solution.go b/solutions/21/q2130/solution.go new file mode 100644 index 0000000..9f9ecd2 --- /dev/null +++ b/solutions/21/q2130/solution.go @@ -0,0 +1,27 @@ +package q2130 + +import "math" + +type ListNode struct { + Val int + Next *ListNode +} + +var arr = []int{} + +func pairSum(head *ListNode) int { + arr = arr[:0] + for p := head; p != nil; p = p.Next { + arr = append(arr, p.Val) + } + maxSum := math.MinInt + l, r := 0, len(arr)-1 + for l < r { + maxSum = max(maxSum, arr[l]+arr[r]) + l++ + r-- + } + return maxSum +} + +var _ = pairSum diff --git a/solutions/23/q2300/solution.go b/solutions/23/q2300/solution.go new file mode 100644 index 0000000..c193bef --- /dev/null +++ b/solutions/23/q2300/solution.go @@ -0,0 +1,32 @@ +package q2300 + +import "slices" + +func nGte(arr []int, target int) int { + l, r := 0, len(arr) + for l < r { + m := (l + r) / 2 + if arr[m] >= target { + r = m + } else { + l = m + 1 + } + } + return len(arr) - l +} + +func successfulPairs(spells []int, potions []int, success int64) []int { + slices.Sort(potions) + + for i := range spells { + pow := spells[i] + want := int(success) / pow + if pow*want < int(success) { + want++ + } + spells[i] = nGte(potions, want) + } + return spells +} + +var _ = successfulPairs diff --git a/solutions/23/q2336/solution.go b/solutions/23/q2336/solution.go new file mode 100644 index 0000000..0420346 --- /dev/null +++ b/solutions/23/q2336/solution.go @@ -0,0 +1,55 @@ +package q2336 + +import "container/heap" + +type MinHeap []int + +func (m *MinHeap) Len() int { return len(*m) } +func (m *MinHeap) Less(i int, j int) bool { return (*m)[i] < (*m)[j] } +func (m *MinHeap) Push(x any) { *m = append(*m, x.(int)) } +func (m *MinHeap) Swap(i int, j int) { (*m)[i], (*m)[j] = (*m)[j], (*m)[i] } + +func (m *MinHeap) Pop() any { + ret := (*m)[len(*m)-1] + *m = (*m)[:len(*m)-1] + return ret +} + +type SmallestInfiniteSet struct { + head int + added MinHeap +} + +func Constructor() SmallestInfiniteSet { + return SmallestInfiniteSet{ + head: 1, + added: MinHeap{}, + } +} + +func (s *SmallestInfiniteSet) PopSmallest() int { + if s.added.Len() > 0 { + top := s.added[0] + for s.added.Len() > 0 && s.added[0] == top { + heap.Pop(&s.added) + } + return top + } else { + s.head++ + return s.head - 1 + } +} + +func (s *SmallestInfiniteSet) AddBack(num int) { + if num >= s.head { + return + } + heap.Push(&s.added, num) +} + +/** + * Your SmallestInfiniteSet object will be instantiated and called as such: + * obj := Constructor(); + * param_1 := obj.PopSmallest(); + * obj.AddBack(num); + */ diff --git a/solutions/23/q2352/solution.go b/solutions/23/q2352/solution.go new file mode 100644 index 0000000..bb02781 --- /dev/null +++ b/solutions/23/q2352/solution.go @@ -0,0 +1,39 @@ +package q2352 + +import "strings" + +func index(grid [][]int, col bool, i int) string { + b := strings.Builder{} + b.Grow(len(grid) * 3) + for j := range grid { + var num int + switch { + case col: // ith col + num = grid[j][i] + default: // ith row + num = grid[i][j] + } + + for range 3 { + b.WriteByte(byte(num % 256)) + num >>= 8 + } + } + return b.String() +} + +func equalPairs(grid [][]int) int { + idx := make(map[string]int, len(grid)) + nEq := 0 + for row := range grid { + s := index(grid, false, row) + idx[s]++ + } + for col := range grid { + s := index(grid, true, col) + nEq += idx[s] + } + return nEq +} + +var _ = equalPairs diff --git a/solutions/24/q2402/solution.go b/solutions/24/q2402/solution.go index c95acc6..526ca20 100644 --- a/solutions/24/q2402/solution.go +++ b/solutions/24/q2402/solution.go @@ -73,5 +73,4 @@ func mostBooked(n int, meetings [][]int) int { return mbIdx } -var _ heap.Interface = &Rooms{} var _ = mostBooked diff --git a/solutions/24/q2462/solution.go b/solutions/24/q2462/solution.go new file mode 100644 index 0000000..2c86c50 --- /dev/null +++ b/solutions/24/q2462/solution.go @@ -0,0 +1,62 @@ +package q2462 + +import "container/heap" + +type CustomMinHeap struct { + data []int + less func(a, b int) bool +} + +func (c *CustomMinHeap) Len() int { return len(c.data) } +func (c *CustomMinHeap) Less(i int, j int) bool { return c.less(c.data[i], c.data[j]) } +func (c *CustomMinHeap) Push(x any) { c.data = append(c.data, x.(int)) } +func (c *CustomMinHeap) Swap(i int, j int) { c.data[i], c.data[j] = c.data[j], c.data[i] } + +func (c *CustomMinHeap) Pop() any { + last := c.data[len(c.data)-1] + c.data = c.data[:len(c.data)-1] + return last +} + +func totalCost(costs []int, k int, candidates int) int64 { + lessFn := func(i, j int) bool { + if costs[i] == costs[j] { + return i < j + } + return costs[i] < costs[j] + } + + indices := make([]int, 0, 2*candidates) + l, r := 0, len(costs)-1 + for l <= r && l < candidates { + indices = append(indices, l) + if l < r { + indices = append(indices, r) + } + l++ + r-- + } + + hp := &CustomMinHeap{data: indices, less: lessFn} + heap.Init(hp) + + cost := 0 + for range k { + i := heap.Pop(hp).(int) + cost += costs[i] + + if l <= r { + switch { + case i < l: + heap.Push(hp, l) + l++ + default: + heap.Push(hp, r) + r-- + } + } + } + return int64(cost) +} + +var _ = totalCost diff --git a/solutions/25/q2542/solution.go b/solutions/25/q2542/solution.go new file mode 100644 index 0000000..41dbe65 --- /dev/null +++ b/solutions/25/q2542/solution.go @@ -0,0 +1,58 @@ +package q2542 + +import ( + "container/heap" + "slices" +) + +type minHeap struct { + data []int + lessFn func(i, j int) bool +} + +func (m *minHeap) Len() int { return len(m.data) } +func (m *minHeap) Less(i int, j int) bool { return m.lessFn(m.data[i], m.data[j]) } +func (m *minHeap) Push(x any) { m.data = append(m.data, x.(int)) } +func (m *minHeap) Swap(i int, j int) { m.data[i], m.data[j] = m.data[j], m.data[i] } + +func (m *minHeap) Pop() any { + last := m.data[len(m.data)-1] + m.data = m.data[:len(m.data)-1] + return last +} + +func maxScore(nums1 []int, nums2 []int, k int) int64 { + indices := make([]int, len(nums1)) + for i := range indices { + indices[i] = i + } + slices.SortFunc(indices, func(a, b int) int { return nums2[b] - nums2[a] }) + + mh := &minHeap{ + data: make([]int, 0, k), + lessFn: func(a int, b int) bool { return nums1[a] < nums1[b] }, + } + + sum := 0 + for i := range k { + mh.data = append(mh.data, indices[i]) + sum += nums1[indices[i]] + } + heap.Init(mh) + maxScore := sum * nums2[indices[k-1]] + + for i := k; i < len(nums1); i++ { + realI := indices[i] + n1, n2 := nums1[realI], nums2[realI] + if nums1[mh.data[0]] < n1 { + sum = sum - nums1[mh.data[0]] + n1 + mh.data[0] = realI + heap.Fix(mh, 0) + maxScore = max(maxScore, sum*n2) + } + } + + return int64(maxScore) +} + +var _ = maxScore diff --git a/solutions/3/q328/solution.go b/solutions/3/q328/solution.go new file mode 100644 index 0000000..0579a9e --- /dev/null +++ b/solutions/3/q328/solution.go @@ -0,0 +1,29 @@ +package q328 + +type ListNode struct { + Val int + Next *ListNode +} + +func oddEvenList(head *ListNode) *ListNode { + odd := &ListNode{} + even := &ListNode{} + pO, pE := odd, even + + i := 0 + for p := head; p != nil; p = p.Next { + i++ + if i%2 == 0 { + pE.Next = p + pE = p + } else { + pO.Next = p + pO = p + } + } + pE.Next = nil + pO.Next = even.Next + return odd.Next +} + +var _ = oddEvenList diff --git a/solutions/3/q334/solution.go b/solutions/3/q334/solution.go new file mode 100644 index 0000000..2b0d9c1 --- /dev/null +++ b/solutions/3/q334/solution.go @@ -0,0 +1,24 @@ +package q334 + +import "math" + +func increasingTriplet(nums []int) bool { + if len(nums) < 3 { + return false + } + + first, second := math.MaxInt, math.MaxInt + + for _, x := range nums { + if x <= first { + first = x + } else if x <= second { + second = x + } else { + return true + } + } + return false +} + +var _ = increasingTriplet diff --git a/solutions/3/q394/solution.go b/solutions/3/q394/solution.go new file mode 100644 index 0000000..3346adf --- /dev/null +++ b/solutions/3/q394/solution.go @@ -0,0 +1,41 @@ +package q394 + +import "strings" + +func decode(s string) (int, string) { + advanced := 0 + number := 0 + buf := strings.Builder{} + +Loop: + for advanced < len(s) { + advanced++ + cur := s[advanced-1] + switch { + case cur >= '0' && cur <= '9': + number = 10*number + int(cur-'0') + + case cur == '[': + adv, child := decode(s[advanced:]) + advanced += adv + for range number { + buf.WriteString(child) + } + number = 0 + + case cur == ']': + break Loop + + default: + buf.WriteByte(cur) + } + } + return advanced, buf.String() +} + +func decodeString(s string) string { + _, ret := decode(s) + return ret +} + +var _ = decodeString diff --git a/solutions/33/q3314/solution.go b/solutions/33/q3314/solution.go new file mode 100644 index 0000000..71dd068 --- /dev/null +++ b/solutions/33/q3314/solution.go @@ -0,0 +1,19 @@ +package q3314 + +func minBitwiseArray(nums []int) []int { + for i := range nums { + if nums[i]%2 == 0 { + nums[i] = -1 + continue + } + + p := 1 + for nums[i]|(1<
0 { + prefix = append(prefix, node.Val+prefix[len(prefix)-1]) + } else { + prefix = append(prefix, node.Val) + } + + cnt := 0 + for i := range len(prefix) - 1 { + if prefix[len(prefix)-1]-prefix[i] == target { + cnt++ + } + } + if prefix[len(prefix)-1] == target { + cnt++ + } + + return cnt + count(node.Left, prefix, target) + count(node.Right, prefix, target) +} + +func pathSum(root *TreeNode, targetSum int) int { + return count(root, nil, targetSum) +} + +var _ = pathSum diff --git a/solutions/4/q443/solution.go b/solutions/4/q443/solution.go new file mode 100644 index 0000000..175c933 --- /dev/null +++ b/solutions/4/q443/solution.go @@ -0,0 +1,39 @@ +package q443 + +func compress(chars []byte) int { + seqLen := 0 + char := chars[0] + + p := 1 + + writeNumber := func(num int) { + i := 1 + for ; i*10 <= num; i *= 10 { + } + for ; i > 0; i /= 10 { + chars[p] = byte(num/i) + '0' + p++ + num %= i + } + } + + for _, c := range chars { + if c == char { + seqLen++ + } else { + char = c + if seqLen > 1 { + writeNumber(seqLen) + } + seqLen = 1 + chars[p] = char + p++ + } + } + if seqLen > 1 { + writeNumber(seqLen) + } + return p +} + +var _ = compress diff --git a/solutions/5/q547/solution.go b/solutions/5/q547/solution.go new file mode 100644 index 0000000..a3fa9bb --- /dev/null +++ b/solutions/5/q547/solution.go @@ -0,0 +1,25 @@ +package q547 + +func walk(graph [][]int, i int, seen []bool) { + for j := range graph { + if graph[i][j] == 1 && !seen[j] { + seen[j] = true + walk(graph, j, seen) + } + } +} + +func findCircleNum(isConnected [][]int) int { + seen := make([]bool, len(isConnected)) + + provinces := 0 + for i := range len(isConnected) { + if !seen[i] { + walk(isConnected, i, seen) + provinces++ + } + } + return provinces +} + +var _ = findCircleNum diff --git a/solutions/6/q649/solution.go b/solutions/6/q649/solution.go new file mode 100644 index 0000000..8155436 --- /dev/null +++ b/solutions/6/q649/solution.go @@ -0,0 +1,51 @@ +package q649 + +func predictPartyVictory(senate string) string { + n := len(senate) + revoked := make([]bool, n) + + rRevoke, dRevoke := 0, 0 + rRem, dRem := 0, 0 + for i := range n { + switch senate[i] { + case 'R': + rRem++ + case 'D': + dRem++ + } + } + + for i := 0; rRem > 0 && dRem > 0; i = (i + 1) % n { + if revoked[i] { + continue + } + + switch senate[i] { + case 'R': + if rRevoke > 0 { + rRevoke-- + rRem-- + revoked[i] = true + } else { + dRevoke++ + } + + case 'D': + if dRevoke > 0 { + dRevoke-- + dRem-- + revoked[i] = true + } else { + rRevoke++ + } + } + } + + if rRem == 0 { + return "Dire" + } else { + return "Radiant" + } +} + +var _ = predictPartyVictory diff --git a/solutions/7/q714/solution.go b/solutions/7/q714/solution.go new file mode 100644 index 0000000..06992fa --- /dev/null +++ b/solutions/7/q714/solution.go @@ -0,0 +1,33 @@ +package q714 + +// Note: could be done faster with dynamic programming + +func maxProfit(prices []int, fee int) int { + var low, high, profit int + bought := false + for i := range prices { + if bought { + high = max(high, prices[i]) + if high-prices[i] > fee { // should have sold earlier or not bought + if high-low > fee { + profit += high - low - fee + } + bought = false + } else if prices[i] < low { // regret buying too early + low, high = prices[i], prices[i] + } + } + + if !bought && i < len(prices)-1 && prices[i+1] > prices[i] { + bought = true // buy the dip + low, high = prices[i], prices[i] + } + } + + if bought && high-low > fee { + profit += high - low - fee + } + return profit +} + +var _ = maxProfit diff --git a/solutions/7/q735/solution.go b/solutions/7/q735/solution.go new file mode 100644 index 0000000..7319ee5 --- /dev/null +++ b/solutions/7/q735/solution.go @@ -0,0 +1,23 @@ +package q735 + +func asteroidCollision(asteroids []int) []int { + p := 0 + for _, a := range asteroids { + if a < 0 { + for p > 0 && asteroids[p-1] > 0 && asteroids[p-1] < -a { + p-- + } + if p > 0 && asteroids[p-1] > 0 { + if asteroids[p-1] == -a { + p-- + } + continue // explode + } + } + asteroids[p] = a + p++ + } + return asteroids[:p] +} + +var _ = asteroidCollision diff --git a/solutions/7/q739/solution.go b/solutions/7/q739/solution.go new file mode 100644 index 0000000..4734afa --- /dev/null +++ b/solutions/7/q739/solution.go @@ -0,0 +1,19 @@ +package q739 + +func dailyTemperatures(temperatures []int) []int { + waitDays := make([]int, len(temperatures)) + + idxStack := make([]int, 0, len(temperatures)) + for i, temp := range temperatures { + for len(idxStack) > 0 && temperatures[idxStack[len(idxStack)-1]] < temp { + popped := idxStack[len(idxStack)-1] + idxStack = idxStack[:len(idxStack)-1] // pop + + waitDays[popped] = i - popped + } + idxStack = append(idxStack, i) + } + return waitDays +} + +var _ = dailyTemperatures diff --git a/solutions/7/q790/solution.go b/solutions/7/q790/solution.go new file mode 100644 index 0000000..b6b06c6 --- /dev/null +++ b/solutions/7/q790/solution.go @@ -0,0 +1,24 @@ +package q790 + +const ( + TopHalf int8 = iota + BottomHalf + Full + + Modulo int = 1e9 + 7 +) + +func numTilings(n int) int { + cache := make([][3]int, n+1) + cache[0][Full] = 1 + cache[1][Full] = 1 + + for w := 2; w <= n; w++ { + cache[w][Full] = (cache[w-1][Full] + cache[w-2][Full] + cache[w-1][TopHalf] + cache[w-1][BottomHalf]) % Modulo + cache[w][TopHalf] = (cache[w-1][BottomHalf] + cache[w-2][Full]) % Modulo + cache[w][BottomHalf] = (cache[w-1][TopHalf] + cache[w-2][Full]) % Modulo + } + return cache[n][Full] +} + +var _ = numTilings diff --git a/solutions/8/q841/solution.go b/solutions/8/q841/solution.go new file mode 100644 index 0000000..7589b97 --- /dev/null +++ b/solutions/8/q841/solution.go @@ -0,0 +1,23 @@ +package q841 + +func canVisitAllRooms(rooms [][]int) bool { + locked := len(rooms) - 1 + + opened := make([]bool, len(rooms)) + opened[0] = true + + queue := []int{0} + for ; len(queue) > 0; queue = queue[1:] { + for _, i := range rooms[queue[0]] { + if opened[i] { + continue + } + opened[i] = true + locked-- + queue = append(queue, i) + } + } + return locked == 0 +} + +var _ = canVisitAllRooms diff --git a/solutions/8/q875/solution.go b/solutions/8/q875/solution.go new file mode 100644 index 0000000..0245211 --- /dev/null +++ b/solutions/8/q875/solution.go @@ -0,0 +1,31 @@ +package q875 + +import ( + "math" + "slices" +) + +func canEat(piles []int, h, speed int) bool { + needed := 0 + for _, n := range piles { + needed += int(math.Ceil(float64(n) / float64(speed))) + } + return needed <= h +} + +func minEatingSpeed(piles []int, h int) int { + maxK := slices.Max(piles) + + l, r := 1, maxK+1 + for l < r { + m := (l + r) / 2 + if canEat(piles, h, m) { + r = m + } else { + l = m + 1 + } + } + return l +} + +var _ = minEatingSpeed diff --git a/solutions/9/q901/solution.go b/solutions/9/q901/solution.go new file mode 100644 index 0000000..5ef4bb1 --- /dev/null +++ b/solutions/9/q901/solution.go @@ -0,0 +1,39 @@ +package q901 + +type Price struct { + day int + price int +} + +type StockSpanner struct { + days []Price + currentDay int +} + +func Constructor() StockSpanner { return StockSpanner{} } + +func (s *StockSpanner) Next(price int) int { + s.currentDay++ + + curr := Price{day: s.currentDay, price: price} + i := len(s.days) - 1 + for ; i >= 0; i-- { + if s.days[i].price > curr.price { + break + } + } + s.days = s.days[:i+1] + + ret := s.currentDay + if len(s.days) > 0 { + ret = s.currentDay - s.days[len(s.days)-1].day + } + s.days = append(s.days, curr) + return ret +} + +/** + * Your StockSpanner object will be instantiated and called as such: + * obj := Constructor(); + * param_1 := obj.Next(price); + */ diff --git a/solutions/9/q994/solution.go b/solutions/9/q994/solution.go new file mode 100644 index 0000000..6463457 --- /dev/null +++ b/solutions/9/q994/solution.go @@ -0,0 +1,48 @@ +package q994 + +func orangesRotting(grid [][]int) int { + w, h := len(grid[0]), len(grid) + queue := make([][3]int, 0, w+h) // row, col, minute + nFresh, nRot := 0, 0 + + for r := range grid { + for c := range grid[0] { + switch grid[r][c] { + case 1: + nFresh++ + case 2: + nRot++ + queue = append(queue, [3]int{r, c, 0}) + } + } + } + + var rot = func(r, c, minute int) { + if r < 0 || c < 0 || r >= h || c >= w || grid[r][c] != 1 { + return + } + grid[r][c] = 2 + nFresh-- + nRot++ + queue = append(queue, [3]int{r, c, minute}) + } + + minutes := 0 + for ; len(queue) > 0; queue = queue[1:] { + cur := queue[0] + r, c, minute := cur[0], cur[1], cur[2] + minutes = max(minute, minutes) + + rot(r, c+1, minute+1) + rot(r, c-1, minute+1) + rot(r+1, c, minute+1) + rot(r-1, c, minute+1) + } + + if nFresh == 0 { + return minutes + } + return -1 +} + +var _ = orangesRotting