玩筹码

标签: 贪心 数组 数学

难度: Easy

有 n 个筹码。第 i 个筹码的位置是 position[i] 。

我们需要把所有筹码移到同一个位置。在一步中,我们可以将第 i 个筹码的位置从 position[i] 改变为:

  • position[i] + 2 或 position[i] - 2 ,此时 cost = 0
  • position[i] + 1 或 position[i] - 1 ,此时 cost = 1

返回将所有筹码移动到同一位置上所需要的 最小代价

示例 1:

输入:position = [1,2,3]
输出:1
解释:第一步:将位置3的筹码移动到位置1,成本为0。
第二步:将位置2的筹码移动到位置1,成本= 1。
总成本是1。

示例 2:

输入:position = [2,2,2,3,3]
输出:2
解释:我们可以把位置3的两个筹码移到位置2。每一步的成本为1。总成本= 2。

示例 3:

输入:position = [1,1000000000]
输出:1

提示:

  • 1 <= position.length <= 100
  • 1 <= position[i] <= 10^9

Submission

运行时间: 23 ms

内存: 16.1 MB

class Solution:
    def minCostToMoveChips(self, position: List[int]) -> int:
        cnt=Counter(i%2 for i in position)
        return min(cnt[0],cnt[1])

Explain

该题解采用的是观察所有筹码位置的奇偶性。因为筹码位置的改变只有两种情况:移动2个单位(无成本)和移动1个单位(成本为1)。移动2个单位不改变筹码的奇偶性,因此我们只需关注将筹码移动到奇数位置或偶数位置的最小成本。通过统计所有奇数位置和偶数位置的筹码数量,我们可以确定哪种筹码更多。最终,将较少的一种筹码(无论是奇数还是偶数)移动到另一种位置将产生的成本就是答案,因为每次移动成本为1。

时间复杂度: O(n)

空间复杂度: O(1)

class Solution:
    def minCostToMoveChips(self, position: List[int]) -> int:
        # 使用计数器统计奇数和偶数位置的筹码数量
        cnt = Counter(i % 2 for i in position)
        # 返回将筹码移动到较少一侧的最小成本
        return min(cnt[0], cnt[1])

Explore

在问题中,筹码位置的移动规则是移动2个单位没有成本,移动1个单位有成本。由于移动2个单位不改变筹码的奇偶性(奇数位置移动2个单位仍然是奇数,偶数同理),这意味着奇数位置的筹码可以无成本地集中到任何其他奇数位置,偶数位置亦然。因此,算法中只需关注筹码在奇数位置和偶数位置的分布。这种分类有效的原因是它允许我们通过统计奇数和偶数的筹码数量来确定哪种筹码较少,从而只需最小化的成本将少数的筹码移动到多数的筹码所在位置,每移动一次成本为1。

这是根据题目规定的移动成本设定的。题目规定移动筹码2个单位的位置不需要任何成本,而移动1个单位需要成本1。这意味着任何筹码在数轴上的位置移动到相邻位置(如从位置3到位置4,或从位置2到位置1)需要支付成本,而移动到第二个相邻位置(如从位置3到位置5,或从位置2到位置4)则不需支付成本。由于奇数和偶数位置是交替的,从任一奇数位置到任一偶数位置或反之都需要经过一个单位的移动,因此成本为1。

`Counter(i % 2 for i in position)`是用来计算筹码在奇数位置和偶数位置的数量。这里的`i % 2`计算的是i除以2的余数,它用来判断每个位置是奇数还是偶数。如果余数为0(`i % 2 == 0`),则位置i是偶数位置;如果余数为1(`i % 2 == 1`),则位置i是奇数位置。使用这个方法,我们可以快速地分类统计所有的奇数位置和偶数位置的筹码数量,以便后续决定最小化移动成本的策略。

是的,算法输出仍然是正确的。如果所有筹码已经位于同一位置,无论这个位置是奇数还是偶数,该位置的筹码数量将成为数组中的唯一值。例如,如果所有筹码都在位置3(奇数),则奇数位置的计数为筹码总数,而偶数位置的计数为0。根据算法,我们会选择将较小数量的偶数位置筹码(在这个例子中为0)移动到奇数位置,因此计算的最小成本为0,这是正确的结果,因为不需要任何移动。