【算法深练】二分答案:从「猜答案」到「精准求解」的解题思路

目录

前言

二分求最小值

1283. 使结果不超过阈值的最小除数

2187. 完成旅途的最少时间

1011. 在 D 天内送达包裹的能力

875. 爱吃香蕉的珂珂

3296. 移山所需的最少秒数

475. 供暖器

2594. 修车的最少时间

1482. 制作 m 束花所需的最少天数

3048. 标记所有下标的最早秒数 I

求最小值拓展(浮点型) 

1870. 准时到达的列车最小时速

3453. 分割正方形 I

二分求最大值

275. H 指数 II

2226. 每个小孩最多能分到多少糖果

2982. 找出出现至少三次的最长特殊子字符串 II

2576. 求出最多标记下标

1898. 可移除字符的最大数目

1802. 有界数组中指定下标处的最大值

1642. 可以到达的最远建筑

2861. 最大合金数

总结


前言

二分答案与二分查找【算法深练】二分查找:从O(n)到O(log n)以对数级效率秒杀海量数据的解题利刃-CSDN博客有异曲同工之妙,与二分查找不同的是:二分答案需要自己编写check函数来判断是否成立。二分答案在我们解题中是比较常用的,如果一个题目无从下手,可以先思考如果在已知答案的情况下,对答案进行判断是否更简单,如果更简单就可以考虑使用二分来AC。

PS:本篇博客中的所有题目均来自于灵茶山艾府 - 力扣(LeetCode)分享的题单。 

二分求最小值

1283. 使结果不超过阈值的最小除数

题解:找到一个不大于threshold的整数,找到数组中除以该整数后仍然小于thorshold的最小除数。根据nums.length<=threshold如果除数是最大值结果就是nums.length满足条件,所以区间就在(0,max(nums)]中对该区间中的所有数进行枚举找到满足条件的最小值,时间复杂度是O(N^2)太慢了。当除数变大的时候结果就在减小,那不就是单调的吗,能使用二分来解决;将左右边界分别设置为0和max(nums),进行二分找到满足条件的最小值。细节:向上取整a/b就是(a+b-1)/b向下取整。

class Solution {//计算如果除数是x结果时多少int div(vector<int>& nums,int x){int ret=0;for(auto e:nums) ret+=(e+x-1)/x;return ret;}
public:int smallestDivisor(vector<int>& nums, int threshold) {int n=nums.size();        //以数组小标表示除数,随着下标增大结果也在减小所以可以使用二分int left=0,right=ranges::max(nums);   //使用左开右开的形式  n<=threshold所以最大值是除数为nums[n-1]时结果是nwhile(left+1<right){int mid=left+(right-left)/2;if(div(nums,mid)<=threshold) right=mid;  //满足条件else left=mid;   //不满足条件}return right;}
};

2187. 完成旅途的最少时间

题解:与类似,当时间在增大时旅途趟数也在增加是递增的可以使用二分进行查找。左右边界怎么进行设置呢???右边界可以设置为min(time)*totalTrips表示最快的车独自完成的时间,左边界可以直接设置为0,也可以设置为min(time)。

class Solution {//时间time内完成的旅途数目long long numsTime(vector<int>& nums,long long time){long long ret=0;for(auto e:nums) ret+=time/e;return ret;}public:long long minimumTime(vector<int>& time, int totalTrips) {//以时间作为二分,时间越长可以完成的旅途越多是单调的//最长时间可以设置为:min(time)*totalTrips即花费最短时间的车辆独自完成时间long long left=0,right=(long long)ranges::min(time)*totalTrips;while(left+1<right){long long mid=left+(right-left)/2;if(numsTime(time,mid)>=totalTrips) right=mid;else left=mid;}return right;}
};

1011. 在 D 天内送达包裹的能力

题解:当运输能力上升时,所需要的时间就在减小所以满足递减,可以使用二分。在下边界世界设置为0即可,上边界设置为:全部包裹是max(weight)的情况下需要的载重能力,即max(weight)*((n-1)/days+1),其中((n-1)/days+1)表示一天至多运输货物的数量;上边界也可以使用所有货物的总重量,表示一天就装完所需的载重能力。

class Solution {//计算运载能力为x时需要的时间long long time(vector<int>& nums,long long x){long long tmp=0,ret=0;for(auto e:nums){if(e>x) return -1;tmp+=e;if(tmp>=x){ret++;tmp=tmp==x?0:e;}}if(tmp) ret++;return ret;}public:int shipWithinDays(vector<int>& weights, int days) {//船运载能力越强所需的时间就越短,是单调递减的可以使用二分来解决int n=weights.size();//右边界设置为如果货物全是weight的最大值当时间为days时需要的运载能力//(n-1)/days+1表示包裹数量除以天数向上取整,即一天至多需要运输多少个包裹long long left=0,right=ranges::max(weights)*((n-1)/days+1);while(left+1<right){long long mid=left+(right-left)/2;int need=time(weights,mid);if(need>0&&need<=days) right=mid;else left=mid;}return right;}
};

875. 爱吃香蕉的珂珂

题解:速度越快需要的时间就越小,单调递减可以使用二分查找;下边界可以使用0表示,上边界使用piles的和表示。

class Solution {long long hours(vector<int>& nums,long long v){long long ret=0;for(auto e:nums)ret+=(e-1)/v+1;return ret;}public:int minEatingSpeed(vector<int>& piles, int h) {//速度越大,所需要的时间越短,单调递减的可以使用二分解决//细节:她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。 说明需要进行向上取整int n=piles.size();//下边界用0来表示,上边界可以用所有的香蕉个数表示long long left=0,right=accumulate(piles.begin(),piles.end(),0LL);while(left+1<right){long long mid=left+(right-left)/2;if(hours(piles,mid)<=h) right=mid;else left=mid;}return right;}
};

3296. 移山所需的最少秒数

题解:当花费的时间越多时高度降低的就越多,所以可以使用二分来找最小值。下边界可以使用0,上边界可以用最快的工人一个人移山所需要的时间。

计算一个工人在t时间内可以降低的高度:

class Solution {//计算所有工人在t内降低的高度long long totalHeight(vector<int>& nums,long long t){long long ret=0;for(auto e:nums) ret+=height(e,t);return ret;}//计算工人在时间t内降低的高度long long height(int worktime,long long t){long long k=t/worktime;long long len=(-1+sqrt(1+8*k))/2;return len;}public:long long minNumberOfSeconds(int mountainHeight, vector<int>& workerTimes) {//当时间越多降低的高度越长,可以使用二分解决long long left=0,right=0;long long heig=0,mintime=ranges::min(workerTimes),each=0;//确定上边界rightwhile(heig<mountainHeight){each+=mintime;right+=each;heig++;}while(left+1<right){long long mid=left+(right-left)/2;if(totalHeight(workerTimes,mid)>=mountainHeight) right=mid;else left=mid;}return right;}
};

475. 供暖器

题解:当半径越大时越满足条件,房屋只存在能供暖和不能供暖两种情况,所以可以使用二分进行查找;对于二分判断是否满足条件不需要考虑太多,直接将设置的x带入题目进行检验即可。

class Solution {//检查当前x时候满足条件bool check(vector<int>& houses,vector<int>& heaters,int x){int n=houses.size(),m=heaters.size();int j=0;for(int i=0;i<n;i++){if(houses[i]>=heaters[j]-x&&houses[i]<=heaters[j]+x) continue;while(j<m&&houses[i]>heaters[j]+x) j++;if(j==m||houses[i]<heaters[j]-x) return false;}return true;}public:int findRadius(vector<int>& houses, vector<int>& heaters) {//先对两个数组进行排序sort(houses.begin(),houses.end());sort(heaters.begin(),heaters.end());int left=-1,right=1000000000;  //设置上下边界while(left+1<right){int mid=left+(right-left)/2;if(check(houses,heaters,mid)) right=mid;else left=mid;}return right;}
};

2594. 修车的最少时间

题解:与上一题类似,依旧是使用二分来解决。先确定上下边界,下边界直接设为0,上边界可以使用最快修理工独自完成所需要的时间。

class Solution {long long check(vector<int>& ranks,long long t){long long ret=0;  //统计修理好的车辆for(auto r:ranks) ret+=sqrt(t/r);  return ret;}public:long long repairCars(vector<int>& ranks, int cars) {//确定上下边界long long left=0,right=0;long long r_min=ranges::min(ranks);right=r_min*cars*cars;while(left+1<right){long long mid=left+(right-left)/2;if(check(ranks,mid)>=cars) right=mid;else left=mid;}return right;}
};

1482. 制作 m 束花所需的最少天数

题解:二分+分组循环;对时间进行二分,下边界使用0,上边界可以使用bloomDay中的最大值;使用check来判断时间t是否满足条件。

class Solution {//检查在t时刻是否满足条件bool check(vector<int>& nums,int m,int k,int t){int i=0,n=nums.size();while(i<n){while(i<n&&nums[i]>t) i++;int start=i++;while(i-start!=k&&i<n&&nums[i]<=t) i++;if(i<=n&&i-start==k) m--;if(m==0) return true;}return false;}public:int minDays(vector<int>& bloomDay, int m, int k) {int n=bloomDay.size();if((long long)k*m>n) return -1;  //数量不够直接返回int left=0,right=ranges::max(bloomDay);  //取上下边界while(left+1<right){int mid=left+(right-left)/2;if(check(bloomDay,m,k,mid)) right=mid;else left=mid;}return right;}
};

3048. 标记所有下标的最早秒数 I

题解:此题难度较大,直接计算时间比较难,但是如果已知答案确定答案是否正确就比较简单,就是二分。标记所有的下标,时间越多越有可能进行标记,所以可以根据时间进行二分。

题意转换:此题可以理解为有n+1场考试[1,n],我们需要对考试进行准备,每一场考试需要准备的时间是确定的,考试可以有多场;根据上面转换后的题意,如果考试越靠后就有更多的时间进行准备,那就可以只准备每门考试的最后一场即可。

代码细节:统计每门考试的最后一场时间,当时间到最后一场时必须进行考试,看前面可以准备的时间够不够即可。

class Solution {//检查时间为t时,是否满足条件bool check(vector<int>& nums,vector<int>& changeIndices,int t){int n=nums.size();vector<int> last_n(n,-1);for(int i=0;i<t;i++)last_n[changeIndices[i]-1]=i;  //存储各个科目最后一次考试时间if(ranges::find(last_n,-1)!=last_n.end()) return false;   //存在没有考试时间的科目int have=0;//i表示时间,changeIndices[i]-1是第几门科目,nums[changeIndices[i]-1]是该门复习需要的时间for(int i=0;i<t;i++){if(i==last_n[changeIndices[i]-1]){if(have<nums[changeIndices[i]-1]) return false;else have-=nums[changeIndices[i]-1];}else have++;}return true;         }public:int earliestSecondToMarkIndices(vector<int>& nums, vector<int>& changeIndices) {int n=nums.size(),m=changeIndices.size();if(n>m) return -1;int left=n-1,right=m+1;  //不能确定时间为m时是否满足条件,但是m+1是一定不满足条件的所以将right置为m+1while(left+1<right){int mid=left+(right-left)/2;if(check(nums,changeIndices,mid)) right=mid;else left=mid;}return right>m?-1:right;}
};

求最小值拓展(浮点型) 

1870. 准时到达的列车最小时速

题解:依旧是二分,但是此题需要特别注意的是小数的处理方式,以及左右边界的处理细节。细节:列车都是整点运行的,所以除了最后一辆列车其他的列车运行时间都要进行向上取整。

class Solution {//检查是否满足条件//因为车都是在整数时间发车的所以要进行向上取整bool check(vector<int>& dist,double hour,int v){int n=dist.size();double total=0;for(int i=0;i<n-1;i++)total+=(dist[i]-1)/v+1;total+=dist[n-1]/(double)v;return total<=hour;}public:int minSpeedOnTime(vector<int>& dist, double hour) {//当速度越大时多需要的时间也短,可以使用二分的方式来求最小速率int n=dist.size();if(n-1>=hour) return -1;  //车次-1时因为最后一次算的是小数而并不需要取整long long left=0,right=ranges::max(dist);  //right用dist中的最大值替代,这样每辆车都只需要行驶一个小时double point=hour-(int)hour;            //如果最后一次出现小数时就需要对最后一次车速进行判断,来确定right是否需要扩大if(point!=0&&dist[n-1]/point>right) right=dist[n-1]/point+1;while(left+1<right){int mid=left+(right-left)/2;if(check(dist,hour,mid)) right=mid;else left=mid;}return right;}
};

3453. 分割正方形 I

题解:易得y一定是存在的,所以此题的难点在于如何确定循环条件。此题以y作为二分基准,当下方面积更大(没有找到准确位置)或者上下面积差在题目范围内(找到了满足条件的位置,但是可能不是最小y )时将right=mid,否则将left=mid;

循环条件应该如何进行设置???

class Solution {//判断以t为分界线是否满足条件bool check(vector<vector<int>>& squares,double t){double down=0,up=0;for(auto& nums:squares){double x=nums[0],y=nums[1],len=nums[2];if(y+len>t)up+= len*min(y+len-t,len);  //注意此处不能直接将len*(y-len-t)其中间可能有空隙if(y<t)down+= len*min(t-y,len);}return up<down||abs(up-down)<=1e-5;  //当下面面积大时right就需要下移,当满足条件时right也下移找最小值}public:double separateSquares(vector<vector<int>>& squares) {double left=0,right=0;for(auto nums: squares)if(nums[1]+nums[2]>right) right=nums[1]+nums[2];for(int i=0;i<48;i++)  //通过计算可以设置循环次数来对数据进行精确{double mid=left+(right-left)/2.0;if(check(squares,mid)) right=mid;else left=mid;}return right;}
};

上面通过计算直接确定了循环的次数,但是如果仍然像之前一样写也是可以的,

for(int i=0;i<48;i++)可以写成while(left+1e-5<right),此写法仍然控制了区间长度不超过1e-5.

但是此处不建议用while本题能够过是因为left和right的值较小,当left值很大的时候left+1e-5的结果可能不再是我们预期的结果,此处与浮点数的存储有关,下面进行简单解释;

存储浮点数的时候会先将浮点数转换为(1.xxxxxxxxxx)*(10^m)的形式在64位下只有52个比特位来存储小数点后面的数据,所以浮点数实际上是不连续的,也就是说1.0的下一个浮点数是1+2^(-52),当这个数越大的时候其下一个浮点数也就越大,所以当left很大时left+1e-5还是left,就会进入死循环。

拓展:此题如果数据范围较小的话,也可以将所有的整数都提升10^5来将浮点数二分转化为整数二分。

二分求最大值

求最大值和求最小值的方法是类似的,只不过判断条件不一样。

275. H 指数 II

题解:数组是单调递增的,当h越大的时候需要的优质论文的个数就越多;所以可以使用二分来找到满足条件的h。假设论文被引用的次数>=h的个数是i,当i>=h时说明满足条件但是不一定是最大的一个让left=mid,当i<h时说明right太大了,所以将right进行缩小right-mid即可。

class Solution {//h表示论文被应用的次数bool check(vector<int>& nums,int h)  {int n=nums.size();int pos=ranges::lower_bound(nums,h)-nums.begin();//判断是否有h个值满足条件return n-pos>=h;}public:int hIndex(vector<int>& citations) {//数据是有序的,可以通过二分来进行查找int n=citations.size();int left=0,right=citations[n-1]+1;while(left+1<right){int mid=left+(right-left)/2;if(check(citations,mid)) left=mid;else right=mid;}return left;}
};

2226. 每个小孩最多能分到多少糖果

题解:当直接求答案比较难的时候,可以考虑用验证法;在已知答案的情况下,对答案的正确性进行验证,就是二分。使用二分先确定一个分到的糖果数,再检验该答案是否正确即可。

class Solution {//能否每人分到x个糖果bool check(vector<int>& nums,long long x,long long k){long long count=0;  //记录能有多少人分到x个糖果for(auto e:nums) count+=e/x;return count>=k;}public:int maximumCandies(vector<int>& candies, long long k) {//直接进行求比较难,但是如果已知答案判断答案是否正确就比较简单了//已知答案就需要考虑二分long long left=0,right=ranges::max(candies)+1;while(left+1<right){long long mid=left+(right-left)/2;if(check(candies,mid,k)) left=mid;else right=mid;}return left;}
};

2982. 找出出现至少三次的最长特殊子字符串 II

当出现了相同子字符串时,第一时间想到的是滑动窗口。用滑动窗口求出每一个相同子串,每个相同字符串又可以进行分割出更多的子字符串,将这些字符串进行统计找出出现三次以上的最长子串。看起来好像可以!!!

class Solution {
public:int maximumLength(string s) {//使用一次滑动窗口unordered_map<string ,int> m;int n=s.size();int i=0;while(i<n){int start=i;while(i<n&&s[start]==s[i]) i++;//此时相同字符串的长度为i-startint len=i-start;string str(s.begin()+start,s.begin()+i);for(int k=len;k>=0;k--)m[str.substr(0,k)]+=len-k+1;  //进行统计}//所有相同的字符串都存储到m中了,找长度最长的并且有3个int ret=-1;for(auto& [str,k]:m){if(k>=3) ret=max(ret,(int)str.size());}return ret;}
};

以上对思路进行实现,但是没有过,是的。因为当相同字符串很长时就会导致map中存储了大量字符串导致最后内存超出限制!!!。

所以需要对代码进行优化,每次统计的时候都是直接把所有的子字符串都统计进去,能不能进行一点裁剪,可以。对for循环进行修改:for(int k=len;k>=len-2&&k>0;k--)只需要统计最长的三个即可,因为如果一个相同字符串长度为len则其满足条件的长度至少为len-2。

class Solution {
public:int maximumLength(string s) {//使用一次滑动窗口unordered_map<string ,int> m;int n=s.size();int i=0;while(i<n){int start=i;while(i<n&&s[start]==s[i]) i++;//此时相同字符串的长度为i-startint len=i-start;string str(s.begin()+start,s.begin()+i);for(int k=len;k>=len-2&&k>0;k--)m[str.substr(0,k)]+=len-k+1;  //进行统计}//所有相同的字符串都存储到m中了,找长度最长的并且有3个int ret=-1;for(auto& [str,k]:m){if(k>=3) ret=max(ret,(int)str.size());}return ret;}
};

方法二:分组循环+二分

统计每个独立的相同字符子串的长度。 

如果字符x的最长字符串为L1,则其可以形成满足条件的最长子串为:L1-2;

如果字符x的次长字符串为L2,则其可以形成满足条件的最长子串为:

当L1==L2,最长子串是:L1-1;

当L1 > L2,最长子串是:L2;

汇总就是:min(L1-1,L2)。

如果字符x的第三长字符串为L3,则其可以形成满足条件的最长子串为:L3

第四长就不需要考虑了,考虑第三长是因为如果三个子字符串的长度相等,长度就是L3。

class Solution {
public:int maximumLength(string s) {unordered_map<char ,vector<int>> m;int i=0,n=s.size();while(i<n){int start=i;while(i<n&&s[i]==s[start]) i++;m[s[start]].push_back(i-start);}int ret=0;for(auto& [ch,nums]:m ){sort(nums.begin(),nums.end(),greater());nums.push_back(0);   //向后面补上两个数据是的数组长度永远大于等于3nums.push_back(0);ret=max({nums[2],min(nums[1],nums[0]-1),nums[0]-2,ret});}return ret==0?-1:ret;}
};

2576. 求出最多标记下标

题解:排序+同向双指针。返回值最大就是数组长度,这种情况就是数组一分为二,数据前半部分与后半部分一一对应;所以可以先对数组进行排序,使用一个指针指向数组中间位置,一个指向数组尾部,判断中间位置数据的两倍是否大于尾部数据,如果大于是一组,否则说明中间数据太大了,向前走找更小的数据。

class Solution {
public:int maxNumOfMarkedIndices(vector<int>& nums) {//先对数组进行排序,再使用同向双指针int n=nums.size();sort(nums.begin(),nums.end());int l=n/2-1,r=n-1,ret=0;while(l>=0&&r>=n/2){if(2*nums[l]<=nums[r]){r--;ret++;}l--;}return ret*2;}
};

1898. 可移除字符的最大数目

题解:模拟+二分。如果直接进行挨个删除效率太低,可以同个二分进行优化。先确定给删除的个数,再验证p是不是s的子序列即可。

class Solution {bool check(string s,string& p,vector<int>& removable,int x){for(int i=0;i<x;i++) s[removable[i]]='0';  //对被删除的位置进行修改int n=s.size(),m=p.size();int j=0;for(int i=0;i<n&&j<m;i++)if(s[i]==p[j]) j++;return j==m;}public:int maximumRemovals(string s, string p, vector<int>& removable) {//如果一个个的进行移除效率太低了//可以使用二分进行优化int n=removable.size();int left=0,right=n+1;while(left+1<right){int mid=left+(right-left)/2;if(check(s,p,removable,mid)) left=mid;else right=mid;}return left;}
};

1802. 有界数组中指定下标处的最大值

题解:当直接进行求解比较难得时候考虑在已知答案得情况下能否进行验证。此题如果直接进行求解比较复杂,如果已知index位置得最大数取判断数组总和是否不超过maxSum就很简单,求和时需要用到数列求和的公式。

class Solution {bool check(int n,int index,long long maxSum,long long t){long long l=index,r=n-index-1;long long all=0;if(t>l) all+=t*(t-1)/2-(t-l-1)*(t-l)/2;else all+=t*(t-1)/2+l-t+1;if(t>r) all+=t*(t-1)/2-(t-r-1)*(t-r)/2;else all+=t*(t-1)/2+r-t+1;return all+t<=maxSum;}public:int maxValue(int n, int index, int maxSum) {//直接进行模拟难度太大,如果已知最大值进行验证就比较简单了int left=0,right=maxSum+1;while(left+1<right){int mid=left+(right-left)/2;if(check(n,index,maxSum,mid)) left=mid;else right=mid;}return left;}
};

1642. 可以到达的最远建筑

题解:在已知到达的高度的情况下,判断砖和梯子是否够即可;细节:为了找到最优解梯子应该使用在需要砖块最多的位置,所以可以使用一个小堆找出使用最多的梯子。

class Solution {
public:int furthestBuilding(vector<int>& heights, int bricks, int ladders) {int n=heights.size();//先将每个房子之间的高度差进行统计vector<int> heidiff(n-1);for(int i=1;i<n;i++) if(heights[i]>heights[i-1]) heidiff[i-1]=heights[i]-heights[i-1];//进行判断auto check=[&](int level){//模拟看能否到达level地方 level-1个间隔long long all=accumulate(heidiff.begin(),heidiff.begin()+level,0L);priority_queue<int,vector<int>,greater<int>> pq;  //找出ladders个最大的数for(int i=0;i<level&&ladders>0;i++) {if(pq.size()<ladders)pq.push(heidiff[i]);else if(pq.top()<heidiff[i]){pq.pop();pq.push(heidiff[i]);}}//进行求和long long more=0;while(!pq.empty()){more+=pq.top();pq.pop();}return all-more<=bricks;};int left=0,right=n;while(left+1<right){int mid=left+(right-left)/2;if(check(mid)) left=mid;else right=mid;}return left;}
};

2861. 最大合金数

题解:依旧是验证答案。通过二分来确定答案,再对答案进行检测即可。如果答案的预算太大right-mid,如果答案预算足够left=mid即可。

class Solution {typedef long long LL;
public:int maxNumberOfAlloys(int n, int k, int budget, vector<vector<int>>& composition, vector<int>& stock, vector<int>& cost) {//判断能否创建ret个合金auto check=[&](LL ret){for(auto& nums:composition){LL sum=0;for(int i=0;i<n;i++)sum+=cost[i]*max(ret*nums[i]-stock[i],(LL)0);if(sum<=budget) return true;}return false;};int left=0,right=1e8*2+1;  //注意此处上界的取值:及要靠你budegt好要考虑stockwhile(left+1<right){int mid=left+(right-left)/2;if(check(mid)) left=mid;else right=mid;}return left;}
};

总结

二分答案的关键是check函数的编写和上下界的判断,以及什么时候能使用二分,二分既能将题目的思路进行转变-----证明一个答案是否正确,还能让时间复杂度大幅度下降。

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

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

相关文章

基于RK3588,飞凌教育品牌推出嵌入式人工智能实验箱EDU-AIoT ELF 2

在AIoT技术驱动产业变革的浪潮中&#xff0c;嵌入式人工智能已成为工业物联网、智慧交通、智慧医疗等领域创新突破的关键引擎。飞凌嵌入式教育品牌ElfBoard立足产业前沿&#xff0c;重磅推出嵌入式人工智能实验箱EDU-AIoT ELF 2&#xff0c;以“软硬协同、产教融合”为设计理念…

51单片机-IO扩展模块 pcf8575

PCF8575介绍 PCF8575 是 NXP&#xff08;原飞利浦半导体&#xff09;生产的一款通用 IC 总线 I/O 扩展器芯片&#xff0c;主要用于微控制器&#xff08;如 Arduino、STM32 等&#xff09;的 I/O 端口扩展。 主要特性 16位并行 I/O 端口&#xff1a;可以配置为输入或输出 IC 总…

Python3 学习(菜鸟)-02基本数据类型

1.多变量赋值 多变量被赋予相同的数值 多变量被赋予不同的数值 2.数值运算 除法 /&#xff1a;返回一个浮点数 除法 //&#xff1a;返回一个整数 3.列表 加号和星号 加号 是列表连接运算符 星号 * 是重复操作 list [ abcd, 786 , 2.23, runoob, 70.2 ] # 定义一个…

『uniapp』搜索功能+商品列表滚动效果(详细图文注释)

目录 预览效果准备工作代码分析与思路1. 页面结构主容器:`menber-container`搜索框:`u-search-inner`菜单:`u-menu-wrap`2. 数据模型`data()` 中的数据定义:3. 生命周期`onLoad(options)``onReady()``mounted()`4. 方法`search()``searchClear()``swichMenu(index)``getElRe…

微服务--消息队列mq

1. mq简介 消息队列是分布式系统中的异步通信中间件&#xff0c;采用"生产者-消费者"模型实现服务间解耦通信 核心作用 服务解耦异步处理流量削峰数据同步最终一致性 消息队列模式 发布/订阅模式&#xff1a;一对多广播工作队列模式&#xff1a;竞争消费死信队列…

第26节 Node.js 事件

Node里很多对象会分发事件&#xff1a; 每次有连接的时候net.Server会分发事件&#xff0c;当文件打开的时候fs.readStream会分发事件。所有能分发事件的对象都是 events.EventEmitter的实例。通过require("events");能访问这个模块。 一般来说&#xff0c;事件名都…

LangChain + MCP + vLLM + Qwen3-32B 构建本地私有化智能体应用

一、私有化智能体应用 在本专栏的前面文章基于Spring AI MCP实现了本地 ChatBI 问答应用&#xff0c;本文还是依据该场景&#xff0c;采用 LangChain vLLM Qwen3-32B MCP 技术栈构建该流程&#xff0c;整体过程如下图所示&#xff1a; 实现效果如下所示&#xff1a; 关于 M…

AKS升级路线最佳实践方案

前言 Kubernetes 社区大约每 4 个月发布次要版本&#xff0c;次要版本包括新增功能和改进。补丁发布更为频繁&#xff08;有时每周都会发布&#xff09;&#xff0c;适用于次要版本中的关键 Bug 修复。修补程序版本包括针对安全漏洞或主要 bug 的修复。对于受支持版本列表以…

树莓派智能小车基本移动实验指导书

1.安装LOBOROBOT库函数 LOBOROBOT.py代码如下&#xff1a; #!/usr/bin/python # -*- coding: utf-8 -*-import time import math import smbus import RPi.GPIO as GPIODir [forward,backward, ]class PCA9685:# Registers/etc.__SUBADR1 0x02__SUBADR2 …

如何对目标检测算法RT-DETR进行创新和改进:突破瓶颈,提升性能!

更多精彩&#xff0c;详见文末~~~ 在目标检测的高速发展中&#xff0c;RT-DETR作为DETR&#xff08;DEtection TRansformer&#xff09;的高效变体&#xff0c;凭借其优异的性能和较快的推理速度&#xff0c;已经成为许多实际应用中的首选算法。然而&#xff0c;尽管RT-DETR在…

Java-String

前言 package com.kjxy.st;public class TestString1 {public static void main(String[] args) {String s1 "hello";String s2 "hello";String s3 new String("hello");String s4 new String("hello");System.out.println(s1 s2…

计算机组成原理——C/存储系统

&#x1f308;个人主页&#xff1a;慢了半拍 &#x1f525; 创作专栏&#xff1a;《史上最强算法分析》 | 《无味生》 |《史上最强C语言讲解》 | 《史上最强C练习解析》|《史上最强C讲解》|《史上最强计组》|《史上最强数据结构》 &#x1f3c6;我的格言&#xff1a;一切只是时…

什么是电输运性能

电输运性能‌是指材料在电场作用下&#xff0c;电子在材料中传输的能力和效率。具体来说&#xff0c;电输运性能包括以下几个方面&#xff1a; ‌电子的自由移动性‌&#xff1a;导体中的电子具有较大的自由移动能力&#xff0c;这是由于导体中的原子或分子结构具有一定的松散…

k3s入门教程(二)部署前后端分离程序

文章目录 部署基础服务部署Redis部署MySQL端口转发测试 运行与构建前后端镜像构建后端镜像 docker build -t ruoyi-admin:v3.8 .构建前端镜像 docker build -t ruoyi-ui:v3.8 .创建私库&#xff0c;推拉镜像 前后端应用部署后端应用部署前端应用部署 启动顺序与初始化容器修改前…

Seata如何与Spring Cloud整合?

&#x1f527; 一、整合核心步骤 1. 启动 Seata Server&#xff08;TC&#xff09; 环境准备&#xff1a; 修改 registry.conf&#xff0c;指定注册中心&#xff08;如 Nacos&#xff09;和配置中心&#xff1a;registry {type "nacos"nacos {serverAddr "l…

Python惰性函数与技术总结-由Deepseek产生

在Python中&#xff0c;惰性&#xff08;Lazy&#xff09;技术指延迟计算直到真正需要结果时才执行&#xff0c;常用于优化内存和性能。以下是常见的惰性函数和技术&#xff1a; 1. 生成器&#xff08;Generators&#xff09; 原理&#xff1a;使用 yield 返回迭代结果&#x…

轮廓 裂缝修复 轮廓修复 填补孔洞 源代码

目录 1. 形态学闭合操作填补小孔洞 完整代码: 使用 Douglas-Peucker 算法对轮廓进行多边形逼近 2.裂缝修复 轮廓修复 轮廓补全 函数封装 调用示例: 1. 形态学闭合操作填补小孔洞 完整代码: import cv2 import numpy as np# 创建模拟图像(白色区域 + 多个不规则黑洞)…

HTTP1.1

HTTP基础知识 HTTP&#xff08;HyperText Transfer Protocol&#xff09;是用于传输超文本 的应用层协议&#xff0c;采用客户端-服务器 模型。 客户端&#xff08;如浏览器&#xff09;发起请求&#xff0c;服务器响应并返回数据。 工作原理 客户端发送HTTP请求至服…

【Linux教程】Linux 生存指南:掌握常用命令,避开致命误操作

Linux 常用操作命令&#xff1a;避免误操作指南 在 Linux 系统中&#xff0c;熟练掌握常用操作命令是高效工作的基础&#xff0c;但同时也要警惕误操作带来的风险。无论是部署程序、配置防火墙、管理端口还是处理进程&#xff0c;一个小小的失误都可能导致系统故障、数据丢失等…

PHP:Web 开发领域的常青树

在当今数字化浪潮中&#xff0c;Web 开发技术日新月异&#xff0c;各种新兴语言和框架层出不穷。然而&#xff0c;PHP 作为一门经典的后端开发语言&#xff0c;依然在 Web 开发领域占据着重要地位&#xff0c;展现出强大的生命力和广泛的应用价值。 PHP 的历史与现状 PHP&…