LeetCode刷题——思维题汇总

318 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情

数学

969. 煎饼排序

题目 给你一个整数数组 arr ,请使用 煎饼翻转 完成对数组的排序。

一次煎饼翻转的执行过程如下:

选择一个整数 k ,1 <= k <= arr.length 反转子数组 arr[0...k-1](下标从 0 开始) 例如,arr = [3,2,1,4] ,选择 k = 3 进行一次煎饼翻转,反转子数组 [3,2,1] ,得到 arr = [1,2,3,4] 。

以数组形式返回能使 arr 有序的煎饼翻转操作所对应的 k 值序列。任何将数组排序且翻转次数在 10 * arr.length 范围内的有效答案都将被判断为正确。

示例 1:

输入:[3,2,4,1] 输出:[4,2,4,3] 解释: 我们执行 4 次煎饼翻转,k 值分别为 4,2,4,和 3。 初始状态 arr = [3, 2, 4, 1] 第一次翻转后(k = 4):arr = [1, 4, 2, 3] 第二次翻转后(k = 2):arr = [4, 1, 2, 3] 第三次翻转后(k = 4):arr = [3, 2, 1, 4] 第四次翻转后(k = 3):arr = [1, 2, 3, 4],此时已完成排序。

示例 2:

输入:[1,2,3] 输出:[] 解释: 输入已经排序,因此不需要翻转任何内容。 请注意,其他可能的答案,如 [3,3] ,也将被判断为正确。

提示:

1 <= arr.length <= 100 1 <= arr[i] <= arr.length arr 中的所有整数互不相同(即,arr 是从 1 到 arr.length 整数的一个排列)

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/pa…

分析 煎饼排序问题找到最短解法是 NP 困难的,而且题目中要求我们找到有效答案即可。所以我们只要找到一个可行的方案即可。这里我们先查找最大的元素,以他基准反转,这样最大元素就已经放到了首位,然后以最后一位为基准反转,最大元素就到了最后一位,然后我们去掉最后一位,对最后一位之前的位数继续重复操作即可。我们以示例1中[3,2,4,1]为例,列表说明。

基准交换后数组最后一位
3[4,2,3,1]4
4[1,3,2,4]4
2[3,1,2,4]3
3[2,1,3,4]3
1[2,1,3,4]2
2[1,2,3,4]2

代码

class Solution {
public:
    vector<int> pancakeSort(vector<int>& arr) {
        vector<int> ans;
        for(int n=arr.size(); n > 1; n--){
            int idx = max_element(arr.begin(), arr.begin()+n) - arr.begin();
            if(idx == n - 1){
                continue;
            }
            reverse(arr.begin(), arr.begin()+idx+1);
            reverse(arr.begin(), arr.begin()+n);
            ans.push_back(idx+1);
            ans.push_back(n);
        }
        return ans;
    }
};

脑筋急转弯

1332. 删除回文子序列

题目 给你一个字符串 s,它仅由字母 'a' 和 'b' 组成。每一次删除操作都可以从 s 中删除一个回文 子序列。

返回删除给定字符串中所有字符(字符串为空)的最小删除次数。

「子序列」定义:如果一个字符串可以通过删除原字符串某些字符而不改变原字符顺序得到,那么这个字符串就是原字符串的一个子序列。

「回文」定义:如果一个字符串向后和向前读是一致的,那么这个字符串就是一个回文。

分析 由于只存在a和b两种字符,所以最多在第二次一定可以把字符全部删完,在字符串回文时删一次即可,不是回文时需要删两次。 代码 示例 1:

输入:s = "ababa"
输出:1
解释:字符串本身就是回文序列,只需要删除一次。

示例 2:

输入:s = "abb"
输出:2
解释:"abb" -> "bb" -> "". 
先删除回文子序列 "a",然后再删除 "bb"

示例 3:

输入:s = "baabb"
输出:2
解释:"baabb" -> "b" -> "". 
先删除回文子序列 "baab",然后再删除 "b"

提示:

1 <= s.length <= 1000 s 仅包含字母 'a' 和 'b'

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/remove-palindromic-subsequences

博弈论

2029. 石子游戏 IX

题目 Alice 和 Bob 再次设计了一款新的石子游戏。现有一行 n 个石子,每个石子都有一个关联的数字表示它的价值。给你一个整数数组 stones ,其中 stones[i] 是第 i 个石子的价值。

Alice 和 Bob 轮流进行自己的回合,Alice 先手。每一回合,玩家需要从 stones 中移除任一石子。

如果玩家移除石子后,导致 所有已移除石子 的价值 总和 可以被 3 整除,那么该玩家就 输掉游戏 。 如果不满足上一条,且移除后没有任何剩余的石子,那么 Bob 将会直接获胜(即便是在 Alice 的回合)。 假设两位玩家均采用 最佳 决策。如果 Alice 获胜,返回 true ;如果 Bob 获胜,返回 false 。

示例 1:

输入:stones = [2,1] 输出:true 解释:游戏进行如下:

  • 回合 1:Alice 可以移除任意一个石子。
  • 回合 2:Bob 移除剩下的石子。 已移除的石子的值总和为 1 + 2 = 3 且可以被 3 整除。因此,Bob 输,Alice 获胜。 示例 2:

输入:stones = [2] 输出:false 解释:Alice 会移除唯一一个石子,已移除石子的值总和为 2 。 由于所有石子都已移除,且值总和无法被 3 整除,Bob 获胜。 示例 3:

输入:stones = [5,1,2,4,3] 输出:false 解释:Bob 总会获胜。其中一种可能的游戏进行方式如下:

  • 回合 1:Alice 可以移除值为 1 的第 2 个石子。已移除石子值总和为 1 。
  • 回合 2:Bob 可以移除值为 3 的第 5 个石子。已移除石子值总和为 = 1 + 3 = 4 。
  • 回合 3:Alices 可以移除值为 4 的第 4 个石子。已移除石子值总和为 = 1 + 3 + 4 = 8 。
  • 回合 4:Bob 可以移除值为 2 的第 3 个石子。已移除石子值总和为 = 1 + 3 + 4 + 2 = 10.
  • 回合 5:Alice 可以移除值为 5 的第 1 个石子。已移除石子值总和为 = 1 + 3 + 4 + 2 + 5 = 15. Alice 输掉游戏,因为已移除石子值总和(15)可以被 3 整除,Bob 获胜。

提示:

1 <= stones.length <= 105 1 <= stones[i] <= 104

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/st…

分析 这里将石子代表的数字转换为余数,即0、1、2,将Alice 和 Bob 设为A和B进行讨论

那么取石头的过程的两种情况是

先取1:

已取出的石子总和的3的余数121212...
取出石子的过程112121...
先取2:
已取出的石子总和的3的余数212121...
----------
取出石子的过程221212...
可以发现无论那种情况都要先去取两次一样的石子,不考虑0的情况A赢的情况如下:
1、当1的个数为1时,2的个数大于0时A赢
2、当1的个数为2时,2的个数大于0时A赢
3、当1的个数大于等于2并且个数不大于2的个数,A赢
4、当2的个数为1时,1的个数大于0时A赢
5、当2的个数为2时,1的个数大于0时A赢
6、当2的个数大于等于2并且个数不大于1的个数,A赢
从中可以看出

A赢得条件为1的个数大于0,2的个数大于0

当0的个数为偶数,不造成影响 当0的个数为奇数相当于互换先后手,这时A赢的情况按照前面的考虑方式就会很麻烦,所以我们从表格入手,如果按照最佳的选择,那么一定是按照表格的循环进行的,因为我们要得到A赢的结果,所以我们要在循环结束之前让B取不到应取的数,再考虑0的个数是奇数,所以我们即从表中找到使得A取不到应取的数的情况即可

1、1的个数比2的个数多至少2个 2、2的个数比1的个数多至少2个 代码

class Solution {
public:
    bool stoneGameIX(vector<int>& stones) {
        int cnt[3]={0,0,0};
        for(int i=0; i < stones.size(); i++){
            cnt[stones[i]%3]++;
        }
        if(cnt[0] % 2 == 0){
            return cnt[1] >= 1 && cnt[2] >=1;
        }else{
            return cnt[1] - cnt[2] > 2 || cnt[2] - cnt[1] > 2;
        }
    }
};