【贪心算法】(一)贪心算法理论及基础习题

news2024/9/21 12:27:55

【贪心算法】贪心算法理论及基础习题(一)

  • 理论基础
  • 简单例题
    • 分发饼干
    • K次取反后最大化的数组和
    • 柠檬水找零
    • 买卖股票的最佳时机 Ⅱ
    • 单调递增的数字
    • 摆动序列
  • 两个纬度权衡问题
    • 分发糖果
    • 根据身高重建队列

理论基础

什么是贪心: 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。

贪心算法没有固定套路,贪心算法大致一般分为如下四步:

  • 将问题分解为若干个子问题

  • 找出适合的贪心策略

  • 求解每一个子问题的最优解

  • 将局部最优解堆叠成全局最优解

简单例题

分发饼干

力扣原题
  假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

示例 1:
输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。虽然你有两块小饼干,由于他们的尺寸都是 1,你只能让胃口值是 1 的孩子满足。所以应该输出1。

示例 2:
输入: g = [1,2], s = [1,2,3]
输出: 2
解释: 你有两个孩子和三块小饼干,2 个孩子的胃口值分别是1,2。你拥有的饼干数量和尺寸都足以让所有孩子满足。所以你应该输出 2。

思路

  1. 先将饼干大小s[i]与孩子的胃口g[i]进行排序
  2. 每一轮保证当前胃口最小的孩子得到饼干吃
  3. 直到最大的饼干大小都无法满足当前孩子的胃口

代码实现

class Solution {
public:
	// g[i] 最小胃口   s[i] 饼干大小		s[i] >= g[i]
    int findContentChildren(vector<int>& g, vector<int>& s) {
		int res = 0;
		int startIdx = 0;				//记录发到第几块饼干了
		sort(g.begin(), g.end());
		sort(s.begin(), s.end());
		for(int i = 0; i < g.size(); i++)
		{
			for(int j = startIdx; j < s.size(); j++)
			{
				if(s[j] >= g[i])
				{
					res++;
					startIdx = j+1;		//从下一块饼干开始发
					break;	
				}
			}
		}
		return res;
    }
};

K次取反后最大化的数组和

力扣链接

给定一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

  • 选择某个下标 i 并将 nums[i] 替换为 -nums[i]
  • 重复这个过程恰好 k 次。可以多次选择同一个下标 i

以这种方式修改数组后,返回数组 可能的最大和

核心思想

  • 局部最优: 让绝对值大的负数变为正数,当前数值达到最大
  • 整体最优: 整个数组和达到最大。

  将数组按照绝对值大小从大到小排序,从前向后遍历,遇到负数将其变为正数,同时K–;结束后如果K还大于0,那么反复转变数值最小的元素,将K用完。

代码实现

class Solution {
static bool cmp(int a, int b)
{
	return abs(a) > abs(b);
}
public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
    	int sum = 0;
		sort(nums.begin(), nums.end(),cmp);			//按绝对值从大到小排序
		// 把尽可能多的负数转为正数
		for(int i = 0; i < nums.size();i++)
		{
			if(nums[i] < 0 && k > 0)
            {
				nums[i] = nums[i] * -1;
				k--;
            }
		}
		
		if(k % 2)		// 若还需要转奇数次,把最小的数转一次
			nums[nums.size()- 1] = nums[nums.size()- 1] * -1;
			
		for(int num:nums)
			sum += num;
			
		return sum;
    }
};

柠檬水找零

力扣链接
  每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元,一开始手头无钱。

示例 1:
输入:bills = [5,5,5,10,20]
输出:true

示例 2:
输入:bills = [5,5,10,10,20]
输出:false

核心思想
贪心:
局部最优: 遇到账单20,优先消耗美元10,完成本次找零。
全局最优: 完成全部账单的找零。
因为美元10只能给账单20找零,而美元5可以给账单10和账单20找零,美元5更万能!

代码实现

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
	    int money5 = 0;
		int money10 = 0;
		for(int i = 0; i < bills.size();i++)
		{
			if(bills[i] == 5)
				money5++;
			else if(bills[i] == 10)
			{
				money10++;
				if(money5 > 0)	
					money5--;
				else
					return false;
			}
            //收到20 有10块的先找10块的 
			else if(bills[i] == 20)
			{
				if(money5 > 0 && money10 > 0)
				{
					money5--;
					money10--;
				}
				else if(money5 >= 3)
					money5 -= 3;
				else
					return false;
			}
		}
		return true;
    }
};

买卖股票的最佳时机 Ⅱ

力扣原题

  给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售,返回 你能获得的 最大 利润 。

示例 1:
输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3。最大总利润为 4 + 3 = 7 。

示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4。最大总利润为 4 。

贪心思想
这道题目可能我们只会想,选一个低的买入,再选个高的卖,再选一个低的买入…循环反复,其实最终利润是可以分解的。

假如第 0 天买入,第 3 天卖出,那么利润为:prices[3] - prices[0]。

相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])。

此时就是把利润分解为每天为单位的维度,而不是从 0 天到第 3 天整体去考虑!
在这里插入图片描述
局部最优:收集每天的正利润,全局最优:求得最大利润。

代码实现

class Solution {
public:
    int maxProfit(vector<int>& prices) {
		int res = 0;
		int profit;
		for(int i = 1; i < prices.size(); i++)
		{	
			profit = prices[i] - prices[i-1];		// 当天利润
			if(profit > 0)
				res += profit;
		}
		return res;
    }
};

单调递增的数字

力扣链接

给定一个非负整数 N,找出小于或等于 N 的最大的整数,同时这个整数需要满足其各个位数上的数字是单调递增。

暴力求解
  暴力的思想即是通过逆序遍历N,判断每一个数字是否符合单调递增的规律,若符合,则直接返回。

bool judge(int num)	
{
	int max = 10;
       while (num) 
	{
           int t = num % 10;	// 依次取每一位
           if (max >= t) 		// 单调递增
			max = t;
           else 
			return false;
           num = num / 10;
       }
       return true;
}

贪心求解

  • 拿一个两位的数字举例,例如98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,即得到小于98的最大的单调递增整数。
  • 从后向前遍历,可以重复利用上次比较得出的结果,从后向前遍历332的数值变化为:332 -> 329 -> 299
  • 最后代码实现的时候,也需要一些技巧,例如用一个flag来标记从哪里起(从第一次出现 strNum[i - 1] > strNum[i] )后面开始赋值9。

代码实现

int monotoneIncreasingDigits(int n) 
{
	string strNum = to_string(n);
	int flag = strNum.size();			// 标记才哪开始起全部赋值为9
	for(int i = strNum.size()-1; i > 0; i--)
	{
		if(strNum[i-1] > strNum[i])		// 第一次出现非递增情况
		{
			strNum[i-1]--;
			flag = i;					// 记录下标,后面全部赋值为9
		}	
	}
	for(int i = flag; i < strNum.size(); i++)
		strNum[i] = '9';
		
	return stoi(strNum);
}

摆动序列

力扣原题

  如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

  • 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
  • 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是 摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。给你一个整数数组 nums ,返回 nums 中作为 摆动序列最长子序列的长度

思路

  • 本题是典型的查找变号 / 波峰波谷问题,但存在诸多特殊情况的细节问题

  • 局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。

  • 整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列。

  • 但本题要考虑三种特殊平坡情况:
    (1)情况一:上下坡中有平坡
    (2)情况二:数组首尾两端
    (3)情况三:单调坡中有平坡

(1)情况一:上下坡中有平坡
在这里插入图片描述
如图,可以统一规则,保留平坡最右边的数字,即删除左边的三个 2:
在这里插入图片描述

  • 在图中,当 i 指向第一个 2 的时候,prediff > 0 && curdiff = 0 ,当 i 指向最后一个 2 的时候 prediff = 0 && curdiff < 0

  • 如果我们采用,删左面三个 2 的规则,那么 当 prediff = 0 && curdiff < 0 也要记录一个峰值,因为他是把之前相同的元素都删掉留下的峰值。

  • 所以我们记录峰值的条件应该是: (preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0),为什么这里允许 prediff == 0 ,就是为了 上面我说的这种情况。

(2)情况二:数组首尾两端

  • 可以假设,数组最前面还有一个数字,那这个数字和第一个数字相同,即使得prediff = 0,curdiff < 0 或者 >0 也记为波谷。
  • 那么为了规则统一,针对序列[2,5],可以假设为[2,2,5],这样它就有坡度了即 preDiff = 0,如图:
    在这里插入图片描述
    针对以上情形,result 初始为 1(默认最右面有一个峰值),此时 curDiff > 0 && preDiff <= 0,那么 result++(计算了左面的峰值),最后得到的 result 就是 2(峰值个数为 2 即摆动序列长度为 2)

代码初步实现:

// 版本一
class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if (nums.size() <= 1) return nums.size();
        int curDiff = 0; // 当前一对差值
        int preDiff = 0; // 前一对差值
        int result = 1;  // 记录峰值个数,序列默认序列最右边有一个峰值
        for (int i = 0; i < nums.size() - 1; i++) {
            curDiff = nums[i + 1] - nums[i];
            // 出现峰值
            if ((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)) {
                result++;
            }
            preDiff = curDiff;
        }
        return result;
    }
};

(3)情况三:单调坡中有平坡
在上述代码中,忽略了一种情况,即 如果在一个单调坡度上有平坡,例如[1,2,2,2,3,4],如图:
在这里插入图片描述

  • 图中,我们可以看出,上述代码在三个地方记录峰值,但其实结果因为是 2,因为 单调中的平坡 不能算峰值(即摆动),之所以版本一会出问题,是因为我们实时更新了 prediff。
  • 我们只需要在 这个坡度 摆动变化的时候,更新 prediff 就行,这样 prediff 在 单调区间有平坡的时候 就不会发生变化,造成我们的误判。

代码最终实现

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
    	int res = 1;			// 最长子序列 默认最右边有坡度
    	int prediff = 0;		// 保存上一轮结果正负
    	int curdiff = 0;		// 暂存当前结果正负
    	bool flag = false;	
    	// 1个
		if(nums.size() == 1)
			return 1;
		for(int i = 0; i < nums.size() - 1; i++)	//去掉最后一个 默认有波动
		{
			curdiff = nums[i+1] - nums[i];
			//波动
			if(prediff >= 0 && curdiff < 0 || prediff <= 0 && curdiff > 0)
			{
				res++;
				prediff = curdiff;
			}
		}
		return res;
	}
};

两个纬度权衡问题

  这种双边题目一定是要确定一边之后,再确定另一边,如果两边一起考虑一定会顾此失彼。

分发糖果

力扣链接

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分,你需要按照以下要求,给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。
  • 相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

示例 1:
输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。

示例 2:
输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。

核心思想

  • 这种双边题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼。

  • 局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果

  • 如果ratings[i] > ratings[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个,所以贪心:candyVec[i] = candyVec[i - 1] + 1,代码如下:

    // 从前向后
    for (int i = 1; i < ratings.size(); i++) {
        if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1;
    }
    
  • 再确定左孩子大于右孩子的情况,为什么需要从后向前遍历?

  • 如果 ratings[i] > ratings[i + 1],此时candyVec[i]有两个选择了,一个是candyVec[i + 1] + 1(从右边这个加1得到的糖果数量),一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量),那么又要贪心了,局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的,遍历代码如下;

    // 从后向前
    for (int i = ratings.size() - 2; i >= 0; i--) {
        if (ratings[i] > ratings[i + 1] ) {
            candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1);
        }
    }
    

代码实现

class Solution {
public:
	// 每个孩子至少分配到 1 个糖果。
	// 相邻两个孩子评分更高的孩子会获得更多的糖果。
	int candy(vector<int>& ratings) {
		int sum = 0;
		vector<int> candyVec(ratings.size(),1);
		// 右孩子比左孩子大
		for(int i = 0; i < ratings.size() - 1; i++)
		{
			if(ratings[i] < ratings[i+1])
				candyVec[i+1] = candyVec[i] + 1;
		}
		
		// 左孩子比右孩子大
		for(int i = ratings.size() - 1; i > 0; i--)
		{
			if(ratings[i-1] > ratings[i])
				candyVec[i-1] = max(candyVec[i-1], candyVec[i] + 1);
		}
		
		for(int num: candyVec)
			sum += num;
			
		return sum;
    }
};

根据身高重建队列

力扣链接

  假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

示例 1:
输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]

示例 2:
输入:people = [[6,0],[5,0],[4,0],[3,2],[2,2],[1,4]]
输出:[[4,0],[5,0],[2,2],[3,2],[1,4],[6,0]]

核心思想

  • 本题有两个维度,h和k,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度,如果两个维度一起考虑一定会顾此失彼
  • 如果按照k来从小到大排序,排完之后,k与h均不符合条件;若按照身高h来排序,身高一定是从大到小排,让高个子在前面。此时先确定身高维度,前面的节点一定都比本节点高!
  • 按照身高排序之后,优先按身高高的people的k来插入,后序插入节点也不会影响前面已经插入的节点,最终按照k的规则完成了队列。

局部最优: 优先按身高高的people的k来插入。插入操作过后的people满足队列属性
全局最优: 最后都做完插入操作,整个队列满足题目队列属性

代码实现

class Solution {
public:
	static bool cmp(vector<int> &a, vector<int> &b)
	{
		if(a[0] == b[0])
			return a[1] < b[1];
		else
			return a[0] > b[0];
	}
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) 
	{
		vector<vector<int>> queue;
		// 按身高从到到低排序
		sort(people.begin(), people.end(), cmp);
		for(int i = 0; i < people.size(); i++)
		{
			int insertPos = people[i][1];
			queue.insert(queue.begin() + insertPos, people[i]);
		}
		return queue;
    }
};

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

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

相关文章

[N-152]基于java贪吃蛇游戏5

开发工具eclipse,jdk1.8 文档截图&#xff1a; N-152基于java贪吃蛇游戏5

通过Python调用Excel VBA宏:扩展自动化能力的深度探索

目录 1. 引言 1.1 自动化办公的重要性 1.2 Python与Excel VBA的结合优势 2. Python调用Excel VBA宏的基本原理 2.1 Excel VBA宏的基本概念 2.2 Python调用VBA宏的方法 3. 安装与准备 3.1 安装pywin32库 3.2 配置Excel以允许宏运行 4. Python调用VBA宏的实例 4.1 导出…

基于单片机的室内装修环境检测系统设计

基于单片机的室内装修环境检测系统&#xff0c;该系统可实现苯、甲醛、氨气等有害气体的浓度检测和超标报警。该系统以STC89C52RC单片机为核心&#xff0c;由传感器检测室内装修环境中苯、甲醛、氨气的浓度以及温湿度&#xff0c;将以上测量出来的数据传送到PCF8591转换器&…

Java+vue的医药进出口交易系统(源码+数据库+文档)

外贸系统|医药进出口交易系统 目录 基于Javavue的服装定制系统 一、前言 二、系统设计 三、系统功能设计 仓储部门功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设…

15.2 JDBC数据库编程2

15.2.1 数据库访问步骤 使用JDBC API连接和访问数据库&#xff0c;一般分为以下5个步骤: (1) 加载驱动程序 (2) 建立连接对象 (3) 创建语句对象 (4) 获得SQL语句的执行结果 (5) 关闭建立的对象&#xff0c;释放资源 下面将详细描述这些步骤 15.2.2 加载驱动程序 要使…

开发中的网络问题逻辑推理分析

基于TCP/IP的逻辑推理&#xff0c;大部分软件从业人员都不是很懂&#xff0c;导致很多问题都被误认为诡异问题。有些人是惧怕TCP/IP网络书籍中的复杂知识内容&#xff0c;有的是被wireshark[1]显示的深红色内容所干扰。 经典案例1&#xff1a; 例如有一个DBA遇到了性能问题&a…

基于SpringBoot+Vue+MySQL的流浪猫狗宠物救助救援网站管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 在当今社会&#xff0c;随着宠物数量的激增及人们关爱动物意识的提升&#xff0c;流浪猫狗问题日益严峻。为解决这一问题&#xff0c;构建一套高效、便捷的流浪猫狗宠物救助救援网站管理系统显得尤为重要。本系统基于SpringBoot…

在VB.net中,TimeSpan有什么属性与方法

标题 在VB.net中&#xff0c;TimeSpan有什么属性与方法 正文 在 VB.NET 中&#xff0c;TimeSpan 结构表示时间间隔&#xff0c;即一段时间&#xff0c;而不表示特定的时间点。TimeSpan 提供了多种属性来获取时间间隔的各个组成部分&#xff0c;以及一些方法来操作这些时间间隔。…

Linux下载新版火狐浏览器,替换默认火狐浏览器,保留桌面任务栏图标快捷方式

Linux下载新版火狐浏览器&#xff0c;替换默认火狐浏览器&#xff0c;保留桌面任务栏图标快捷方式 方式一 替换默认程序入口 下载官方浏览器 火狐浏览器下载地址【官网】 &#xff08;搞清楚你的Linux系统是32位还是64位&#xff09; 解压下载的程序包&#xff0c;建议放到/o…

Leetcode面试经典150题-74.搜索二维矩阵

解法都在代码里&#xff0c;不懂就留言或者私信 二分查找&#xff0c;比较简单 class Solution {/**解题思路&#xff1a;每一行有序、每一列也有序&#xff0c;只是整体不是严格有序的&#xff0c;那我们需要找一个点&#xff0c;只能往两个方向走&#xff0c;往一个方向走是…

【docker】命令之镜像操作

一、前言 之前讲解了docker的安装&#xff0c;这里呢接着上面的内容来介绍docker中的相关命令的操作。这里我们更具一个案例就是启动一个nginx&#xff08;是一个在我们应用市场存在的一个软件包&#xff09;,并尝试对其进行修改&#xff0c;然后发布出去&#xff0c;让别人都能…

Guitar Pro 8.2中文解锁版下载及2024最新图文安装教程

Guitar Pro 8.2中文解锁版是一款深受广大音乐人和音乐爱好者喜爱的吉他打谱软件&#xff0c;帮助所有吉他爱好者学习、绘谱、创作&#xff0c;使用非常简单只需直接在五线谱或六线谱上编辑&#xff0c;即可轻松谱写自己的乐章。 Guitar Pro 8.2中文解锁版基本简介 Guitar Pro 8…

【python】python 安装和 pycharm 安装

1 python 安装 1.1 下载 下载地址&#xff1a;python 官网 1.2 安装 windows 安装为例。 双击.exe文件打开 安装界面 安装完成 1.3 检查安装是否成功 win/start 键r 键 运行窗口输入 cmd 回车 3 输入 python查看 显示版本信息&#xff0c;表示已经安装成功。 …

谷粒商城-P125【gulimall-search】:更改 elasticsearch 版本不生效

谷粒商城-P125【gulimall-search】&#xff1a;更改 elasticsearch 版本不生效 报错信息报错原因解决办法 报错信息 SpringBoot 项目的版本是 2.6.13&#xff0c;默认集成的 elasticsearch 的版本是 7.15.2&#xff0c;我们需要用的版本是 7.4.2。 SpringBoot 版本 SpringB…

pptpd配置文件/etc/pptpd.conf详解

正文共&#xff1a;1111 字 2 图&#xff0c;预估阅读时间&#xff1a;1 分钟 如果要在Linux系统配置PPTP&#xff08;Point-to-Point Tunneling Protocol&#xff0c;点到点隧道协议&#xff09;VPN&#xff0c;一般是使用pptpd软件。pptpd命令通常从配置文件/etc/pptpd.conf中…

JavaWeb【day15】--(Maven高级)

Maven高级 Web开发讲解完毕之后&#xff0c;我们再来学习Maven高级。其实在前面的课程当中&#xff0c;我们已经学习了Maven。 我们讲到 Maven 是一款构建和管理 Java 项目的工具。经过前面 10 多天 web 开发的学习&#xff0c;相信大家对于 Maven 这款工具的基本使用应该没什…

Windows安装HeidiSQL教程(图文)

一、软件简介 HeidiSQL是一款开源的数据库管理工具&#xff0c;主要用于管理MySQL、MariaDB、SQL Server、PostgreSQL和SQLite等数据库系统。它提供了直观的用户界面&#xff0c;使用户可以轻松地连接到数据库服务器、执行SQL查询、浏览和编辑数据、管理数据库结构等操作。 跨…

Linux:epoll 工作模式

边缘触发&#xff08;Edge Triggered&#xff0c;简称ET&#xff09;和 水平触发&#xff08;Level Triggered&#xff0c;简称LT&#xff09;是epoll两种不同的工作模式&#xff0c;它们在处理I/O事件时有不同的行为。 1&#xff1a;水平触发&#xff08;LT&#xff09;模式 1…

4G MQTT网关在物联网应用中的优势-天拓四方

随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;各种设备和系统之间的互联互通变得日益重要。MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;作为一种轻量级的发布/订阅消息传输协议&#xff0c;因其高效、可靠、简单的特性&#xff0c;在…

从 Greenplum 到 Databend,数据仓库的开源新选择

Greenplum 是知名开源数据仓库项目&#xff0c;曾是大数据分析领域的明星产品&#xff0c;在全球范围内尤其是在国内市场上有着重要的地位。今年 6 月&#xff0c; Greenplum 的 GitHub 仓库突然被改为归档模式&#xff0c;访问权限也修改为只读&#xff0c;用户将失去对源代码…