算法每日一题: 石子游戏 | 一维数组合体为二维简化写法 | 倒序排序写法 | 多层嵌套时,三目运算符的写法 | 两个数组轮流取数组实现 | 一维数组合体为二维简化写法

hello,大家好,我是星恒
今天的题目只能说太太太太太可恶了,看似较为简单一道题目,门门道道非常多,具体我们分析的时候道来
这道题的知识点:两个数组轮流取数组实现,一维数组合体为二维简化写法,倒序排序写法,多层嵌套时,三目运算符的写法

题目:leetcode 1686
Alice 和 Bob 轮流玩一个游戏,Alice 先手。
一堆石子里总共有 n 个石子,轮到某个玩家时,他可以 移出 一个石子并得到这个石子的价值。Alice 和 Bob 对石子价值有 不一样的的评判标准 。双方都知道对方的评判标准。
给你两个长度为 n 的整数数组 aliceValues 和 bobValues 。aliceValues[i] 和 bobValues[i] 分别表示 Alice 和 Bob 认为第 i 个石子的价值。
所有石子都被取完后,得分较高的人为胜者。如果两个玩家得分相同,那么为平局。两位玩家都会采用 最优策略 进行游戏。
请你推断游戏的结果c,用如下的方式表示:

  • 如果 Alice 赢,返回 1 。
  • 如果 Bob 赢,返回 -1 。
  • 如果游戏平局,返回 0 。
    示例:
    示例 1:
输入:aliceValues = [1,3], bobValues = [2,1]
输出:1
解释:
如果 Alice 拿石子 1 (下标从 0开始),那么 Alice 可以得到 3 分。
Bob 只能选择石子 0 ,得到 2 分。
Alice 获胜。

示例 2:

输入:aliceValues = [1,2], bobValues = [3,1]
输出:0
解释:
Alice 拿石子 0 , Bob 拿石子 1 ,他们得分都为 1 分。
打平。

示例 3:

输入:aliceValues = [2,4,3], bobValues = [1,6,7]
输出:-1
解释:
不管 Alice 怎么操作,Bob 都可以得到比 Alice 更高的得分。
比方说,Alice 拿石子 1 ,Bob 拿石子 2 , Alice 拿石子 0 ,Alice 会得到 6 分而 Bob 得分为 7 分。
Bob 会获胜。

提示:

  • n == aliceValues.length == bobValues.length
  • 1 <= n <= 105
  • 1 <= aliceValues[i], bobValues[i] <= 100


分析:
这道题目主要是理解题目,因为他这道题其实很有歧义,例如:第一,毕竟是比赛,凭什么Alice是先手,而且他题目也没说Alice是先手。第二,他说的最优策略,如果第一次做这种题目的同学,肯定不知道最优了个啥,需要仔细的分辨示例才能得出(这里不是说求最优规则,而是说Alice和Bob都会选最优与他们的策略,他们似乎有上帝视角一般)第三,不一样的的评判标准这个规则也比较怪,需要仔细理解

所以这道题目,意思是有两个人依次拿一个石子,这个石子有两种价值,一种是Alice价值,一种是Bob价值,每次拿,他们都能拿到有利于他们自己的胜利的棋子(哈,只能说他们很聪明)。

所以,他们如何拿能更有利于结果呢?首先,他们自己的价值要在评判范围内,其次,想要最大话价值,还要降低Bob的价值。说到这里,其实答案呼之欲出,他们只要选择同一块石头,两个人价值和最大的石子,就是最有利于最后胜利的解法,我们只要贪心的找和最大的值就可以了!

题解:

class Solution {
    public int stoneGameVI(int[] aliceValues, int[] bobValues) {
        int n = aliceValues.length;
        int[][] values = new int[n][3];
        for (int i = 0; i < n; i++) {
            values[i][0] = aliceValues[i] + bobValues[i];
            values[i][1] = aliceValues[i];
            values[i][2] = bobValues[i];
        }
        Arrays.sort(values, (a, b) -> b[0] - a[0]);
        int aliceSum = 0, bobSum = 0;
        for (int i = 0; i < n; i++) {
            if (i % 2 == 0) {
                aliceSum += values[i][1];
            } else {
                bobSum += values[i][2];
            }
        }
        return aliceSum > bobSum ? 1 : aliceSum == bobSum ? 0 : -1;
    }
}

注意:

  1. 两个数组轮流取数组模拟两人取石子

使用i % 2 == 0就可以很好的实现

  1. 一维数组合体为二维简化写法
int[][] values = new int[n][3];
for (int i = 0; i < n; i++) {
    values[i][0] = aliceValues[i] + bobValues[i];
    values[i][1] = aliceValues[i];
    values[i][2] = bobValues[i];
}

这个数据结构设计的就很妙,他很大的简化了我们的写法,是真的优雅

  1. 倒序排序写法
    • Arrays.sort(数组名,起始下标,终止下标)
规则:起始下标 <= 数组 < 终止下标

例如:Arrays.sort(a,14)
排序:将下标 1, 2, 3 的数字排序

注意:
    1. 数字代表着下标
    2. 边界左闭右开
  • Arrays.sort(数组名,起始下标,终止下标,排序规则)
源码:
    public static <T> void sort(T[] a,int fromIndex, int toIndex,  Comparator<? super T> c)

Comparator - 排序规则:默认为从小到大,如果想要倒序,需要传入Comparator参数,来改变排序规则


例如:将二维数组按照第一个元素倒序排列
int[][] values = new int[n][3];
for (int i = 0; i < n; i++) {
    values[i][0] = aliceValues[i] + bobValues[i];
    values[i][1] = aliceValues[i];
    values[i][2] = bobValues[i];
}
Arrays.sort(values, (a, b) -> b[0] - a[0]);

可以看到,实现倒序的方法:
    1. 使用Lambda表达式,实现Comparator函数式接口
    2. 使用第二个参数值 - 第一个参数值

神奇的:
    1. 返回的值类型,是第一个参数values一个二维数组
    2. 而排序规则,是Lambda表达式中的参数来排序
  1. 多层嵌套时,三目运算符的写法

三目运算符:(expression) ? if-true-statement : if-false-statement

三目运算符的语法规则是:先对逻辑表达式expression求值,如果expression返回true,则返回第二个操作数的值,否则返回第三个操作数的值。

示例:

if (aliceSum > bobSum) {
    return 1;
} else if (aliceSum == bobSum) {
    return 0;
} else {
    return -1;
}

->

return aliceSum > bobSum ? 1 : aliceSum == bobSum ? 0 : -1;

如果大家有什么思考和问题,可以在评论区讨论,也可以私信我,很乐意为大家效劳。
好啦,今天的每日一题到这里就结束了,如果大家觉得有用,可以可以给我一个小小的赞呢,我们下期再见!

你可能感兴趣的:(算法每日一题,算法)