C++算法学习心得八.动态规划算法(4)

1.零钱兑换(322题)

题目描述:

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

你可以认为每种硬币的数量是无限的。

示例 1:

  • 输入:coins = [1, 2, 5], amount = 11
  • 输出:3
  • 解释:11 = 5 + 5 + 1

dp[j]:凑足总额为j所需钱币的最少个数为dp[j] 

凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i])

所以dp[j] 要取所有 dp[j - coins[i]] + 1 中最小的。

递推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);

dp[0] = 0;

考虑到递推公式的特性,dp[j]必须初始化为一个最大的数,否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖。

所以下标非0的元素都是应该是最大值。

本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数

所以本题并不强调集合是组合还是排列。

如果求组合数就是外层for循环遍历物品,内层for遍历背包

如果求排列数就是外层for遍历背包,内层for循环遍历物品

本题的两个for循环的关系是:外层for循环遍历物品,内层for遍历背包或者外层for遍历背包,内层for循环遍历物品都是可以的

class Solution {
public:int coinChange(vector<int>& coins, int amount) {vector<int>dp(amount + 1,INT_MAX);dp[0] = 0;for(int i = 0;i < coins.size();i++){ // 遍历物品for(int j = coins[i];j <= amount;j++){// 遍历背包if (dp[j - coins[i]] != INT_MAX) { // 如果dp[j - coins[i]]是初始值则跳过dp[j] = min(dp[j - coins[i]] + 1, dp[j]);}}}if (dp[amount] == INT_MAX) return -1;return dp[amount];}
};
  • 时间复杂度: O(n * amount),其中 n 为 coins 的长度
  • 空间复杂度: O(amount)

遍历背包放在外循环,遍历物品放在内循环也是可以的 

class Solution {
public:int coinChange(vector<int>& coins, int amount) {vector<int>dp(amount + 1,INT_MAX);dp[0] = 0;for(int i = 1;i <= amount;i++){ // 遍历背包for(int j = 0;j < coins.size();j++){// 遍历物品if (i-coins[j] >= 0 && dp[i - coins[j]] != INT_MAX) { // 如果dp[j - coins[i]]是初始值则跳过dp[i] = min(dp[i - coins[j]] + 1, dp[i]);}}}if (dp[amount] == INT_MAX) return -1;return dp[amount];}
};

2.完全平方数(279题)

题目描述:

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

示例 1:

  • 输入:n = 12
  • 输出:3
  • 解释:12 = 4 + 4 + 4

dp[j]:和为j的完全平方数的最少数量为dp[j]

dp[j] 可以由dp[j - i * i]推出, dp[j - i * i] + 1 便可以凑成dp[j]。

此时我们要选择最小的dp[j],所以递推公式:dp[j] = min(dp[j - i * i] + 1, dp[j]);

dp[0]表示 和为0的完全平方数的最小数量,那么dp[0]一定是0,非0下标的dp[j]一定要初始为最大值,这样dp[j]在递推的时候才不会被初始值覆盖

本题外层for遍历背包,内层for遍历物品,还是外层for遍历物品,内层for遍历背包,都是可以的

先遍历物品,在遍历背包 

class Solution {
public:int numSquares(int n) {vector<int>dp(n + 1,INT_MAX);dp[0] = 0;for(int i = 1;i * i <= n;i++){// 遍历物品for(int j = i * i;j <= n;j++){// 遍历背包dp[j] = min(dp[j],dp[j - i * i]+1);}}return dp[n];}
};

遍历背包,遍历物品

class Solution {
public:int numSquares(int n) {vector<int> dp(n + 1, INT_MAX);dp[0] = 0;for (int i = 0; i <= n; i++) { // 遍历背包for (int j = 1; j * j <= i; j++) { // 遍历物品dp[i] = min(dp[i - j * j] + 1, dp[i]);}}return dp[n];}
};
  • 时间复杂度: O(n * √n)
  • 空间复杂度: O(n)

 3.单词拆分(139题)

题目描述:

给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。

说明:

拆分时可以重复使用字典中的单词。

你可以假设字典中没有重复的单词。

示例 1:

  • 输入: s = "leetcode", wordDict = ["leet", "code"]
  • 输出: true
  • 解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。

回溯算法:本道是枚举分割所有字符串,判断是否在字典里出现过

class Solution {
private:bool backtracking (const string& s, const unordered_set<string>& wordSet, int startIndex) {if (startIndex >= s.size()) {return true;}for (int i = startIndex; i < s.size(); i++) {string word = s.substr(startIndex, i - startIndex + 1);if (wordSet.find(word) != wordSet.end() && backtracking(s, wordSet, i + 1)) {return true;}}return false;}
public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string> wordSet(wordDict.begin(), wordDict.end());return backtracking(s, wordSet, 0);}
};
  • 时间复杂度:O(2^n),因为每一个单词都有两个状态,切割和不切割
  • 空间复杂度:O(n),算法递归系统调用栈的空间

改进版回溯算法:

class Solution {
private:bool backtracking (const string& s,const unordered_set<string>& wordSet,vector<bool>& memory,int startIndex) {if (startIndex >= s.size()) {return true;}// 如果memory[startIndex]不是初始值了,直接使用memory[startIndex]的结果if (!memory[startIndex]) return memory[startIndex];for (int i = startIndex; i < s.size(); i++) {string word = s.substr(startIndex, i - startIndex + 1);if (wordSet.find(word) != wordSet.end() && backtracking(s, wordSet, memory, i + 1)) {return true;}}memory[startIndex] = false; // 记录以startIndex开始的子串是不可以被拆分的return false;}
public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string> wordSet(wordDict.begin(), wordDict.end());vector<bool> memory(s.size(), 1); // -1 表示初始化状态return backtracking(s, wordSet, memory, 0);}
};

 这个时间复杂度其实也是:O(2^n)

背包问题:

dp[i] : 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词

如果确定dp[j] 是true,且 [j, i] 这个区间的子串出现在字典里,那么dp[i]一定是true。(j < i )。

所以递推公式是 if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) 那么 dp[i] = true。

从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false了。

拆分为一个或多个在字典中出现的单词,所以这是完全背包。

还要讨论两层for循环的前后顺序。

如果求组合数就是外层for循环遍历物品,内层for遍历背包

如果求排列数就是外层for遍历背包,内层for循环遍历物品

本题一定是 先遍历 背包,再遍历物品

class Solution {
public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string> wordSet(wordDict.begin(), wordDict.end());vector<bool> dp(s.size() + 1, false);dp[0] = true;for (int i = 1; i <= s.size(); i++) {   // 遍历背包for (int j = 0; j < i; j++) {       // 遍历物品string word = s.substr(j, i - j); //substr(起始位置,截取的个数)if (wordSet.find(word) != wordSet.end() && dp[j]) {dp[i] = true;}}}return dp[s.size()];}
};
  • 时间复杂度:O(n^3),因为substr返回子串的副本是O(n)的复杂度(这里的n是substring的长度)
  • 空间复杂度:O(n)

4.多重背包理论基础(卡玛网56题)

有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大。

#include<iostream>
#include<vector>
using namespace std;int main(){int bagWeight,n;cin >> bagWeight >> n;vector<int> weight(n, 0);vector<int> value(n, 0);vector<int> nums(n, 0);for (int i = 0; i < n; i++) cin >> weight[i];for (int i = 0; i < n; i++) cin >> value[i];for (int i = 0; i < n; i++) cin >> nums[i];vector<int> dp(bagWeight + 1, 0);for(int i = 0; i < n; i++) { // 遍历物品for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量// 以上为01背包,然后加一个遍历个数for (int k = 1; k <= nums[i] && (j - k * weight[i]) >= 0; k++) { // 遍历个数dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);}}}cout << dp[bagWeight] << endl;
}

 时间复杂度:O(m × n × k),m:物品种类个数,n背包容量,k单类物品数量

5.打家劫舍( 198题)

题目描述:

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

  • 示例 1:
  • 输入:[1,2,3,1]
  • 输出:4

解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。   偷窃到的最高金额 = 1 + 3 = 4 。

dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]。 

dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])

dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值即:dp[1] = max(nums[0], nums[1]);

dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的,那么一定是从前到后遍历!

class Solution {
public:int rob(vector<int>& nums) {//当前数组大小为0时返回0if (nums.size() == 0)return 0;//当前数组大小1时返回1if (nums.size() == 1)return nums[0];vector<int> dp(nums.size());//定义dp数组dp[0] = nums[0];//初始化0dp[1] = max(nums[0], nums[1]);//初始化dp[1]//遍历,从后向前遍历for (int i = 2; i < nums.size(); i++) {dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);//递推公式}return dp[nums.size() - 1];//返回值}
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

6. 打家劫舍II(213题)

题目描述:

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。

给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。

示例 1:

  • 输入:nums = [2,3,2]

  • 输出:3

  • 解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

  • 情况一:考虑不包含首尾元素
  • 情况二:考虑包含首元素,不包含尾元素
  • 情况三:考虑包含尾元素,不包含首元素

虽然是考虑包含尾元素,但不一定要选尾部元素,情况二 和 情况三 都包含了情况一了,所以只考虑情况二和情况三就可以了。

class Solution {
public:int rob(vector<int>& nums) {if (nums.size() == 0) return 0;if (nums.size() == 1) return nums[0];int result1 = robRange(nums, 0, nums.size() - 2); // 情况二int result2 = robRange(nums, 1, nums.size() - 1); // 情况三return max(result1, result2);}int robRange(vector<int>& nums,int start,int end){if (end == start) return nums[start];vector<int>dp(nums.size());dp[start] = nums[start];dp[start + 1] = max(nums[start],nums[start + 1]);for(int i = start + 2;i <= end;i++){dp[i] = max(dp[i - 1],dp[i - 2] + nums[i]);}return dp[end];}
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

 7.打家劫舍 III(337题)

题目描述:

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

 本题一定是要后序遍历,如果抢了当前节点,两个孩子就不能动,如果没抢当前节点,就可以考虑抢左右孩子

暴力递归

class Solution {
public:int rob(TreeNode* root) {if(root == NULL)return NULL;if(root->left == NULL && root->right == NULL)return root->val;// 偷父节点int val1 = root->val;if(root->left)val1 += rob(root->left->left) + rob(root->left->right);// 跳过root->left,相当于不考虑左孩子if(root->right)val1 += rob(root->right->left) + rob(root->right->right);// 跳过root->right,相当于不考虑右孩子了// 不偷父节点int val2 = rob(root->left) + rob(root->right);return max(val1, val2);}
};
  • 时间复杂度:O(n^2),这个时间复杂度不太标准,也不容易准确化,例如越往下的节点重复计算次数就越多
  • 空间复杂度:O(log n),算上递推系统栈的空间

记忆化递推:可以使用一个map把计算过的结果保存一下,这样如果计算过孙子了,那么计算孩子的时候可以复用孙子节点的结果。 

class Solution {
public:unordered_map<TreeNode* , int> umap; // 记录计算过的结果int rob(TreeNode* root) {if (root == NULL) return 0;if (root->left == NULL && root->right == NULL) return root->val;if (umap[root]) return umap[root]; // 如果umap里已经有记录则直接返回// 偷父节点int val1 = root->val;if (root->left) val1 += rob(root->left->left) + rob(root->left->right); // 跳过root->leftif (root->right) val1 += rob(root->right->left) + rob(root->right->right); // 跳过root->right// 不偷父节点int val2 = rob(root->left) + rob(root->right); // 考虑root的左右孩子umap[root] = max(val1, val2); // umap记录一下结果return max(val1, val2);}
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(log n),算上递推系统栈的空间

动态规划

 这道题目算是树形dp的入门题目,因为是在树上进行状态转移

这里的返回数组就是dp数组

dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。

dp数组就是一个长度为2的数组

在递归的过程中,系统栈会保存每一层递归的参数

在遍历的过程中,如果遇到空节点的话,很明显,无论偷还是不偷都是0,所以就返回,相当于dp数组的初始化,明确的是使用后序遍历。

通过递归左节点,得到左节点偷与不偷的金钱。

通过递归右节点,得到右节点偷与不偷的金钱。

如果是偷当前节点,那么左右孩子就不能偷,val1 = cur->val + left[0] + right[0]; (如果对下标含义不理解就再回顾一下dp数组的含义

如果不偷当前节点,那么左右孩子就可以偷,至于到底偷不偷一定是选一个最大的,所以:val2 = max(left[0], left[1]) + max(right[0], right[1]);

最后当前节点的状态就是{val2, val1}; 即:{不偷当前节点得到的最大金钱,偷当前节点得到的最大金钱}

class Solution {
public:int rob(TreeNode* root) {vector<int> result = robTree(root);return max(result[0], result[1]);}// 长度为2的数组,0:不偷,1:偷vector<int> robTree(TreeNode* cur) {if (cur == NULL) return vector<int>{0, 0};vector<int> left = robTree(cur->left);vector<int> right = robTree(cur->right);// 偷cur,那么就不能偷左右节点。int val1 = cur->val + left[0] + right[0];// 不偷cur,那么可以偷也可以不偷左右节点,则取较大的情况int val2 = max(left[0], left[1]) + max(right[0], right[1]);return {val2, val1};}
};
  • 时间复杂度:O(n),每个节点只遍历了一次
  • 空间复杂度:O(log n),算上递推系统栈的空间

总结:

零钱兑换:不同面额的硬币 coins 和一个总金额 amount,凑成总金额所需的最少的硬币个数,dp[j]:凑足总额为j所需钱币的最少个数为dp[j] ,递推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);dp[0] = 0;dp[j]必须初始化为一个最大的数,否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖,下标非0的元素都是应该是最大值,本题的两个for循环的关系是:外层for循环遍历物品,内层for遍历背包或者外层for遍历背包,内层for循环遍历物品都是可以的,我们最后返回dp[amount]即可,如果dp[j - coins[i]]是初始值则跳过判断条件,

完全平方数:给定一个整数,使用完全平方数来实现和为这个整数,dp[j]:和为j的完全平方数的最少数量为dp[j],最小的dp[j],所以递推公式:dp[j] = min(dp[j - i * i] + 1, dp[j]),dp[0]一定是0,非0下标的dp[j]一定要初始为最大值,本题外层for遍历背包,内层for遍历物品,还是外层for遍历物品,内层for遍历背包,都是可以的。

for(int i = 1;i * i <= n;i++){// 遍历物品
            for(int j = i * i;j <= n;j++){// 遍历背包
                dp[j] = min(dp[j],dp[j - i * i]+1);
            }
        }

 单词拆分:给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。回溯算法:本道是枚举分割所有字符串,判断是否在字典里出现过,组合问题,我们首先对字符串进行取哈希表的方法,unordered_set<string> wordSet,然后是组合问题,startindex,终止条件if(startindex > s.size())return true;for(int i = startindex;i<s.size();i++)之后我们需要对这个进行取字符串操作,s.substr操作,然后我们进行下面的操作,判断是否出现过且进行递归,然后返回True,否则返回false,使用背包来解决问题,dp[i] : 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词。递推公式是 if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) 那么 dp[i] = true,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false,本题一定是 先遍历 背包,再遍历物品,

多重背包理论基础:有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大。

for(int i = 0; i < n; i++) { // 遍历物品
        for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
            // 以上为01背包,然后加一个遍历个数
            for (int k = 1; k <= nums[i] && (j - k * weight[i]) >= 0; k++) { // 遍历个数
                dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);
            }
        }
    }

打家劫舍: 给定一个数组,然后限制条件是相邻的有警报系统,可以偷取的最大价值是多少,dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]),dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值即:dp[1] = max(nums[0], nums[1]);从前到后遍历,这里我们定义dp数组大小为数组大小即可,初始化和上述介绍,遍历从前向后遍历,从2开始到nums.size(),最后递推公式即可,最后返回dp[nums.size() - 1]

打家劫舍II:该题与上一个题不同于整个数组是连成一个圈首尾呼应,三种情况第一个不考虑首尾,第二种考虑首不考虑尾,第三种情况考虑尾不考虑首,第二三种情况包括了第一种情况,所以我们直接考虑设计一个函数根据首尾位置的一个打家劫舍的函数即可实现,这里采用两个首尾位置下标的方法,首先递推公式和上一个一样,这里初始化需要根据下标进行初始化,初始化也就是把初始化的下标换成start即可,最后返回dp[end]即可,

打家劫舍III:和二叉树联系起来的一个打家劫舍问题,这里一定需要后序遍历,抢了当前节点,两个孩子就不能动,如果没抢当前节点,就可以考虑抢左右孩子,分两种情况取考虑,这里需要知道一个是取父节点(之后我们需要左节点的左右孩子,还要右节点的左右孩子),另一个是不取父节点(递归左和右)记忆化递推:可以使用一个map把计算过的结果保存一下,这样如果计算过孙子了,那么计算孩子的时候可以复用孙子节点的结果,树形dp是在树上进行状态转移,dp数组下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。dp数组就是一个长度为2的数组,如果是偷当前节点,那么左右孩子就不能偷,val1 = cur->val + left[0] + right[0]; (如果对下标含义不理解就再回顾一下dp数组的含义)如果不偷当前节点,那么左右孩子就可以偷,至于到底偷不偷一定是选一个最大的,所以:val2 = max(left[0], left[1]) + max(right[0], right[1]);最后当前节点的状态就是{val2, val1}; 即:{不偷当前节点得到的最大金钱,偷当前节点得到的最大金钱}其实这里就是将其分开讨论了,最后取最大值即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/750766.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSDN学习笔记总索引(2024)——我的创作纪念日(1024)

2021-05-21至2024-03-17笔记&#xff0c;收集并展示浏览阅读点赞收藏等数据。 (本笔记适合初通Python&#xff0c;对其基本数据类型字符串str、列表list、元组tuple、字典dict初步了解&#xff0c;认识Linux获取Html文本指令crul、会使正则模块re的coder翻阅) 【学习的细节是欢…

VS2019加QT5.14中Please assign a Qt installation in ‘Qt Project Settings‘.问题的解决

第一篇&#xff1a; 原文链接&#xff1a;https://blog.csdn.net/aoxuestudy/article/details/124312629 error:There’ no Qt version assigned to project mdi.vcxproj for configuration release/x64.Please assign a Qt installation in “Qt Project Settings”. 一、分…

Linux基础开发工具之yum与vim

1. Linux软件包管理器——yum 1.1 什么是软件包&#xff1f; 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上, …

Nginx离线安装(保姆级教程)

1、下载与安装gcc-c环境 获取rpm包的方式很多&#xff0c;在这里推荐使用yum工具获取&#xff0c;因为手动从官网下载&#xff0c;手动执行rpm -Uvh *.rpm --nodeps --force命令进行安装&#xff0c;可能会缺少某个依赖&#xff0c;我们也不确定到底需要哪些依赖。 因此需要准…

基于Linux内核的socket编程(TCP)的C语言示例

原文地址&#xff1a;https://www.geeksforgeeks.org/socket-programming-cc/ 服务端&#xff1a; #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <unistd.h>#…

Python之Web开发中级教程----搭建Web框架二

Python之Web开发中级教程----搭建Web框架二 搭建虚拟环境 虚拟环境的作用 虚拟环境可以搭建独立的python运行环境, 使得单个项目的运行环境与其它项目互不影响. 搭建虚拟环境 &#xff08;1&#xff09;安装 sudo pip install virtualenv sudo pip install virtualenvwra…

在线答疑系统|基于springboot框架+ Mysql+Java+Tomcat的在线答疑系统设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 学生功能模块 教师后台功能模块 管理员功能模块 系统功能设计 数据库E-R图设计 lunwen参考 摘要 研…

Redis实现分布式锁源码分析

为什么使用分布式锁 单机环境并发时&#xff0c;使用synchronized或lock接口可以保证线程安全&#xff0c;但它们是jvm层面的锁&#xff0c;分布式环境并发时&#xff0c;100个并发的线程可能来自10个服务节点&#xff0c;那就是跨jvm了。 简单分布式锁实现 SETNX 格式&…

【ollama】linux、window系统更改模型存放位置,全网首发2024!

首先是window系统 so easy 直接进入系统环境变量添加就行 其次是linux系统 全靠自己试出来的,去Ollama官网找半天文档不知道在哪,而且linux也没有说:【 https://github.com/ollama/ollama/blob/main/docs/README.md https://github.com/ollama/ollama/blob/main/docs/li…

最大异或对(trie树)

题目描述&#xff1a; 思路&#xff1a; 1、首先此题我们要知道异或的规则&#xff0c;这里不赘述了&#xff0c;可以百度 2、如果利用trie树去找到一个数字与其异或能得到最大值 比如二进制数&#xff1a;1010.....是一个很大的数 我们想要异或得到的值更大&#xff0c;就需…

HarmonyOS(二十)——管理应用拥有的状态之LocalStorage(页面级UI状态存储)

LocalStorage是页面级的UI状态存储&#xff0c;通过Entry装饰器接收的参数可以在页面内共享同一个LocalStorage实例。LocalStorage也可以在UIAbility实例内&#xff0c;在页面间共享状态。 本文仅介绍LocalStorage使用场景和相关的装饰器&#xff1a;LocalStorageProp和LocalS…

微服务技术栈之rabbitMQ高级(二)

我们该如何确保MQ消息的可靠性&#xff1f; 如果真的发送失败&#xff0c;有没有其它的兜底方案&#xff1f; 这些问题&#xff0c;在这一次的学习中都会找到答案。 生产者的可靠性 首先&#xff0c;我们一起分析一下消息丢失的可能性有哪些。 消息从发送者发送消息&#…

StarRocks实战——云览科技存算分离实践

目录 背景 一、平台现状&痛点 1.1 使用组件多&#xff0c;维护成本高 1.2 链路冗长&#xff0c;数据时效性难以保证 1.3 服务稳定性不足 二、StarRocks 存算分离调研 2.1 性能对比 2.2 易用性 2.3 存储成本 三、StarRocks 存算分离实践 3.1 查询优化 3.1.1 物化…

Linux网络编程: 以太网帧Frame/ARP/RARP详解

一、TCP/IP五层模型 物理层&#xff08;Physical Layer&#xff09;&#xff1a;物理层是最底层&#xff0c;负责传输比特流&#xff08;bitstream&#xff09;以及物理介质的传输方式。它定义了如何在物理媒介上传输原始的比特流&#xff0c;例如通过电缆、光纤或无线传输等。…

【论文阅读】Diffused Heads: Diffusion Models Beat GANs on Talking-Face Generation

Diffused Heads: 扩散模型在说话人脸生成方面击败GANs paper&#xff1a;[2301.03396] Diffused Heads: Diffusion Models Beat GANs on Talking-Face Generation (arxiv.org) code&#xff1a;MStypulkowski/diffused-heads: Official repository for Diffused Heads: Diffu…

R:简易的Circos图

library(grid) library(circlize) library(RColorBrewer) library(ComplexHeatmap) setwd("C:/Users/fordata/Downloads/Circos") # 创建颜色调色板 coul <- colorRampPalette(brewer.pal(9, "Set3"))(12) # 读取基因组数据 genome <- read.table(ci…

贪心算法(两个实例)

例一&#xff1a;调度问题 问题&#xff1a;由n项任务&#xff0c;每项任务的加工时间已知&#xff0c;从零时刻开始陆续加入一台机器上去加工&#xff0c;每个任务完成的时间是从0时刻到任务加工截至的时间。 求总完成时间&#xff08;所有任务完成时间最短计划方案&#xf…

PostMan测试文件上传

后端代码 package com.example.backend.controller;import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.example.backend.common.Result; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import org…

Python Web开发记录 Day9:Django part3 用户管理

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 1、数据库准备2、用户列表3、新建用户4、编辑用…

科研学习|论文解读——美国政治经济中的权力:网络分析(JASIST, 2019)

论文原题目 Power in the U.S. political economy: A network analysis 摘要 美国政治经济的许多特征产生于大型政治和经济机构之间的互动&#xff0c;然而我们对它们的互动性质和这些机构之间的权力分配知之甚少。在本文中&#xff0c;对总部设在美国的组织的网络进行了详细的…