Skip to content

Commit 701f15d

Browse files
authored
Improved tasks 3510, 3515
1 parent 95f4181 commit 701f15d

File tree

3 files changed

+200
-167
lines changed
  • src
    • main/kotlin/g3501_3600
    • test/kotlin/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii

3 files changed

+200
-167
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,119 @@
11
package g3501_3600.s3510_minimum_pair_removal_to_sort_array_ii
22

33
// #Hard #Array #Hash_Table #Heap_Priority_Queue #Simulation #Linked_List #Ordered_Set
4-
// #Doubly_Linked_List #2025_04_09_Time_219_ms_(100.00%)_Space_108.86_MB_(9.09%)
4+
// #Doubly_Linked_List #2025_04_29_Time_172_ms_(100.00%)_Space_85.64_MB_(66.67%)
55

6-
class Solution {
7-
private class Segment {
8-
private val start: Int
9-
private val end: Int
10-
private var left: Segment? = null
11-
private var right: Segment? = null
12-
private var lIdx: Int = 0
13-
private var lNum: Long = 0
14-
private var rIdx: Int = 0
15-
private var rNum: Long = 0
16-
var ok: Boolean = false
17-
var minSum: Long = 0
18-
var li: Int = 0
19-
var ri: Int = 0
6+
import kotlin.math.ceil
7+
import kotlin.math.ln
8+
import kotlin.math.min
9+
import kotlin.math.pow
2010

21-
companion object {
22-
fun init(arr: IntArray): Segment {
23-
return Segment(arr, 0, arr.size - 1)
24-
}
11+
class Solution {
12+
fun minimumPairRemoval(nums: IntArray): Int {
13+
if (nums.size == 1) {
14+
return 0
2515
}
26-
27-
constructor(arr: IntArray, s: Int, e: Int) {
28-
start = s
29-
end = e
30-
if (s >= e) {
31-
lIdx = s
32-
rIdx = s
33-
lNum = arr[s].toLong()
34-
rNum = arr[s].toLong()
35-
minSum = Long.MAX_VALUE
36-
ok = true
37-
return
16+
val size = 2.0.pow(ceil(ln(nums.size - 1.0) / ln(2.0))).toInt()
17+
val segment = LongArray(size * 2 - 1)
18+
segment.fill(Long.Companion.MAX_VALUE)
19+
val lefts = IntArray(size * 2 - 1)
20+
val rights = IntArray(size * 2 - 1)
21+
val sums = LongArray(nums.size)
22+
sums.fill(Long.Companion.MAX_VALUE / 2)
23+
val arrIdxToSegIdx: Array<IntArray> = Array(nums.size) { IntArray(0) }
24+
sums[0] = nums[0].toLong()
25+
var count = 0
26+
arrIdxToSegIdx[0] = intArrayOf(-1, size - 1)
27+
for (i in 1..<nums.size) {
28+
if (nums[i] < nums[i - 1]) {
29+
count++
3830
}
39-
val mid = s + ((e - s) shr 1)
40-
left = Segment(arr, s, mid)
41-
right = Segment(arr, mid + 1, e)
42-
merge()
31+
lefts[size + i - 2] = i - 1
32+
rights[size + i - 2] = i
33+
segment[size + i - 2] = nums[i - 1] + nums[i].toLong()
34+
arrIdxToSegIdx[i] = intArrayOf(size + i - 2, size + i - 1)
35+
sums[i] = nums[i].toLong()
4336
}
44-
45-
private fun merge() {
46-
left?.let { left ->
47-
right?.let { right ->
48-
lIdx = left.lIdx
49-
lNum = left.lNum
50-
rIdx = right.rIdx
51-
rNum = right.rNum
52-
ok = left.ok && right.ok && left.rNum <= right.lNum
53-
minSum = left.minSum
54-
li = left.li
55-
ri = left.ri
56-
if (left.rNum + right.lNum < minSum) {
57-
minSum = left.rNum + right.lNum
58-
li = left.rIdx
59-
ri = right.lIdx
60-
}
61-
if (right.minSum < minSum) {
62-
minSum = right.minSum
63-
li = right.li
64-
ri = right.ri
65-
}
66-
}
67-
}
37+
arrIdxToSegIdx[nums.size - 1][1] = -1
38+
for (i in size - 2 downTo 0) {
39+
val l = 2 * i + 1
40+
val r = 2 * i + 2
41+
segment[i] = min(segment[l], segment[r])
6842
}
43+
return getRes(count, segment, lefts, rights, sums, arrIdxToSegIdx)
44+
}
6945

70-
fun update(i: Int, n: Long) {
71-
if (start <= i && end >= i) {
72-
if (start >= end) {
73-
lNum = n
74-
rNum = n
46+
private fun getRes(
47+
count: Int,
48+
segment: LongArray,
49+
lefts: IntArray,
50+
rights: IntArray,
51+
sums: LongArray,
52+
arrIdxToSegIdx: Array<IntArray>,
53+
): Int {
54+
var count = count
55+
var res = 0
56+
while (count > 0) {
57+
var segIdx = 0
58+
while (2 * segIdx + 1 < segment.size) {
59+
val l = 2 * segIdx + 1
60+
val r = 2 * segIdx + 2
61+
segIdx = if (segment[l] <= segment[r]) {
62+
l
7563
} else {
76-
left?.update(i, n)
77-
right?.update(i, n)
78-
merge()
64+
r
7965
}
8066
}
81-
}
82-
83-
fun remove(i: Int): Segment? {
84-
if (start > i || end < i) {
85-
return this
86-
} else if (start >= end) {
87-
return null
67+
val arrIdxL = lefts[segIdx]
68+
val arrIdxR = rights[segIdx]
69+
val numL = sums[arrIdxL]
70+
val numR = sums[arrIdxR]
71+
if (numL > numR) {
72+
count--
73+
}
74+
sums[arrIdxL] = sums[arrIdxL] + sums[arrIdxR]
75+
val newSum = sums[arrIdxL]
76+
val leftPointer = arrIdxToSegIdx[arrIdxL]
77+
val rightPointer = arrIdxToSegIdx[arrIdxR]
78+
val prvSegIdx = leftPointer[0]
79+
val nextSegIdx = rightPointer[1]
80+
leftPointer[1] = nextSegIdx
81+
if (prvSegIdx != -1) {
82+
val l = lefts[prvSegIdx]
83+
if (sums[l] > numL && sums[l] <= newSum) {
84+
count--
85+
} else if (sums[l] <= numL && sums[l] > newSum) {
86+
count++
87+
}
88+
modify(segment, prvSegIdx, sums[l] + newSum)
8889
}
89-
left = left?.remove(i)
90-
right = right?.remove(i)
91-
if (left == null) {
92-
return right
93-
} else if (right == null) {
94-
return left
90+
if (nextSegIdx != -1) {
91+
val r = rights[nextSegIdx]
92+
if (numR > sums[r] && newSum <= sums[r]) {
93+
count--
94+
} else if (numR <= sums[r] && newSum > sums[r]) {
95+
count++
96+
}
97+
modify(segment, nextSegIdx, newSum + sums[r])
98+
lefts[nextSegIdx] = arrIdxL
9599
}
96-
merge()
97-
return this
100+
modify(segment, segIdx, Long.Companion.MAX_VALUE)
101+
res++
98102
}
103+
return res
99104
}
100105

101-
fun minimumPairRemoval(nums: IntArray): Int {
102-
var root = Segment.init(nums)
103-
var res = 0
104-
while (!root.ok) {
105-
val l = root.li
106-
val r = root.ri
107-
root.update(l, root.minSum)
108-
root = root.remove(r) ?: break
109-
res++
106+
private fun modify(segment: LongArray, idx: Int, num: Long) {
107+
var idx = idx
108+
if (segment[idx] == num) {
109+
return
110+
}
111+
segment[idx] = num
112+
while (idx != 0) {
113+
idx = (idx - 1) / 2
114+
val l = 2 * idx + 1
115+
val r = 2 * idx + 2
116+
segment[idx] = min(segment[l], segment[r])
110117
}
111-
return res
112118
}
113119
}

0 commit comments

Comments
 (0)