leetcode 1040. Перемещайте камни до непрерывного II

Ссылка на оригинальное название: Likou

На  числовой прямой бесконечной  длины  i положение первого камня равно  stones[i]. Если камешек имеет наименьшую/максимальную позицию, то такой камешек называется  конечным камнем  .

Каждый ход вы можете брать и перемещать конечный камень в незанятое место, что делает его неконечным камнем.

Стоит отметить, что если камешек такой  stones = [1,2,5] , вы  не сможете  переместить конечный камешек в положение 5, потому что независимо от того, в какое положение вы его переместите (например, 0 или 3), камешек все равно будет конечная галька.

Когда вы не можете делать никаких ходов, то есть когда позиции этих камней непрерывны, игра окончена.

Какое минимальное и максимальное количество ходов вы можете сделать, чтобы закончить игру? Возвращает ответ в виде массива длины 2: answer = [minimum_moves, maximum_moves] .

Пример 1:

Ввод: [7,4,9]
 Вывод: [1,2]
 Объяснение: 
Мы можем сделать один ход, 4 -> 8, игра окончена. 
В качестве альтернативы мы можем дважды переместить 9 -> 5, 4 -> 6, и игра окончена.

Пример 2:

Ввод: [6,5,4,3,10]
 Вывод: [2,3]
 Объяснение: 
Мы можем переместить 3 -> 8, затем 10 -> 7, игра окончена. 
В качестве альтернативы мы можем переместить 3 -> 7, 4 -> 8, 5 -> 9, игра окончена. 
Обратите внимание, что мы не можем сделать ход вроде 10 -> 2, чтобы закончить игру, так как это нежелательный ход.

Пример 3:

Ввод: [100,101,104,102,103]
 Вывод: [0,0]

Аннотированная версия решения:

class Solution {
public:
    vector<int> numMovesStonesII(vector<int>& stones) {
        // 获取石头数量
        int n = stones.size();
        // 将石头按位置排序
        sort(stones.begin(), stones.end());
        // 如果石头形成一个连续的序列,那么不需要移动就可以完成游戏,返回结果{0,0}
        if (stones.back() - stones[0] + 1 == n) {
            return {0, 0};
        }
        // 找到移动石头的最大值和最小值
        // 移动最大值就是将一侧的所有石头移动到另一侧,其中不需要移动的石头数量为 n - 1
        // 因此,最大值是两侧剩余石头数量的较大值减去需要移动的石头数量 n - 1
        int ma = max(stones[n - 2] - stones[0] + 1, stones[n - 1] - stones[1] + 1) - (n - 1);
        // 移动最小值就是将剩余的石头尽可能地靠拢,形成最大的连续序列
        int mi = n;
        // 遍历石头,找到最长的连续子序列
        for (int i = 0, j = 0; i < n && j + 1 < n; ++i) {
            // 在当前位置 i 的情况下,找到最远的 j,使得区间 [i,j] 中的石头可以放到一起,形成连续的子序列
            while (j + 1 < n && stones[j + 1] - stones[i] + 1 <= n) {
                ++j;
            }
            // 如果当前连续子序列的长度等于 n - 1,且两端的石头分别与序列的首尾相邻,那么只需要移动 2 个石头就可以形成连续的序列
            if (j - i + 1 == n - 1 && stones[j] - stones[i] + 1 == n - 1) {
                mi = min(mi, 2);
            } else {
                // 否则,需要移动 n - (j - i + 1) 个石头才能形成连续的序列
                mi = min(mi, n - (j - i + 1));
            }
        }
        // 返回最小值和最大值
        return {mi, ma};
    }
};

рекомендация

отblog.csdn.net/qq_40016005/article/details/130007548