zoukankan      html  css  js  c++  java
  • [LeetCode] 1217. Minimum Cost to Move Chips to The Same Position 玩筹码


    We have n chips, where the position of the ith chip is position[i].

    We need to move all the chips to the same position. In one step, we can change the position of the ith chip from position[i] to:

    • position[i] + 2 or position[i] - 2 with cost = 0.
    • position[i] + 1 or position[i] - 1 with cost = 1.

    Return the minimum cost needed to move all the chips to the same position.

    Example 1:

    Input: position = [1,2,3]
    Output: 1
    Explanation: First step: Move the chip at position 3 to position 1 with cost = 0.
    Second step: Move the chip at position 2 to position 1 with cost = 1.
    Total cost is 1.
    

    Example 2:

    Input: position = [2,2,2,3,3]
    Output: 2
    Explanation: We can move the two chips at position  3 to position 2. Each move has cost = 1. The total cost = 2.
    

    Example 3:

    Input: position = [1,1000000000]
    Output: 1
    

    Constraints:

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

    这道题说是有一堆筹码,第i个筹码所在的位置是 position[i],现在需要将所有的筹码移动到一摞,规则是:左右移动两个位置没有 cost,左右移动一个位置需要花费1个 cost,问移动到同一摞需要的最少花费是多少。博主最先做的时候,一看既然是 Easy 题目,就别多想了,直接上暴力破解呗,找到 position 数组中的最大最小值,然后遍历每一个位置,都统计所有筹码移动到这个位置上的总花费,然后返回一个最小值,结果被 OJ 打脸,超时了 Time Limit Exceeded。直接过不去的就是题目中的例子3,这种方法要把范围中的十亿个位置都遍历一遍,能不超时么。所以博主想了下,最终合成一摞的位置肯定是在某一个已经存在的筹码的位置。

    严谨的证明博主也不会,这里就大概说一下博主能想到的原因,若最终位置不在某个已经存在的筹码的位置,那么看该位置距离任意一个筹码的距离是否有偶数距离,有的话最终位置其实可以移动到那个筹码的位置,因为偶数距离之间的移动没有花费。若最终位置距离所有筹码的位置均为奇数(则所有筹码之间的距离均为偶数),那么该位置根本不应该成为最终位置,因为奇数距离都是有花费的。综上所述,最终结果位置必定在某一个已经存在的筹码的位置,那么这里其实就可以遍历所有给定筹码的位置,然后统计每个位置的花费。但其实这里还可以进一步优化,若有很多筹码都在同一个位置,那么显然按筹码遍历就不是很高效了,因为同一摞的筹码可以一起移动,则花费可以一起计算。这里用一个 HashMap 统计每个位置上的筹码个数,这样就可以把相同位置上的筹码摞到一起了。然后就可以遍历每一个位置了,对于遍历到的位置,再遍历其他所有的位置,统计花费,这样只要找到距离目标奇数位置,就可以把整个一摞的花费一起加上了。最后每次更新结果 res 即可,参见代码如下:


    解法一:

    class Solution {
    public:
        int minCostToMoveChips(vector<int>& position) {
            int res = INT_MAX;
            unordered_map<int, int> posCnt;
            for (int pos : position) ++posCnt[pos];
            for (auto &a : posCnt) {
                int sum = 0;
                for (auto &b : posCnt) {
                    if ((b.first - a.first) % 2 == 0) continue; 
                    sum += b.second;
                }
                res = min(res, sum);
            }
            return res;
        }
    };
    

    其实这道题还有更加简洁高效的解法,因为距离为偶数的筹码可以事先移动到一摞,而所有奇数位置的筹码互相之间都是相距偶数的距离,所有偶数位置的筹码互相之间也都是相距偶数的距离。这样所有筹码就可以在花费为0的情况下归为相邻的两大摞,则总花费其实就是个数较小的那一摞,参见代码如下:


    解法二:

    class Solution {
    public:
        int minCostToMoveChips(vector<int>& position) {
            int even = 0, odd = 0;
            for (int pos : position) {
                (pos % 2 == 1) ? ++odd : ++even;
            }
            return min(odd, even);
        }
    };
    

    Github 同步地址:

    https://github.com/grandyang/leetcode/issues/1217


    类似题目:

    Minimum Number of Operations to Move All Balls to Each Box


    参考资料:

    https://leetcode.com/problems/minimum-cost-to-move-chips-to-the-same-position/

    https://leetcode.com/problems/minimum-cost-to-move-chips-to-the-same-position/discuss/398239/C%2B%2B-3-lines

    https://leetcode.com/problems/minimum-cost-to-move-chips-to-the-same-position/discuss/398178/Detailed-Explanation-O(n)-or-O(1)-Everything-is-in-0-or-1


    LeetCode All in One 题目讲解汇总(持续更新中...)


    喜欢请点赞,疼爱请打赏❤️~.~


    微信打赏


    Venmo 打赏

  • 相关阅读:
    【linux基础】linux系统日志设置相关记录
    【linux基础】mount: unknown filesystem type 'exfat'
    [c++]float assign
    第6章 移动语义和enable_if:6.1 完美转发
    第5章 技巧性基础:5.7 模板模板参数
    第5章 技巧性基础:5.6 变量模板
    第5章 技巧性基础:5.4 原生数组和字符串字面量的模板
    第5章 技巧性基础:5.3 this->的使用
    第5章 技巧性基础:5.2 零初始化
    第5章 技巧性基础:5.1 关键字typename
  • 原文地址:https://www.cnblogs.com/grandyang/p/15228529.html
Copyright © 2011-2022 走看看