动态规划02 自由之路[C++]

这篇具有很好参考价值的文章主要介绍了动态规划02 自由之路[C++]。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  动态规划02 自由之路[C++],# 动态规划,动态规划,算法,c++,笔记

图源:文心一言

leedcode每日一题,提供了常规解法及其详细解释,供小伙伴们参考~🥝🥝

  • 第1版:在力扣新手村刷题的记录~🧩🧩
    • 方法一:递归调用,可以运行,但是不能通过较长的测试用例<失败>~
    • 方法二:动态规划,普遍适用的方法~

编辑:梅头脑🌸

审核:文心一言

题目:514. 自由之路 - 力扣(LeetCode)


目录

🧵514. 自由之路

🧩题目

🌰方法一:哈希表 + 递归调用<超时的失败方案>

🌰方法二:动态规划

🔚结语


🧵514. 自由之路

🧩题目

电子游戏“辐射4”中,任务 “通向自由” 要求玩家到达名为 “Freedom Trail Ring” 的金属表盘,并使用表盘拼写特定关键词才能开门。

给定一个字符串 ring ,表示刻在外环上的编码;给定另一个字符串 key ,表示需要拼写的关键词。您需要算出能够拼写关键词中所有字符的最少步数。

最初,ring 的第一个字符与 12:00 方向对齐。您需要顺时针或逆时针旋转 ring 以使 key 的一个字符在 12:00 方向对齐,然后按下中心按钮,以此逐个拼写完 key 中的所有字符。

旋转 ring 拼出 key 字符 key[i] 的阶段中:

  1. 您可以将 ring 顺时针或逆时针旋转 一个位置 ,计为1步。旋转的最终目的是将字符串 ring 的一个字符与 12:00 方向对齐,并且这个字符必须等于字符 key[i] 。
  2. 如果字符 key[i] 已经对齐到12:00方向,您需要按下中心按钮进行拼写,这也将算作 1 步。按完之后,您可以开始拼写 key 的下一个字符(下一阶段), 直至完成所有拼写。

 示例1:

动态规划02 自由之路[C++],# 动态规划,动态规划,算法,c++,笔记

输入: ring = "godding", key = "gd"
输出: 4
解释:
 对于 key 的第一个字符 'g',已经在正确的位置, 我们只需要1步来拼写这个字符。 
 对于 key 的第二个字符 'd',我们需要逆时针旋转 ring "godding" 2步使它变成 "ddinggo"。
 当然, 我们还需要1步进行拼写。
 因此最终的输出是 4。

示例 2:

输入: ring = "godding", key = "godding"
输出: 13

🌰方法一:哈希表 + 递归调用<超时的失败方案>

📇算法思路

  • 算法思想:
    • 使用哈希表来记录ring中每个字符出现的位置;

    • 对于key中的每个字符,查找它在ring中的所有出现位置,并计算从当前位置顺时针或逆时针旋转到这些位置的最小步数;

    • 累加每个字符的旋转步数和按下按钮的步数(每次按下按钮计为1步);在计算完一个字符后,更新当前位置为下一个字符的起始位置;

    • 最后,返回累加的总步数。

  • 时间复杂度:O(n^m),这是因为对于key中的每个字符,我们可能需要检查ring中的n个位置,而对于key中的下一个字符,我们再次可能需要检查ring中的n个位置,依此类推;
  • 空间复杂度:O(n+m),其中nring的长度,mkey的长度。这是因为除了递归栈之外,我们还需要额外的空间来存储charMap和DFS函数中的局部变量。

⌨️算法代码

#include <iostream>  
#include <string>  
#include <unordered_map>  
#include <vector>  
using namespace std;

class Solution {
public:
    int findRotateSteps(string ring, string key) {
        // 构建字符到索引位置的映射  
        unordered_map<char,vector<int>> charMap;
        for (int i = 0; i < ring.size(); ++i) {
            charMap[ring[i]].push_back(i);
        }

        // 定义一个递归函数来计算步数

        // 参数:当前ring的索引位置,当前需要拼写的key的索引位置,以及已经走过的步数  
        return dfs(charMap, ring.size(), 0, 0, key);
    }

private:
    int dfs(unordered_map<char, vector<int>>& charMap, int ringSize, int ringPos, int keyPos, const string& key) {
        // 递归终止条件:已经拼写完key中的所有字符  
        if (keyPos == key.size()) {
            return 0;
        }

        int minSteps = INT_MAX;
        char currentChar = key[keyPos];

        // 查找当前字符在ring中的所有位置  
        if (charMap.count(currentChar) > 0) {
            for (int nextRingPos : charMap[currentChar]) {
                // 计算从当前位置到下一个位置的顺时针或逆时针最小步数  
                int stepsToRotate = min(abs(nextRingPos - ringPos), ringSize - abs(nextRingPos - ringPos));
                // 递归计算拼写下一个字符所需的总步数,并更新最小步数  
                int totalSteps = stepsToRotate + 1 + dfs(charMap, ringSize, nextRingPos, keyPos + 1, key);
                minSteps = min(minSteps, totalSteps);
            }
        }

        return minSteps;
    }
};

/*  
int main() {  
    Solution solution;  
    string ring = "godding";  
    string key = "godding";  
    cout << "Minimum steps required: " << solution.findRotateSteps(ring, key) << endl;  
    return 0;  
}
*/

作者:文心一言 + 梅头脑

备注:这个思路可以用于较为简单的字符串,官方提供的2个测试用例本地可以通过,但是提交时的隐藏测试用例会因超时被打下来~~

📇代码解释

1:构建哈希表记录字符出现的位置

unordered_map<char, std::vector<int>> charMap;

for (int i = 0; i < ring.size(); ++i) { charMap[ring[i]].push_back(i); }

  • 使用 ring[i] 作为键来访问 charMap 中的元素。如果 charMap 中还没有这个键,那么会创建一个新的键值对,其中键是 ring[i],值是一个空的 vector<int>

  • 调用 push_back(i) 方法将当前索引 i 添加到与 ring[i] 关联的 vector<int> 中。

举个栗子,如果 ring 是字符串 "godding",那么在执行完这段循环代码后,charMap:

动态规划02 自由之路[C++],# 动态规划,动态规划,算法,c++,笔记

2:计算从当前位置到下一个位置的顺时针或逆时针最小步数  

int stepsToRotate = min(abs(nextRingPos - ringPos), ringSize - abs(nextRingPos - ringPos));

  • ringpos为指针当前位置,nextringpos为哈希表记录的位置;
  • min计算最小值,abs为绝对值,即取abs(nextRingPos - ringPos)或ringSize - abs(nextRingPos - ringPos)的最小值,表示计算从当前位置到下一个位置顺时针或逆时针最小步数;

3:累加每个字符的旋转步数和按下按钮的步数,在计算完一个字符后,更新当前位置为下一个字符的起始位置;

int totalSteps = stepsToRotate + 1 + dfs(charMap, ringSize, nextRingPos, keyPos + 1, key);

  • 这一圈的旋转次数stepsToRotate,这一圈的按动次数1;
  • 下一圈的旋转与按动次数,通过递归调用dfs实现,传入的参数:charMap(步骤1的哈希表),ringsize(字符串长度), nextRingPos(更新当前ring字符串的索引位置),keyPos + 1(key的下一个字符),key(题目中给到的key字符串);

动态规划02 自由之路[C++],# 动态规划,动态规划,算法,c++,笔记

4:返回累加的总步数:

return minSteps;  

🌰方法二:动态规划

📇算法思路

  • 算法思想:
    • 记录ring中每个字符出现的位置;

    • 动态规划:定义一个状态数组来存储子问题的解,并通过状态转移方程来计算当前问题的解。在这个问题中,我们可以定义一个二维DP数组,其中 dp[i][j] 表示拼写完 key 的前 i 个字符,并且最后一个字符是通过旋转 ring 使得 ring[j] 对齐到 key[i-1] 的最小步数。

    • 最后,返回累加的总步数。

  • 时间复杂度:O(mn^2),动态规划部分有三层循环:
    • 外层循环遍历键(key)的每个字符,时间复杂度为 O(m),其中 m 是键的长度。
    • 中间循环遍历与当前键字符匹配的环形字符串中的字符索引,这在最坏情况下是 O(n)(假设每个字符在环形字符串中都出现)。
    • 内层循环遍历环形字符串的所有可能起始位置,时间复杂度为 O(n)。
    • 因此,动态规划部分的总时间复杂度为 O(m * n * n)。

  • 空间复杂度:O(mn),其中 m 和 n 分别是key和ring字符串的长度。

⌨️算法代码

#include <iostream>  
#include <string>  
#include <vector>  
#include <climits>  
#include <unordered_map>  
#include <algorithm>

class Solution {
public:
    int findRotateSteps(std::string ring, std::string key) {
        int n = ring.size();
        int m = key.size();

        // 构建字符到索引位置的映射  
        std::unordered_map<char, std::vector<int>> charMap;
        for (int i = 0; i < n; ++i) {
            charMap[ring[i]].push_back(i);
        }

        // 初始化DP数组  
        std::vector<std::vector<int>> dp(m + 1, std::vector<int>(n, INT_MAX));

        // 对于ring中的每个字符,如果它是key的第一个字符,则初始化dp[1][j]  
        for (int j = 0; j < n; ++j) {
            if (ring[j] == key[0]) {
                dp[1][j] = std::min(j, n - j); // 使用std::min  
            }
        }

        // 动态规划计算最小步数  
        for (int i = 2; i <= m; ++i) {
            for (int j : charMap[key[i - 1]]) {
                for (int k = 0; k < n; ++k) {
                    // 如果ring[k]是key的前一个字符  
                    if (dp[i - 1][k] != INT_MAX) {
                        // 计算从位置k旋转到位置j的最小步数  
                        int steps = std::min(abs(j - k), n - abs(j - k)); // 使用std::min  
                        dp[i][j] = std::min(dp[i][j], dp[i - 1][k] + steps); // 使用std::min  
                    }
                }
            }
        }

        // 找到拼写完整个key的最小步数  
        int minSteps = *std::min_element(dp[m].begin(), dp[m].end()); // 使用std::min_element  
        return minSteps + m; // 加上m,因为每次旋转后都需要按下一个字符  
    }
};

/*
int main() {
    Solution solution;
    std::string ring = "godding";
    std::string key = "gd";
    std::cout << "Minimum steps required: " << solution.findRotateSteps(ring, key) << std::endl;

    // 更长的测试用例  
    ring = "caotmcaataijjxi";
    key = "oatjiioicitatajtijciocjcaaxaaatmctxamacaamjjx";
    std::cout << "Minimum steps required for longer test case: " << solution.findRotateSteps(ring, key) << std::endl;

    return 0;
}
*/

作者:文心一言 

📇代码解释

备注:我之前没有接触过动态规划的题目,所以对于这个问题的理解若隐若现。先把文心一言的回答与运行输出贴在下面,另外补充知乎博主的入门讲解——

捡田螺的小男孩🌸捡田螺的小男孩博文:看一遍就理解:动态规划详解 - 知乎 (zhihu.com)

1:构建哈希表记录字符出现的位置(同方法一)

unordered_map<char, std::vector<int>> charMap;

for (int i = 0; i < ring.size(); ++i) { charMap[ring[i]].push_back(i); }
  • 使用 ring[i] 作为键来访问 charMap 中的元素。如果 charMap 中还没有这个键,那么会创建一个新的键值对,其中键是 ring[i],值是一个空的 vector<int>

  • 调用 push_back(i) 方法将当前索引 i 添加到与 ring[i] 关联的 vector<int> 中。

举个栗子,如果 ring 是字符串 "godding",那么在执行完这段循环代码后,charMap:

动态规划02 自由之路[C++],# 动态规划,动态规划,算法,c++,笔记

2:初始化动态数组

std::vector<std::vector<int>> dp(m + 1, std::vector<int>(n, INT_MAX));​​​​​​​ 
  • 这行代码声明了一个二维的 std::vector,名为 dp。具体来说,它是一个向量(vector),其元素也是向量(vector),内部的这些向量又包含了整数(int)。
  • min计算最小值,abs为绝对值,即取abs(nextRingPos - ringPos)或ringSize - abs(nextRingPos - ringPos)的最小值,表示计算从当前位置到下一个位置顺时针或逆时针最小步数;
  • dp(m + 1, std::vector<int>(n, INT_MAX)) 是 dp 的构造函数调用,它做了两件事:

    • 设置 dp 的大小为 m + 1。也就是说,dp 会有 m + 1 个元素,每个元素都是一个 std::vector<int>

    • 初始化这 m + 1 个元素。每个元素(也就是内部的 std::vector<int>)都被初始化为具有 n 个元素,且每个元素的值为 INT_MAXINT_MAX 是在 <climits> 头文件中定义的,表示 int 类型可以存储的最大值。

  • 这种初始化方式常用于动态规划(Dynamic Programming,DP)问题中,因为 DP 通常需要一个二维数组(或在这里是二维向量)来存储子问题的解。将 dp 的所有元素初始化为 INT_MAX 是为了在后续的计算中,可以通过比较和更新这些值来找到最小的解。

for (int j = 0; j < n; ++j) { if (ring[j] == key[0]) { dp[1][j] = std::min(j, n - j); } }
  • ​​​​​​​对于ring(环形字符串)中的每个字符,检查它是否与目标键key的第一个字符匹配。如果匹配,我们需要计算将这个字符旋转到索引0位置(即环形字符串的起始位置)所需的最小步骤数。
  • 旋转到索引0位置可以通过两种方式实现:

    • 顺时针旋转j步,如果j是当前字符的索引。
    • 逆时针旋转n - j步,其中nring的长度。这是因为环形字符串是闭合的,所以从任何位置逆时针旋转n - j步也会将字符带到索引0位置。
  • 在这两种旋转方式中,我们选择步数较少的那一种,因此使用了std::min(j, n - j)来计算所需的最小步骤数,并将这个值存储在dp[1][j]中。这里,dp[1][j]表示在匹配key的第一个字符时,将ring[j]旋转到起始位置所需的最小步骤数。
  • 这样做是为了建立一个基础状态,之后的动态规划过程将基于这些初始状态进行计算。

3:动态规划计算最小步数

        for (int i = 2; i <= m; ++i) {
            for (int j : charMap[key[i - 1]]) {
                for (int k = 0; k < n; ++k) {
                    // 如果ring[k]是key的前一个字符
                    if (dp[i - 1][k] != INT_MAX) {
                        // 计算从位置k旋转到位置j的最小步数
                        int steps = std::min(abs(j - k), n - abs(j - k)); // 使用std::min
                        dp[i][j] = std::min(dp[i][j], dp[i - 1][k] + steps); // 使用std::min
                    }
                }
            }
        }
  1. 外层循环 for (int i = 2; i <= m; ++i) 遍历键(key)的每个字符,从第二个字符开始(因为第一个字符的初始化已经在之前的步骤中完成了)。

  2. 中间循环 for (int j : charMap[key[i - 1]]) 遍历与当前键字符匹配的环形字符串中的所有字符索引。这里使用了 charMap,它是一个哈希表,将环形字符串中的字符映射到它们在字符串中出现的所有索引上。

  3. 内层循环 for (int k = 0; k < n; ++k) 遍历环形字符串的所有可能起始位置。对于每个位置 k,我们检查它是否能够通过旋转环形字符串与上一个键字符匹配。

  4. 在内层循环中,if (dp[i - 1][k] != INT_MAX) 检查上一个键字符匹配时的最小步数是否已经被计算过(即不是初始化的最大值)。如果是这样,我们就继续计算从位置 k 旋转到当前键字符位置 j 所需的最小步数。

  5. 计算旋转步数的逻辑是 int steps = std::min(abs(j - k), n - abs(j - k));,它比较了顺时针和逆时针旋转到目标位置所需的步数,并选择了较小的一个。

  6. 最后,dp[i][j] = std::min(dp[i][j], dp[i - 1][k] + steps); 更新了匹配当前键字符时,将环形字符串旋转到位置 j 所需的最小步数。这里采用了状态转移方程,将当前状态的最小步数与之前状态的最小步数加上旋转步数进行比较,保留了较小的一个。

📇计算过程

以key:godding,ring:godding为例:

初始化后的矩阵:g可以通过顺时针旋转0次或者逆时针旋转1次得到,因此以0作为记录,计算下一列;

ring \ key g o d d i n g
g 0 NAN NAN NAN NAN NAN NAN
o NAN NAN NAN NAN NAN NAN NAN
d NAN NAN NAN NAN NAN NAN NAN
d NAN NAN NAN NAN NAN NAN NAN
i NAN NAN NAN NAN NAN NAN NAN
n NAN NAN NAN NAN NAN NAN NAN
g 1 NAN NAN NAN NAN NAN NAN

DP array after processing key character 'o' (1/6): o可以通过旋转1次得到;

ring \ key g o d d i n g
g 0 NAN NAN NAN NAN NAN NAN
o NAN 1 NAN NAN NAN NAN NAN
d NAN NAN NAN NAN NAN NAN NAN
d NAN NAN NAN NAN NAN NAN NAN
i NAN NAN NAN NAN NAN NAN NAN
n NAN NAN NAN NAN NAN NAN NAN
g 1 NAN NAN NAN NAN NAN NAN

---------------------
DP array after processing key character 'd' (2/6): 
d可以通过顺时针旋转1或2次;

ring \ key g o d d i n g
g 0 NAN NAN NAN NAN NAN NAN
o NAN 1 NAN NAN NAN NAN NAN
d NAN NAN 2 NAN NAN NAN NAN
d NAN NAN 3 NAN NAN NAN NAN
i NAN NAN NAN NAN NAN NAN NAN
n NAN NAN NAN NAN NAN NAN NAN
g 1 NAN NAN NAN NAN NAN NAN

---------------------
DP array after processing key character 'd' (3/6):

ring \ key g o d d i n g
g 0 NAN NAN NAN NAN NAN NAN
o NAN 1 NAN NAN NAN NAN NAN
d NAN NAN 2 2 NAN NAN NAN
d NAN NAN 3 3 NAN NAN NAN
i NAN NAN NAN NAN NAN NAN NAN
n NAN NAN NAN NAN NAN NAN NAN
g 1 NAN NAN NAN NAN NAN NAN

---------------------
DP array after processing key character 'i' (4/6):

ring \ key g o d d i n g
g 0 NAN NAN NAN NAN NAN NAN
o NAN 1 NAN NAN NAN NAN NAN
d NAN NAN 2 2 NAN NAN NAN
d NAN NAN 3 3 NAN NAN NAN
i NAN NAN NAN NAN 4 NAN NAN
n NAN NAN NAN NAN NAN NAN NAN
g 1 NAN NAN NAN NAN NAN NAN

---------------------
DP array after processing key character 'n' (5/6):

ring \ key g o d d i n g
g 0 NAN NAN NAN NAN NAN NAN
o NAN 1 NAN NAN NAN NAN NAN
d NAN NAN 2 2 NAN NAN NAN
d NAN NAN 3 3 NAN NAN NAN
i NAN NAN NAN NAN 4 NAN NAN
n NAN NAN NAN NAN NAN 5 NAN
g 1 NAN NAN NAN NAN NAN NAN

---------------------
DP array after processing key character 'g' (6/6):

ring \ key g o d d i n g
g 0 NAN NAN NAN NAN NAN 7
o NAN 1 NAN NAN NAN NAN NAN
d NAN NAN 2 2 NAN NAN NAN
d NAN NAN 3 3 NAN NAN NAN
i NAN NAN NAN NAN 4 NAN NAN
n NAN NAN NAN NAN NAN 5 NAN
g 1 NAN NAN NAN NAN NAN 6

---------------------
Minimum steps required: 13

根据动态规划矩阵,最后1列的最小值为6,即匹配7轮后,最少需要旋转6次能够完成字符匹配。另外,加上需要按动7次按钮,所以一共需要的最小步数为6+7=13。

以key:gd,ring:godding为例,最后的旋转矩阵:

ring \ key g d
g 0 NAN
o NAN NAN
d NAN 2
d NAN 3
i NAN NAN
n NAN NAN
g 1 NAN

Minimum steps required: 4

根据动态规划矩阵,最后1列的最小值为2,即匹配2轮后,最少需要旋转2次能够完成字符匹配。另外,加上需要按动2次按钮,所以一共需要的最小步数为2+2=4。


🔚结语

博文到此结束,写得模糊或者有误之处,欢迎小伙伴留言讨论与批评,督促博主优化内容{例如有错误、难理解、不简洁、缺功能}等,博主会顶锅前来修改~~😶‍🌫️😶‍🌫️

我是梅头脑,本片博文若有帮助,欢迎小伙伴动动可爱的小手默默给个赞支持一下,感谢点赞小伙伴对于博主的支持~~🌟🌟

同系列的博文1:🌸动态规划_梅头脑_的博客-CSDN博客

同系列的博文2:🌸数据结构_梅头脑_的博客-CSDN博客

同博主的博文:🌸随笔03 笔记整理-CSDN博客文章来源地址https://www.toymoban.com/news/detail-837084.html

到了这里,关于动态规划02 自由之路[C++]的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Day36算法记录|动态规划 dp02

    步骤回顾: C语言版本写的很清楚 对应得Java版本视频解析 方法一: 动态规划 1 确定dp数组(dp table)以及下标的含义 dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。 2 . 确定递推公式 ,求dp[i][j],只能有两个方向来推导出来,即dp[i - 1][j] 和 dp[i][j - 1]。 3. dp数

    2024年02月12日
    浏览(39)
  • 【leetcode刷题之路】剑指Offer(4)——分治+排序算法+动态规划

    8 分治算法 8.1 【递归】剑指 Offer 07 - 重建二叉树 https://leetcode.cn/problems/zhong-jian-er-cha-shu-lcof/   前序遍历是根左右,中序遍历是左根右,这也就意味着前序遍历的第一个节点是整棵树的根节点,顺着这个节点找到它在中序遍历中的位置,即为in_root,那么in_root左边的都在左子

    2024年02月11日
    浏览(43)
  • 【leetcode刷题之路】初级算法(2)——链表+树+排序和搜索+动态规划

    3.1 【链表】删除链表中的节点 https://leetcode.cn/problems/delete-node-in-a-linked-list/ 给出的就是要删除的那个节点,直接前后移动就行了。 3.2 【双指针】删除链表的倒数第 N 个结点 https://leetcode.cn/problems/remove-nth-node-from-end-of-list/ 利用双指针left和right,首先让right遍历n个节点,再让两

    2024年02月10日
    浏览(38)
  • 算法笔记(Java)——动态规划

    动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。 所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的, 动规和递归的区别是动规不是暴力的

    2024年02月08日
    浏览(37)
  • 动态规划(DP)(算法笔记)

    本文内容基于《算法笔记》和官方配套练题网站“晴问算法”,是我作为小白的学习记录,如有错误还请体谅,可以留下您的宝贵意见,不胜感激。 动态规划(Dynamic Programming,DP)是一种用来解决一类最优化问题的算法思想。简单来说,动态规划将一个复杂的问题分解成若干个子

    2024年02月05日
    浏览(38)
  • 算法笔记14.动态规划

    就是切割问题变成一堆小问题,最好子问题之间可以递推,这样就能利用之前的子问题的答案得出新的结果。 可以削减总量,比如求n个数的什么什么,可以削n的大小,n削到n-1……一直到1,1的结果很好求,然后利用1的结果求2,然后再一直求到n。 也可以不削总量削单量,比

    2024年04月15日
    浏览(20)
  • 算法学习笔记(动态规划——01背包)

    先来聊聊动态规划,动态规划是分治法的一种体现,把一个问题分解成若干个子集,通过当前状态,经过操作得到下一个状态,最后得到最优问题解的一种方法。 步骤: 设定状态,保存状态 根据状态设定转移方程 确定边界 其中的01背包解决的是关于选择的动态规划问题,

    2024年03月25日
    浏览(40)
  • 动态规划算法刷题笔记【状压dp】

    a1 == 1 判断是否为奇数,如果为1,则为奇数 因为奇数二进制末位一定是1,所以 与1 得到的结果是1 这里,114——2 14 ——第15位是1,可以表示14个1 i(1j)—— 从0开始是因为,原本第1位就是1。所以j=0时,对应的就是 i 的最低位 F l o y d Floyd Fl oy d 算法: n o w ∣ f l a g = = f l

    2024年02月11日
    浏览(33)
  • Acwing-基础算法课笔记之动态规划(背包问题)

    01背包中的0和1指的是放与不放,而且不能出现放多个的情况,背包只能放相同物品中的一个; 首先是对 d [ i ] [ j ] d[i][j] d [ i ] [ j ] 数组的解释,该数组表示的是只看前 i i i 个物品,总体积是 j j j 的情况下,总价值最大是多少; 不选第 i i i 个物品,只考虑前 i − 1 i-1 i −

    2024年04月17日
    浏览(38)
  • 算法基础复盘笔记Day09【动态规划】—— 背包问题

    ❤ 作者主页:欢迎来到我的技术博客😎 ❀ 个人介绍:大家好,本人热衷于 Java后端开发 ,欢迎来交流学习哦!( ̄▽ ̄)~* 🍊 如果文章对您有帮助,记得 关注 、 点赞 、 收藏 、 评论 ⭐️⭐️⭐️ 📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉 1. 题目

    2023年04月22日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包