[解题报告] 《算法零基础100讲》(第31讲) 多维枚举(一)


前言

跟着英雄哥打卡第三十一天
[专题跳转->《算法零基础100讲》]
[万人千题社区跳转]


一、判断子序列

跳转力扣:392. 判断子序列

难度:★☆☆☆☆

说明:双指针解决, s s s 表示短字符串, t t t 表示长字符串, i i i 记录短字符串的下标, j j j 记录长字符串下标,循环遍历 t t t s [ i ] = = t [ j ] s[i]==t[j] s[i]==t[j]表示搜索到相同字符,此时短字符串向后走一步,当长字符串遍历结束后,指针 i i i 也到了最后则表示 s s s t t t 的子序列

代码如下(示例):

class Solution {
public:
    bool isSubsequence(string s, string t) {
        int n = s.size(), m = t.size();
        int i, j;
        for (i = 0, j = 0; j < m; j ++) {
            if (s[i] == t[j]) i ++;
        }
        return i == n;
    }
};

二、搜索二维矩阵 II

跳转力扣:240. 搜索二维矩阵 II

难度:★☆☆☆☆

说明:优化暴力,由于数组每列向右递增,每行向下递增,以右上角为起点查找 t a r g e t target target ,若大于 t a r g e t target target ,则向左查找,若小于 t a r g e t target target ,则向下查找

代码如下(示例):

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m = matrix.size(), n = matrix[0].size();
        int x = 0, y = n - 1;
        while (x < m && y >= 0) {
            if (matrix[x][y] > target)
                y --;
            else if (matrix[x][y] < target)
                x ++;
            else return true;
        }
        return false;
    }
};

三、差的绝对值为 K 的数对数目

跳转力扣:2006. 差的绝对值为 K 的数对数目

难度:★☆☆☆☆

说明:哈希表,记录数字出现的次数,最后在数据范围内从小到大查找每个数字出现的次数比之大k的值出现的次数的乘积

代码如下(示例):

class Solution {
public:
    int countKDifference(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        int ans = 0;
        for (auto &n: nums)
            hash[n] ++; // 把列表中该数字的次数记录下来
        for (int i = 1; i + k < 105; i ++) {
            ans += hash[i] * hash[i + k]; // 由于给出num[i]的范围:1-100 
                                          // 则枚举数字从1到100数字,
                                          // 哈希值乘积表示各自从中挑出多少个值进行比对
        }
        return ans;
    }
};

四、找不同

跳转力扣:389. 找不同

难度:★☆☆☆☆

说明:哈希表, m s ms ms 表示 s s s 中每个字符出现的次数, m t mt mt 表示 t t t 中每个字符出现的次数,返回元素c,其中c在哈希表 m t mt mt 中比 m s ms ms 大 ,即添加的元素

代码如下(示例):

class Solution {
public:
    char findTheDifference(string s, string t) {
        unordered_map<char, int> ms, mt;
        for (auto &c: s) ms[c] ++;
        for (auto &c: t) {
            mt[c] ++;
            if (mt[c] > ms[c])
                return c;
        }
        return ' ';
    }
};

五、拥有最多糖果的孩子

跳转力扣:1431. 拥有最多糖果的孩子

难度:★☆☆☆☆

说明:贪心,先找到初始糖果数量最多的孩子,然后遍历每个孩子,如果现有全部糖果 e x t r a C a n d i e s extraCandies extraCandies 全部给这个孩子后,都比初始具有糖果数最多的孩子少,则返回false,否则为true

代码如下(示例):

class Solution {
public:
    vector<bool> kidsWithCandies(vector<int>& candies, int extraCandies) {
        int maxn = 0;
        vector<bool> ans;
        for (int i = 0; i < candies.size(); i ++) 
            maxn = max(maxn, candies[i]);
        for (int i = 0; i < candies.size(); i ++) {
            if (candies[i] + extraCandies < maxn)
                ans.push_back(false);
            else ans.push_back(true);
        }
        return ans;
    }
};

六、所有奇数长度子数组的和

跳转力扣:1588. 所有奇数长度子数组的和

难度:★☆☆☆☆

说明:数学,计算在所有满足要求的子数组中每个数字出现的次数,遍历每一个数字,计算该数字左边有多少个数字 l e f t C o u n t leftCount leftCount ,右边有多少个数字 r i g h t C o u n t rightCount rightCount ,再分别计算左右两边连续奇数、偶数子数组的组数,计算可得结果

代码如下(示例):

class Solution {
public:
    int sumOddLengthSubarrays(vector<int>& arr) {
        int sum = 0;
        int n = arr.size();
        for (int i = 0; i < n; i++) {
            int leftCount = i, rightCount = n - i - 1; // 左边元素个数 右边元素个数
            int leftOdd = (leftCount + 1) / 2; // 左边有多少个子数组个数为奇数 
                                               // 如若[1,2,3,4]为左边的元素,则[4]和[2,3,4]满足要求所需,即2个
            int rightOdd = (rightCount + 1) / 2;
            int leftEven = leftCount / 2 + 1; // 左边有多少个子数组个数为偶数 
                                               // 如若[1,2,3,4]为左边的元素,则[3,4]和[1,2,3,4]满足要求所需,即2个
            int rightEven = rightCount / 2 + 1;
            sum += arr[i] * (leftOdd * rightOdd + leftEven * rightEven);
        }
        return sum;
    }
};

七、统计好三元组

跳转力扣:1534. 统计好三元组

难度:★☆☆☆☆

说明:暴力查找,若第一个数和第二个数不满足要求,直接跳过可节省时间

代码如下(示例):

class Solution {
public:
    int countGoodTriplets(vector<int>& arr, int a, int b, int c) {
        int n = arr.size(), ans = 0;
        for (int i = 0; i < n; i ++) {
            for (int j = i + 1; j < n; j ++) {
                if (abs(arr[i] - arr[j]) > a) continue;
                for (int k = j + 1; k < n; k ++) {
                    if (abs(arr[j] - arr[k]) <= b && abs(arr[i] - arr[k]) <= c)
                        ans ++;
                }
            }
        }
        return ans;
    }
};

八、宝石与石头

跳转力扣:771. 宝石与石头

难度:★★☆☆☆

说明:集合,直接把题意翻译成代码,在遍历石头中如果有宝石就 + 1 +1 +1

代码如下(示例):

class Solution {
public:
    int numJewelsInStones(string jewels, string stones) {
        int jewelsCount = 0;
        unordered_set<char> jewelsSet;
        for (auto &jewel: jewels) {
            jewelsSet.insert(jewel);
        }
        for (auto &stone: stones) {
            if (jewelsSet.count(stone)) {
                jewelsCount++;
            }
        }
        return jewelsCount;
    }
};

九、按既定顺序创建目标数组

跳转力扣:1389. 按既定顺序创建目标数组

难度:★★☆☆☆

说明:数组,直接调用数组的方法 i n s e r t ( p o s , n u m ) insert(pos, num) insert(pos,num) 在规定的下标pos插入数值num

代码如下(示例):

class Solution {
public:
    vector<int> createTargetArray(vector<int>& nums, vector<int>& index) {
        vector<int> ans;
        for (int i = 0; i < nums.size(); i ++) {
            ans.insert(ans.begin() + index[i], nums[i]);
        }
        return ans;
    }
};

十、最长公共前缀

跳转力扣:14. 最长公共前缀

难度:★★☆☆☆

说明:哈希表,以第一个字符串 f i r s t first first 作为基底,将每个字符哈希,从第二个字符串开始遍历,计算每个字符串与 f i r s t first first 的前缀相同的最大值,然后在找出所有字符串计算出的最大前缀当中最小一个作为答案

代码如下(示例):

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (strs.size() == 1 ) return strs[0];
        int hash[205], cnt = 0, ans = 205;
        string first = strs[0];
        while (cnt <= first.size()) {
            hash[cnt ++] = first[cnt] - 'a';
        }
        for (int i = 1; i < strs.size(); i ++) {
            int maxn = 0;
            for (int j = 0; j < cnt && j < strs[i].size(); j ++) {
                if (strs[i][j] - 'a' == hash[j])
                    maxn = max(maxn, j + 1);
                else break;
            }
            ans = min(maxn, ans);
        }
        if (ans == 205) return "";
        return first.substr(0, ans);
    }
};

十一、统计平方和三元组的数目

跳转力扣:1925. 统计平方和三元组的数目

难度:★★☆☆☆

说明:暴力枚举,优化了三层循环,枚举了2个数后计算得到满足平方要求的第三个数,若第三个数也在 n n n 以内,则满足所有要求,计数器+1

代码如下(示例):

class Solution {
public:
    int countTriples(int n) {
        int res = 0;
        // 枚举 a 与 b
        for (int a = 1; a <= n; ++a){
            for (int b = 1; b <= n; ++b){
                // 判断是否符合要求
                int c = int(sqrt(a * a + b * b));
                if (c <= n && c * c == a * a + b * b){
                    ++res;
                }
            }
        }
        return res;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
多维动态规划(MDP)是一种在多维状态空间中求解最优策略的算法。下面是解题思路的一般步骤: 1. 定义状态和动作:首先,需要明确问题的状态和可选的动作。将问题抽象成一个多维状态空间,并确定每个状态下可执行的动作。 2. 定义价值函数:为了评估每个状态的优劣,需要定义一个价值函数来衡量状态的价值。价值函数可以是累积奖励、期望回报等。 3. 定义转移函数:转移函数描述了状态之间的转换关系,即在执行某个动作后,当前状态如何转移到下一个状态。转移函数可以是确定性的或概率性的。 4. 构建动态规划表格:根据问题的状态空间和动作空间,构建一个多维表格。每个单元格代表一个状态,并记录该状态下执行不同动作所得到的价值。 5. 递归求解最优策略:从最后一个状态开始,根据动态规划的原理递归地计算每个状态的最优价值,并记录最优动作。通过向前逐步计算,可以得到整个状态空间下的最优策略。 6. 优化算法:对于复杂问题,可以采用一些优化技巧来减少计算量,如值迭代、策略迭代等。 需要注意的是,多维动态规划算法的实现可能会比较复杂,涉及到状态空间的遍历和动作选择等问题。因此,了解问题的特点和算法的原理非常重要。 希望这个解题思路能对你有所帮助!如果还有其他问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值