力扣1217. 玩筹码
题意
有 n 个筹码。第 i 个筹码的位置是 position[i] 。
我们需要把所有筹码移到同一个位置。在一步中,我们可以将第 i 个筹码的位置从 position[i] 改变为:
position[i] + 2 或 position[i] - 2 ,此时 cost = 0 position[i] + 1 或 position[i] - 1 ,此时 cost = 1 返回将所有筹码移动到同一位置上所需要的 最小代价 。
因为题意很多人刚看会不太理解:
难点在于理解题目意思。chips = [1, 2, 2, 2, 3, 15, 23] 意味着位置1有1个筹码,位置2有3个筹码,同样位置3、15、23各有1个筹码。把所有筹码移动到一个位置,移动两步代价为0,那其实我就可以把所有“奇数位置”筹码移动到一个点A(奇数位置),且不必花费任何代价;同理,所有“偶数位置”的筹码移动到点B(偶数位置)也不需要任何代价。最终就是看A,B两点谁的筹码数多,把少的筹码移动到多的筹码的位置,每一个筹码的代价都是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
Note:1 <= chips.length <= 100,1 <= chips[i] <= 10^9
题型:贪心,数组,数学
提示:
- The first move keeps the parity of the element as it is.
- The second move changes the parity of the element.
- Since the first move is free, if all the numbers have the same parity, the answer would be zero.
- Find the minimum cost to make all the numbers have the same parity.
AC代码
👀Java版本: 方法一:Map记录相关信息
class Solution {
public int minCostToMoveChips(int[] position) {
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i:position){
map.put(i,map.getOrDefault(i,0)+1);
}
int min1 = Integer.MAX_VALUE;
int sum;
for(int key:map.keySet()){
sum=0;
for(int t:map.keySet()){
if(Math.abs(t-key)%2==1){
sum+=map.get(t);
}
}
min1 = Math.min(min1,sum);
}
return min1;
}
}
方法二:奇偶数位置上的数比较,因为奇数和偶数分别相互之间移动耗费为0
public int minCostToMoveChips(int[] chips) {
int odd = 0, even = 0;
for (int i = 0; i < chips.length; i++) {
if (chips[i] % 2 == 0) {
even++;
} else if (chips[i] % 2 != 0) {
odd++;
}
}
return Math.min(even, odd);
}
分析
为什么这么做是因为移动偶数个的位置使用耗费为0,所以任意偶数位置移动到任意奇数位置除了每次移动2个位置的消耗为0,再需要移动一个位置即可到达对应的位置。同理,任意奇数移动到任意偶数位置的耗费要么是0,要么是1.
方法一解法分析
这个方法使用的是map记录每个位置上的数量,然后再分别对每个位置进行作为目标位置,让其他位置上的节点移动到该位置,所以用了两层for循环,也就是这两层for循环,做了和你多不必要的运算,导致时间的小号很大的浪费。
方法二解法分析
因为移动2个位置不需要代价,那么奇数位置移到奇数位置不用代价,偶数位置移到偶数位置不用代价,那就分别统计奇数位置和偶数位置的个数,相当于把所有奇数放一起,所有偶数的放一起,然后比较奇数的少还是偶数的少,将少的个数移到多的个数位置上去就可以了。
题解过程分析
方法一
Map<Integer,Integer> map:代表用于记录存在数的每个位置,和该位置上对应的个数。 两层for循环用于遍历每一个存在节点的位置,内层循环用于对外层循环的每一个位置作为目标节点,然后再遍历一遍for循环记录到目标节点的位置,并在每次进行内层循环之后和min1进行比较最小值,用于记录整个数组中的最小值
方法二
使用old记录偶数位置的个数,使用even记录奇数的个数,然后遍历统计两者的个数即可,遍历完成之后返回old和even中最小的个数,相比于方法一,这个方法只需要一次for循环即可,而且只需要两个变量记录,大大减少了运行的时间和空间占用。
时间复杂度
方法一
-
时间复杂度:O(n^2),其中 n 为数组 position 的长度,只对数组进行了一次遍历。
-
空间复杂度:O(2*n),分别记录对应的位置和对应位置上的数量。
方法二
-
时间复杂度:O(n),其中 n 为数组 position 的长度,只对数组进行了一次遍历。
-
空间复杂度:O(1),仅使用常数变量。
总结
一般这种常常根据题意去具体分析该使用什么方法,如果思路敏捷的话,能想到方法二,一下子逼格就上来了是吧。
- 方法一:使用Map时间复杂度和空间复杂度太高
- 方法二:使用两个变量分别记录奇数位置上和偶数位置上分别总数量,大大降低了时间和空间复杂度
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿