# 第 42 场双周赛题解

# Q1 1700. 无法吃午餐的学生数量 (opens new window)

有点意思的题目,可以无视学生的顺序,只要栈顶的三明治有学生能吃掉就可以吃,直到没有人能吃掉栈顶的三明治为止。

class Solution1700 {
    fun countStudents(students: IntArray, sandwiches: IntArray): Int {
        val cur = ArrayList(students.toList())
        sandwiches.forEach {
            if (it in cur) {
                cur.remove(it)
            } else {
                return cur.size
            }
        }
        return 0
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# Q2 1701. 平均等待时间 (opens new window)

正常模拟即可。需要注意数值范围,刚开始用IntIntWAWA了一次...

class Solution1701 {
    fun averageWaitingTime(customers: Array<IntArray>): Double {
        var cur = 0
        var ans = 0.0
        customers.forEach {
            cur = maxOf(cur, it[0])
            cur += it[1]
            ans += cur - it[0]
        }
        return ans / customers.size
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# Q3 1702. 修改后的最大二进制字符串 (opens new window)

先解读两种操作的逻辑:

  1. 1010转换为0101相当于让11值沉底,但不影响0011的总数
  2. 0000转换为1010让顶部值变为11

观察数据后可知,最优解法是除最左侧连续的11以外,将所有的11沉底,其余位从左到右均设置为11,仅保留一位00

class Solution1702 {
    fun maximumBinaryString(binary: String): String {
        if (binary.all { it == '1' }) return binary
        val n = binary.length
        var meet = false
        var r = 0
        for (i in binary.indices) {
            if (binary[i] == '0') {
                meet = true
            } else if (binary[i] == '1' && meet) {
                r++
            }
        }
        val ans = CharArray(n) { '1' }
        ans[n - r - 1] = '0'
        return ans.joinToString("")
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Q4 1703. 得到连续 K 个 1 的最少相邻交换次数 (opens new window)

这道题需要理解加油站中位数解法。我们使用滑动窗口,保证窗口内有kk个1存在。此时,若要将这kk11挨在一起需要转化为每个11距离当前中位数11的位置的距离。

对于奇数个11来说,如101001101001,移动到011100011100花费最小。比如若是001110001110为最终结果,则需要左侧两个11多移动一次,而右侧11少移动一次,得不偿失。

而对于偶数个11,则是无论以那个为中心不动,结果都是相同的。如1100100111001001,最终结果可以为1111000011110000也可以为0011110000111100,它们的costcost都是66。都是左侧若+1+1则右侧的都1-1,总体的costcost是稳定的。

国际服图解题解 (opens new window)

时间复杂度:O(n)O(n)

class Solution5624 {
    fun minMoves(nums: IntArray, k: Int): Int {
        var ans = Int.MAX_VALUE
        val l = arrayListOf<Int>()
        var cur = 0
        for (i in nums.indices) {
            if (nums[i] != 1) {
                continue
            }
            if (l.size < k) {
                l.add(i)
                if (l.size == k) {
                    val mid = l[(k - 1) / 2]
                    l.forEachIndexed { index, it ->
                        cur += abs(it - mid) - abs(k / 2 - index)
                    }
                }
            } else {
                ans = minOf(ans, cur)
                var mid = l[l.size / 2]
                l.add(i)
                cur += i - mid

                mid = l[l.size / 2]
                val j = l.removeAt(0)
                cur -= mid - j
            }
        }
        return minOf(ans, cur)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31