diff --git a/src/main/kotlin/g0901_1000/s0999_available_captures_for_rook/Solution.kt b/src/main/kotlin/g0901_1000/s0999_available_captures_for_rook/Solution.kt index 11cb77c64..1256814ac 100644 --- a/src/main/kotlin/g0901_1000/s0999_available_captures_for_rook/Solution.kt +++ b/src/main/kotlin/g0901_1000/s0999_available_captures_for_rook/Solution.kt @@ -1,98 +1,56 @@ package g0901_1000.s0999_available_captures_for_rook -// #Easy #Array #Matrix #Simulation #2023_05_13_Time_143_ms_(80.00%)_Space_34.6_MB_(60.00%) +// #Easy #Array #Matrix #Simulation #2025_03_13_Time_0_ms_(100.00%)_Space_40.08_MB_(8.33%) -@Suppress("NAME_SHADOWING") class Solution { - private val directions = intArrayOf(0, 1, 0, -1, 0) fun numRookCaptures(board: Array): Int { - val m = board.size - val n = board[0].size - var rowR = -1 - var colR = -1 - for (i in 0 until m) { - for (j in 0 until n) { + // Find the position of the rook + var rookRow = -1 + var rookCol = -1 + for (i in 0..7) { + for (j in 0..7) { if (board[i][j] == 'R') { - rowR = i - colR = j + rookRow = i + rookCol = j break } } - } - val count = intArrayOf(0) - for (i in 0..3) { - val neighborRow = rowR + directions[i] - val neighborCol = colR + directions[i + 1] - if (neighborRow in 0 until m && neighborCol >= 0 && neighborCol < n && - board[neighborRow][neighborCol] != 'B' - ) { - if (directions[i] == 0 && directions[i + 1] == 1) { - extracted(board, n, count, neighborRow, neighborCol) - } else if (directions[i] == 1 && directions[i + 1] == 0) { - extracted1(board, m, count, neighborRow, neighborCol) - } else if (directions[i] == 0 && directions[i + 1] == -1) { - extracted(board, count, neighborRow, neighborCol) - } else { - extracted1(board, count, neighborRow, neighborCol) - } - } - } - return count[0] - } - - private fun extracted(board: Array, count: IntArray, neighborRow: Int, neighborCol: Int) { - var neighborCol = neighborCol - while (neighborCol >= 0) { - if (board[neighborRow][neighborCol] == 'p') { - count[0]++ + if (rookRow != -1) { break - } else if (board[neighborRow][neighborCol] == 'B') { - break - } else { - neighborCol-- } } - } - - private fun extracted(board: Array, n: Int, count: IntArray, neighborRow: Int, neighborCol: Int) { - var neighborCol = neighborCol - while (neighborCol < n) { - if (board[neighborRow][neighborCol] == 'p') { - count[0]++ - break - } else if (board[neighborRow][neighborCol] == 'B') { - break - } else { - neighborCol++ - } - } - } - - private fun extracted1(board: Array, count: IntArray, neighborRow: Int, neighborCol: Int) { - var neighborRow = neighborRow - while (neighborRow >= 0) { - if (board[neighborRow][neighborCol] == 'p') { - count[0]++ - break - } else if (board[neighborRow][neighborCol] == 'B') { - break - } else { - neighborRow-- - } - } - } - - private fun extracted1(board: Array, m: Int, count: IntArray, neighborRow: Int, neighborCol: Int) { - var neighborRow = neighborRow - while (neighborRow < m) { - if (board[neighborRow][neighborCol] == 'p') { - count[0]++ - break - } else if (board[neighborRow][neighborCol] == 'B') { - break - } else { - neighborRow++ + // Define the four directions: up, right, down, left + val directions = arrayOf( // up + intArrayOf(-1, 0), // right + intArrayOf(0, 1), // down + intArrayOf(1, 0), // left + intArrayOf(0, -1), + ) + var captureCount = 0 + // Check each direction + for (dir in directions) { + var row = rookRow + var col = rookCol + while (true) { + // Move one step in the current direction + row += dir[0] + col += dir[1] + // Check if out of bounds + if (row < 0 || row >= 8 || col < 0 || col >= 8) { + break + } + // If we hit a bishop, we're blocked + if (board[row][col] == 'B') { + break + } + // If we hit a pawn, we can capture it and then we're blocked + if (board[row][col] == 'p') { + captureCount++ + break + } + // Otherwise (empty square), continue in the same direction } } + return captureCount } } diff --git a/src/main/kotlin/g1801_1900/s1825_finding_mk_average/MKAverage.kt b/src/main/kotlin/g1801_1900/s1825_finding_mk_average/MKAverage.kt index 8cae4c3e5..3c542b072 100644 --- a/src/main/kotlin/g1801_1900/s1825_finding_mk_average/MKAverage.kt +++ b/src/main/kotlin/g1801_1900/s1825_finding_mk_average/MKAverage.kt @@ -1,131 +1,62 @@ package g1801_1900.s1825_finding_mk_average // #Hard #Design #Heap_Priority_Queue #Ordered_Set #Queue -// #2023_06_21_Time_1101_ms_(100.00%)_Space_122.8_MB_(100.00%) +// #2025_03_13_Time_69_ms_(100.00%)_Space_98.49_MB_(100.00%) -import java.util.Deque import java.util.LinkedList -import java.util.TreeMap +import java.util.TreeSet +import kotlin.math.abs +import kotlin.math.min -@Suppress("NAME_SHADOWING") -class MKAverage(m: Int, k: Int) { - private val m: Double - private val k: Double - private val c: Double - private var avg: Double - private val middle: Bst - private val min: Bst - private val max: Bst - private val q: Deque - - init { - this.m = m.toDouble() - this.k = k.toDouble() - c = (m - k * 2).toDouble() - avg = 0.0 - middle = Bst() - min = Bst() - max = Bst() - q = LinkedList() - } +class MKAverage(private val capacity: Int, private val boundary: Int) { + private val nums: IntArray = IntArray(100001) + private val numSet: TreeSet = TreeSet() + private val order: LinkedList = LinkedList() fun addElement(num: Int) { - var num = num - if (min.size < k) { - min.add(num) - q.offer(num) - return - } - if (max.size < k) { - min.add(num) - max.add(min.removeMax()) - q.offer(num) - return - } - if (num >= min.lastKey() && num <= max.firstKey()) { - middle.add(num) - avg += num / c - } else if (num < min.lastKey()) { - min.add(num) - val `val` = min.removeMax() - middle.add(`val`) - avg += `val` / c - } else if (num > max.firstKey()) { - max.add(num) - val `val` = max.removeMin() - middle.add(`val`) - avg += `val` / c - } - q.offer(num) - if (q.size > m) { - num = q.poll() - if (middle.containsKey(num)) { - avg -= num / c - middle.remove(num) - } else if (min.containsKey(num)) { - min.remove(num) - val `val` = middle.removeMin() - avg -= `val` / c - min.add(`val`) - } else if (max.containsKey(num)) { - max.remove(num) - val `val` = middle.removeMax() - avg -= `val` / c - max.add(`val`) + if (order.size == capacity) { + val numToDelete = order.removeFirst() + nums[numToDelete] = nums[numToDelete] - 1 + if (nums[numToDelete] == 0) { + numSet.remove(numToDelete) } } + nums[num]++ + numSet.add(num) + order.add(num) } fun calculateMKAverage(): Int { - return if (q.size < m) { - -1 - } else { - avg.toInt() - } - } - - internal class Bst { - var map: TreeMap = TreeMap() - var size: Int = 0 - - fun add(num: Int) { - val count = map.getOrDefault(num, 0) + 1 - map[num] = count - size++ - } - - fun remove(num: Int) { - val count = map.getOrDefault(num, 1) - 1 - if (count > 0) { - map[num] = count - } else { - map.remove(num) + if (order.size == capacity) { + var skipCount = boundary + var numsCount = capacity - 2 * boundary + val freq = capacity - 2 * boundary + var sum = 0 + for (num in numSet) { + val count = nums[num] + if (skipCount < 0) { + sum += num * min(count, numsCount) + numsCount = (numsCount - min(count, numsCount)).toInt() + } else { + skipCount -= count + if (skipCount < 0) { + sum += num * min(abs(skipCount), numsCount) + numsCount = (numsCount - min(abs(skipCount), numsCount)).toInt() + } + } + if (numsCount == 0) { + break + } } - size-- - } - - fun removeMin(): Int { - val key = map.firstKey() - remove(key) - return key - } - - fun removeMax(): Int { - val key = map.lastKey() - remove(key) - return key - } - - fun containsKey(key: Int): Boolean { - return map.containsKey(key) - } - - fun firstKey(): Int { - return map.firstKey() - } - - fun lastKey(): Int { - return map.lastKey() + return sum / freq } + return -1 } } + +/* + * Your MKAverage object will be instantiated and called as such: + * var obj = MKAverage(m, k) + * obj.addElement(num) + * var param_2 = obj.calculateMKAverage() + */ diff --git a/src/main/kotlin/g3401_3500/s3425_longest_special_path/Solution.kt b/src/main/kotlin/g3401_3500/s3425_longest_special_path/Solution.kt index cac8f2239..91fc3176d 100644 --- a/src/main/kotlin/g3401_3500/s3425_longest_special_path/Solution.kt +++ b/src/main/kotlin/g3401_3500/s3425_longest_special_path/Solution.kt @@ -1,92 +1,64 @@ package g3401_3500.s3425_longest_special_path // #Hard #Array #Hash_Table #Depth_First_Search #Tree #Sliding_Window -// #2025_01_19_Time_106_ms_(100.00%)_Space_187.68_MB_(100.00%) +// #2025_03_13_Time_59_ms_(100.00%)_Space_123.56_MB_(55.56%) -class Solution { - private lateinit var adj: Array> - private lateinit var nums: IntArray - private lateinit var dist: IntArray - private lateinit var lastOccur: IntArray - private lateinit var pathStack: ArrayList - private var minIndex = 0 - private var maxLen = 0 - private var minNodesForMaxLen = 0 +import kotlin.math.max +@Suppress("kotlin:S107") +class Solution { fun longestSpecialPath(edges: Array, nums: IntArray): IntArray { - val n = nums.size - this.nums = nums - adj = Array>(n) { ArrayList() } + val n = edges.size + 1 + var max = 0 + val adj: Array> = Array(n) { ArrayList() } for (i in 0..() + max = max(nums[i], max) } for (e in edges) { - val u = e[0] - val v = e[1] - val w = e[2] - adj[u].add(intArrayOf(v, w)) - adj[v].add(intArrayOf(u, w)) - } - dist = IntArray(n) - buildDist(0, -1, 0) - var maxVal = 0 - for (`val` in nums) { - if (`val` > maxVal) { - maxVal = `val` - } - } - lastOccur = IntArray(maxVal + 1) - lastOccur.fill(-1) - pathStack = ArrayList() - minIndex = 0 - maxLen = 0 - minNodesForMaxLen = Int.Companion.MAX_VALUE - dfs(0, -1) - return intArrayOf(maxLen, minNodesForMaxLen) - } - - private fun buildDist(u: Int, parent: Int, currDist: Int) { - dist[u] = currDist - for (edge in adj[u]) { - val v = edge[0] - val w = edge[1] - if (v == parent) { - continue - } - buildDist(v, u, currDist + w) + adj[e[0]].add(intArrayOf(e[1], e[2])) + adj[e[1]].add(intArrayOf(e[0], e[2])) } + val dist = IntArray(n) + val res = intArrayOf(0, Int.Companion.MAX_VALUE) + val st = IntArray(n + 1) + val seen = arrayOfNulls(max + 1) + dfs(adj, nums, res, dist, seen, st, 0, -1, 0, 0) + return res } - private fun dfs(u: Int, parent: Int) { - val stackPos = pathStack.size - pathStack.add(u) - val `val` = nums[u] - val oldPos = lastOccur[`val`] - val oldMinIndex = minIndex - lastOccur[`val`] = stackPos - if (oldPos >= minIndex) { - minIndex = oldPos + 1 + private fun dfs( + adj: Array>, + nums: IntArray, + res: IntArray, + dist: IntArray, + seen: Array, + st: IntArray, + node: Int, + parent: Int, + start: Int, + pos: Int, + ) { + var start = start + val last = seen[nums[node]] + if (last != null && last >= start) { + start = last + 1 } - if (minIndex <= stackPos) { - val ancestor = pathStack[minIndex] - val pathLength = dist[u] - dist[ancestor] - val pathNodes = stackPos - minIndex + 1 - if (pathLength > maxLen) { - maxLen = pathLength - minNodesForMaxLen = pathNodes - } else if (pathLength == maxLen && pathNodes < minNodesForMaxLen) { - minNodesForMaxLen = pathNodes - } + seen[nums[node]] = pos + st[pos] = node + val len = dist[node] - dist[st[start]] + val sz = pos - start + 1 + if (res[0] < len || res[0] == len && res[1] > sz) { + res[0] = len + res[1] = sz } - for (edge in adj[u]) { - val v = edge[0] - if (v == parent) { + for (neighbor in adj[node]) { + if (neighbor[0] == parent) { continue } - dfs(v, u) + dist[neighbor[0]] = dist[node] + neighbor[1] + dfs(adj, nums, res, dist, seen, st, neighbor[0], node, start, pos + 1) } - pathStack.removeAt(pathStack.size - 1) - lastOccur[`val`] = oldPos - minIndex = oldMinIndex + seen[nums[node]] = last } } diff --git a/src/main/kotlin/g3401_3500/s3441_minimum_cost_good_caption/Solution.kt b/src/main/kotlin/g3401_3500/s3441_minimum_cost_good_caption/Solution.kt index 3f8a525e7..e96fef711 100644 --- a/src/main/kotlin/g3401_3500/s3441_minimum_cost_good_caption/Solution.kt +++ b/src/main/kotlin/g3401_3500/s3441_minimum_cost_good_caption/Solution.kt @@ -1,167 +1,72 @@ package g3401_3500.s3441_minimum_cost_good_caption -// #Hard #String #Dynamic_Programming #2025_02_05_Time_78_ms_(100.00%)_Space_51.28_MB_(100.00%) +// #Hard #String #Dynamic_Programming #2025_03_13_Time_48_ms_(83.33%)_Space_48.60_MB_(83.33%) -import kotlin.math.abs -import kotlin.math.min +import kotlin.math.max -@Suppress("kotlin:S107") class Solution { fun minCostGoodCaption(caption: String): String { val n = caption.length if (n < 3) { return "" } - val arr = caption.toCharArray() - val prefixCost = Array(n + 1) { IntArray(26) } - for (i in 0.. 0) { - nextIndex[i] = i + l - nextChar[i] = bestLetter - blockLen[i] = l - } - } + val s = caption.toByteArray() + val f = IntArray(n + 1) + f[n - 2] = Int.Companion.MAX_VALUE / 2 + f[n - 1] = f[n - 2] + val t = ByteArray(n + 1) + val size = ByteArray(n) + for (i in n - 3 downTo 0) { + val sub = s.copyOfRange(i, i + 3) + sub.sort() + val a = sub[0] + val b = sub[1] + val c = sub[2] + val s3 = t[i + 3] + var res = f[i + 3] + (c - a) + var mask = b.toInt() shl 24 or (s3.toInt() shl 16) or (s3.toInt() shl 8) or s3.toInt() + size[i] = 3 + if (i + 4 <= n) { + val sub4 = s.copyOfRange(i, i + 4) + sub4.sort() + val a4 = sub4[0] + val b4 = sub4[1] + val c4 = sub4[2] + val d4 = sub4[3] + val s4 = t[i + 4] + val res4 = f[i + 4] + (c4 - a4 + d4 - b4) + val mask4 = b4.toInt() shl 24 or (b4.toInt() shl 16) or (s4.toInt() shl 8) or s4.toInt() + if (res4 < res || res4 == res && mask4 < mask) { + res = res4 + mask = mask4 + size[i] = 4 } } - } - if (dp[0] >= INF) { - return "" - } - val builder = StringBuilder(n) - var idx = 0 - while (idx < n) { - val len = blockLen[idx] - val c = nextChar[idx] - (0.. - builder.append(('a'.code + c).toChar()) - } - idx = nextIndex[idx] - } - return builder.toString() - } - - private fun compareSolutions( - oldLetter: Int, - oldLen: Int, - oldNext: Int, - newLetter: Int, - newLen: Int, - newNext: Int, - nextIndex: IntArray, - nextChar: IntArray, - blockLen: IntArray, - n: Int, - ): Int { - var offsetOld = 0 - var offsetNew = 0 - var curOldPos: Int - var curNewPos: Int - var letOld = oldLetter - var letNew = newLetter - var lenOld = oldLen - var lenNew = newLen - var nxtOld = oldNext - var nxtNew = newNext - while (true) { - if (letOld != letNew) { - return if (letOld < letNew) -1 else 1 - } - val remainOld = lenOld - offsetOld - val remainNew = lenNew - offsetNew - val step = min(remainOld.toDouble(), remainNew.toDouble()).toInt() - offsetOld += step - offsetNew += step - if (offsetOld == lenOld && offsetNew == lenNew) { - if (nxtOld == n && nxtNew == n) { - return 0 - } - if (nxtOld == n) { - return -1 - } - if (nxtNew == n) { - return 1 - } - curOldPos = nxtOld - letOld = nextChar[curOldPos] - lenOld = blockLen[curOldPos] - nxtOld = nextIndex[curOldPos] - offsetOld = 0 - curNewPos = nxtNew - letNew = nextChar[curNewPos] - lenNew = blockLen[curNewPos] - nxtNew = nextIndex[curNewPos] - offsetNew = 0 - } else if (offsetOld == lenOld) { - if (nxtOld == n) { - return -1 + if (i + 5 <= n) { + val sub5 = s.copyOfRange(i, i + 5) + sub5.sort() + val a5 = sub5[0] + val b5 = sub5[1] + val c5 = sub5[2] + val d5 = sub5[3] + val e5 = sub5[4] + val res5 = f[i + 5] + (d5 - a5 + e5 - b5) + val mask5 = c5.toInt() shl 24 or (c5.toInt() shl 16) or (c5.toInt() shl 8) or t[i + 5].toInt() + if (res5 < res || res5 == res && mask5 < mask) { + res = res5 + mask = mask5 + size[i] = 5 } - curOldPos = nxtOld - letOld = nextChar[curOldPos] - lenOld = blockLen[curOldPos] - nxtOld = nextIndex[curOldPos] - offsetOld = 0 - } else if (offsetNew == lenNew) { - if (nxtNew == n) { - return 1 - } - curNewPos = nxtNew - letNew = nextChar[curNewPos] - lenNew = blockLen[curNewPos] - nxtNew = nextIndex[curNewPos] - offsetNew = 0 } + f[i] = res + t[i] = (mask shr 24).toByte() } - } - - companion object { - private const val INF = Int.Companion.MAX_VALUE / 2 + val ans = StringBuilder(n) + var i = 0 + while (i < n) { + ans.append(Char(t[i].toUShort()).toString().repeat(max(0.0, size[i].toDouble()).toInt())) + i += size[i].toInt() + } + return ans.toString() } }