**今天是小浩算法“365刷题计划”第57天。为大家分享一个脑筋急转弯(???)**类型的算法题。leetcode这个脑筋急转弯的tag打的我措手不及...
01
PART
移动石子
分享这道题目的原因,是因为有很多同学,在拿到题目的一瞬间,如果发现题目很长,然后自己就慌了。其实,对于这种题目,如果认真的分析下去,非常简单。
1033题:三枚石子放置在数轴上,位置分别为 a,b,c。每一回合,我们假设这三枚石子当前分别位于位置 x, y, z 且 x < y < z。从位置 x 或者是位置 z 拿起一枚石子,并将该石子移动到某一整数位置 k 处,其中 x < k < z 且 k != y。当你无法进行任何移动时,即,这些石子的位置连续时,游戏结束。要使游戏结束,你可以执行的最小和最大移动次数分别是多少?以长度为 2 的数组形式返回答案:answer = [minimum_moves, maximum_moves]
输入:a = 1, b = 2, c = 5
输出:[1, 2]
解释:将石子从 5 移动到 4 再移动到 3,或者我们可以直接将石子移动到 3。
示例 2:
输入:a = 4, b = 3, c = 2
输出:[0, 0]
解释:我们无法进行任何移动。
提示:
1 <= a <= 100
1 <= b <= 100
1 <= c <= 100
a != b, b != c, c != a
(瞪一瞪就全部掌握)
02
PART
题目分析
这种题,基本上不慌,就赢了一半。
通过分析题中的样例,就算再笨,画一画应该都能理解题意。
比如:a = 1, b = 2, c = 5
比如:a = 4, b = 3, c = 2
(无法移动)
读懂了题意,开始进行分析。首先可以明确,每一次我们其实是从边上来挑选石子,然后往中间进行移动。所以,我们首先得找到min(左),max(右)以及mid(中)三个值。我们设,min和mid中的距离为x,max和min中的距离为y。大概就是下面这样:
然后只需要计算x和y的和,就是我们要找的最大值。而最小值,就很容易了,只有0,1,2三种可能性。
根据分析,得到代码:(本命...Go)
1//GO
2func numMovesStones(a int, b int, c int) []int {
3 arr := []int{a, b, c}
4 sort.Ints(arr)
5 x := arr[1] - arr[0] - 1
6 y := arr[2] - arr[1] - 1
7 max := x + y
8 min := 0
9 if x != 0 || y != 0 {
10 if x > 1 && y > 1 {
11 min = 2
12 } else {
13 min = 1
14 }
15 }
16 return []int{min, max}
17}
郑重申明(读我的文章必看):
-
本系列所有教程都不会用到复杂的语言特性,不需要担心没有学过相关语法,使用各语言纯属本人爱好。
-
作为学术文章,虽然风格可以风趣,但严谨,我是认真的。本文所有代码均在leetcode上进行过测试运行。
-
算法思想才是最重要的。
03
PART
C++代码
当然,也可以不用排序,把代码写漂亮一点。像是下面这样...
1//C++
2class Solution {
3public:
4 vector<int> numMovesStones(int a, int b, int c) {
5 int max = a > b ? (a > c ? a : c) : (c > b ? c : b);
6 int min = a < b ? (a < c ? a : c) : (b < c ? b : c);
7 int med = a + b + c - max - min;
8 int maxMove = max - min - 2;
9 int minMove = 2;
10 if (max - med == 1 && med - min == 1) {
11 minMove = 0;
12 } else if (max - med == 1 || med - min == 1) {
13 minMove = 1;
14 } else if (max - med == 2 || med - min == 2) {
15 minMove = 1;
16 }
17 return vector{minMove,maxMove};
18 }
19};