【每日一题Day170】LC1040移动石子直到连续 II | 双指针 贪心 数学

简介: 【每日一题Day170】LC1040移动石子直到连续 II | 双指针 贪心 数学

移动石子直到连续 II【LC1040】

在一个长度 无限 的数轴上,第 i 颗石子的位置为 stones[i]。如果一颗石子的位置最小/最大,那么该石子被称作 端点石子

每个回合,你可以将一颗端点石子拿起并移动到一个未占用的位置,使得该石子不再是一颗端点石子。

值得注意的是,如果石子像 stones = [1,2,5] 这样,你将 无法 移动位于位置 5 的端点石子,因为无论将它移动到任何位置(例如 0 或 3),该石子都仍然会是端点石子。

当你无法进行任何移动时,即,这些石子的位置连续时,游戏结束。

要使游戏结束,你可以执行的最小和最大移动次数分别是多少? 以长度为 2 的数组形式返回答案:answer = [minimum_moves, maximum_moves]

这几天一直在干活 然后昨天下午做题一直被打断 最后我都以为自己已经发好题解了 结果并没有发…

  • 思路
  • 首先,明确每次移动时只能移动端点,并且端点移动后不能还是端点,即移动后石子的左侧和右侧必须有其他石子。每次移动后两边端点的距离较小
  • 什么时候无法移动?

         所有石子之间没有空位,都位于连续的n个位置

  • 如何获得最大移动次数?

           每次移动,都让移动的距离尽可能小【贪心】,那么移动次数就能达到最大。

           那么第一次移动存在两种移动方式

  • 移动stones[0]stones[1]+1
  • 移动stones[n-1]stones[n-2]-1

而我们之后的每次移动都可以使移动距离为1,从而获得最大的移动次数,移动的次数取决于第一次移动后新端点之间的空位,即

s[n1]s[1]1(n3)=s[n1]s[1]n+2

s[n2]s[0]1(n3)=s[n2]s[0]n+2

因此,最大移动次数为

max(s[n1]s[1]n+2,s[n2]s[0]n+2)

如何获得最小移动次数?

由于所有端点可以移动至可以中间任意的空位,那么我们应该尽可能将石子移动至最合适的问题。

那么我们可以枚举长度为n的滑动窗口,计算其中没有石子的位置的个数,取最小值返回。

但此时存在特殊情况,即移动后石子仍为端点的情况image.png

于是,我们需要判断,s[0]至s[n2]和s[1]s[n1]之间是否有空位,如果没有空位,那么答案为2;还需比较与最大移动次数的关系,如果最小移动次数应小于最大移动次数

  • 滑动窗口
  • 实现
class Solution {
    public int[] numMovesStonesII(int[] s) {
        Arrays.sort(s);
        int n = s.length;
        int e1 = s[n - 2] - s[0] - n + 2;
        int e2 = s[n - 1] - s[1] - n + 2; // 计算空位
        int maxMove = Math.max(e1, e2);
        if (e1 == 0 || e2 == 0) // 特殊情况:没有空位
            return new int[]{Math.min(2, maxMove), maxMove};
        int maxCnt = 0, left = 0;
        for (int right = 0; right < n; ++right) { // 滑动窗口:枚举右端点所在石子
            while (s[right] - s[left] + 1 > n) // 窗口长度大于 n
                ++left; // 缩小窗口长度
            maxCnt = Math.max(maxCnt, right - left + 1); // 维护窗口内的最大石子数
        }
        return new int[]{n - maxCnt, maxMove};
    }
}
作者:灵茶山艾府
链接:https://leetcode.cn/problems/moving-stones-until-consecutive-ii/solutions/2212638/tu-jie-xia-tiao-qi-pythonjavacgo-by-endl-r1eb/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度

  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(1)
目录
相关文章
|
6月前
【每日一题Day149】LC2389和有限的最长子序列 | 贪心+前缀和+二分查找
【每日一题Day149】LC2389和有限的最长子序列 | 贪心+前缀和+二分查找
43 0
|
6月前
【每日一题Day302】LC849到最近的人的最大距离 | 贪心+分类讨论
【每日一题Day302】LC849到最近的人的最大距离 | 贪心+分类讨论
53 0
|
6月前
【每日一题Day175】LC1147段式回文 | 贪心 +双指针
【每日一题Day175】LC1147段式回文 | 贪心 +双指针
45 0
|
5月前
|
存储
【洛谷 P1255】数楼梯 题解(递归+记忆化搜索+高精度)
这是一个使用动态规划解决的“数楼梯”问题。给定楼梯数`N`,求不同上楼方式的数量。程序通过递归函数`f()`计算,其中`f(x) = f(x - 1) + f(x - 2)`,初始条件`f(1) = 1`,`f(2) = 2`。考虑到数据规模可能很大,使用了高精度加法运算。样例输入`4`,输出`5`。代码中定义了一个存储中间结果的向量`mem`,并提供了一个用于显示高精度数的`printv()`函数。
85 0
|
5月前
|
算法
力扣每日一题 6/16 字符串 + 随机一题 动态规划/数学
力扣每日一题 6/16 字符串 + 随机一题 动态规划/数学
44 0
|
6月前
【每日一题Day192】LC1033移动石子直到连续 | 分类讨论 贪心
【每日一题Day192】LC1033移动石子直到连续 | 分类讨论 贪心
31 0
|
6月前
【每日一题Day261】LC16最接近的三数之和 | 双指针
【每日一题Day261】LC16最接近的三数之和 | 双指针
37 0
|
6月前
【每日一题Day122】LC1237找出给定方程的正整数解 | 双指针 二分查找
【每日一题Day122】LC1237找出给定方程的正整数解 | 双指针 二分查找
40 0
|
6月前
【每日一题Day265】LC979在二叉树中分配硬币 | 树形dp
【每日一题Day265】LC979在二叉树中分配硬币 | 树形dp
55 0
|
算法 C++
剑指offer(C++)-JZ11:旋转数组的最小数字(算法-搜索算法)
剑指offer(C++)-JZ11:旋转数组的最小数字(算法-搜索算法)