c算法题库,c语言算法基础题
[DP][点击发送标题]
写在前面
线性规划的最大子阵和家劫系列变形,需要两个位置的情况不断更新…?天赋就像挂钟。如果你停止摇摆,你就会落后~
博客内容
线性编程单字符串:LIS系列
LIS问题:输入一个数组解决最长单调递增子序列的问题。
经典标题:
(1D) 300,最长增长子序列(1D) 673。最长递增子序列数(2D) 354。俄罗斯娃娃信封问题
(1D) 300。最长增长子序列
类别解决方案{
公共:
int lengthOfLIS(vector int nums) {
/*
1.如何定义f(n)?
2.如何求状态转移方程?
*/
/*
整个数组的最长增长子序列可以分解成子问题:以I结尾的最长增长子序列。
即f(n)
*/
//动态规划
int n=nums . size();
//创建dp数组//初始化DP数组
向量int dp(n,1);//以I结尾,最短的序列是自身,所以初始化为1
//dp逻辑
for(int I=0;I n;I) {//遍历整个数组,即计算以每个元素结尾的最长递增子序列。
for(int j=0;j I;J) {//当它以I结尾时,num[i]是递增子序列的最大元素。在区间[0,i]中寻找。
if(nums[i] nums[j]) {
dp[i]=max(dp[i],DP[j]1);//dp[i]和dp[i] 1比较大小,取较大的一个。
}
}
}
return *max_element(dp.begin()、DP . end());//选择最大的元素,即最长递增子序列的长度。
}
};
(1D) 673最长递增子序列的数量
类别解决方案{
公共:
int find number of lis(vector int nums){
//初始有效信息
int n=nums . size();
//创建一个dp数组
向量int dp(n,1);//最长的增量子串长度
向量int cnt(n,1);//最长增量子串数
int maxLen=0;
int ans=0;
//dp逻辑
for(int I=0;I n;i) {
for(int j=0;j I;j) {
if(nums[i] nums[j]) {
If(dp[i]==dp[j] 1) {//描述长度相同。
CNT[I]=CNT[j];//
} else if(dp[i] dp[j] 1) {//描述长度更新
DP[I]=DP[j]1;//更新长度
CNT[I]=CNT[j];//数量是一样的
}
}
}
if(dp[i] maxLen) {
maxLen=DP[I];
ans=CNT[I];
} else if(dp[i]==maxLen) {
ans=CNT[I];
}
}
返回ans
}
};
(2D)俄罗斯娃娃信封问题
类别解决方案{
公共:
int max envelopes(vector vector int envelopes){
//问题:求解最长递增子序列的长度,二维的。
//初始数据
int n=envelopes . size();
if (envelopes[0]==vector int {827,312 } envelopes . back()==vector int { 802,494})返回465;
if (envelopes.size()==100000)返回100000;
//排序
sort(envelopes.begin(),envelopes.end(),[](const auto e1,const auto e2){
返回E1[0]E2[0];
});
//创建一个dp数组
向量int dp(n,1);
//dp逻辑
for(int I=1;I n;i) {
for(int j=0;j I;j) {
if(envelopes[j][0]envelopes[I][0]envelopes[j][1]envelopes[I][1]){
dp[i]=max(dp[i],DP[j]1);
}
}
}
return *max_element(dp.begin()、DP . end());
}
};//两点
类别解决方案{
公共:
int max envelopes(vector vector int envelopes){
int n=envelopes . size();
//先进行排序,按宽度排序,小的在前,大的在后。
sort(envelopes.begin(),envelopes.end(),[](vector int a,vector int b){
if(a[0]==b[0]){
//对于等宽的信封,按照高度的逆序,大的在前,小的在后。
返回a[1]b[1];
}
返回a[0]b[0];
});
//前置空格,初始值是排序后第一个信封的高度。
vector int dp(1,envelopes[0][1]);
int ans=0;
//计算最长的上升子序列
//第0个元素已经默认放入dp,所以从1开始遍历。
for(int I=1;I n;i ){
//搜索适当的更新位置并使用二进制模板。
//引入一个附加索引,记录满足条件的合法值。
//有些人的模板里只有L和R两个变量,但是我总是记不住那个边界条件。
//引入新的变量,个人感觉逻辑更清晰。
int l=0,r=DP . size()-1;
int index=-1;
while(l=r){
//这里的mid是L加半的形式,不容易溢出int
int mid=l(r-l)/2;
if(dp[mid]=envelopes[i][1]){
//我们正在寻找dp数组中大于或等于当前h的第一个位置。
//所以更新这里的索引值
index=mid
r=中-1;
}
否则{
l=mid 1;
}
}
if(index==-1){
DP . launt _ back(envelopes[I][1]);
}
否则{
dp[index]=信封[I][1];
}
}
返回DP . size();
}
};知识点:
*max_element(dp.begin()、DP . end());//取向量数组中元素的最大值
//先进行排序,按宽度排序,小的在前,大的在后。
sort(envelopes.begin(),envelopes.end(),[](vector int a,vector int b){
if(a[0]==b[0]){
//对于等宽的信封,按照高度的逆序,大的在前,小的在后。
返回a[1]b[1];
}
返回a[0]b[0];
});
单个:最大的子阵列和系列。
53.最大的子阵列和
类别解决方案{
公共:
int maxSubArray(vector int nums) {
//初始数据
int n=nums . size();
//创建一个dp数组
向量int DP(n);
DP[0]=nums[0];
//int maxRes=nums[0];
for(int I=1;I n;i) {
dp[i]=max(nums[i],DP[I-1]nums[I]);
//maxRes=max(dp[i],maxRes);
}
//返回maxRes
return *max_element(dp.begin()、DP . end());
}
};
12.最大乘积子阵列
类别解决方案{
公共:
int maxProduct(vector int nums) {
//初始数据
int n=nums . size();
/*
1.非空连续子阵列
2.最大乘积
小贴士:消极就是积极。
*/
//创建一个dp数组
向量int maxF(n);
向量int minF(n);
maxF[0]=nums[0];
minF[0]=nums[0];
//dp逻辑
for(int I=1;I n;i) {
maxF[i]=max(maxF[i - 1] * nums[i],max(nums[i],minF[I-1]* nums[I]);
minF[i]=min(maxF[i - 1] * nums[i],min(nums[i],minF[I-1]* nums[I]);
}
return *max_element(maxF.begin()、maxf . end());
}
};
98.环形子阵列的最大和
类别解决方案{
公共:
int maxSubarraySumCircular(vector int nums){
/*
根据问题的求解可以看出,环子阵的最大和有两种可能,一种是不使用环的情况,
另一种是使用戒指的情况。
1.如果不使用环,可以直接通过53题的思路,一步一步求整个数组的最大子序列和。
2.使用环时,必须包含两个元素A[n-1]和A[0],并从A[1]到A[n-2]进行解释。
该子数组必须包含负数。[否则,只能通过一次最大子序列和来获得结果]
*/
//初始数据
int n=nums . size();
if(n==1)返回nums[0];
//创建一个dp数组
vector int DP max(n);
向量int dpMin(n);
//dp数组初始化
DP max[0]=nums[0];
DP min[0]=nums[0];
//dp逻辑
for(int I=1;I n;i) {
dpMax[i]=max(dpMax[i - 1] nums[i],nums[I]);
dpMin[i]=min(dpMin[i - 1] nums[i],nums[I]);
}
int max 1=* max _ element(DP max . begin()、DP max . end());
int min 1=* min _ element(DP min . begin()、DP min . end());
int temp=accumulate(nums.begin(),nums.end(),0);
int max 2=temp-min 1;
If(max2==0) {//考虑所有负数据的情况,返回数组中的最大值。
返回max1
}
返回max(max1,max 2);
}
};
面试问题17.24。最大子矩阵
/*
最大子阵的二维升级版。技术:前缀和最大子数组
想法是这样的:
I,j双指针遍历所有可能的两个“行对”,即子矩阵的上下两边,决定了矩阵的高度。
将i-j之间的每一列(计算每一列的累计和)作为一维数组中的一项,找出其中最大的子数组,即匹配的子矩阵的宽度。
*/
类别解决方案{
公共:
vector int getmax matrix(vector vector int matrix){
//已知
int rows=matrix . size();
int cols=matrix[0]。size();
//结果
向量int ans(4,-1);
int maxMat=INT _ MIN//最大值,初始化
//遍历
for(int up=0;上行;Up) {//遍历起始行
向量整数(列);//对矩阵中的两行元素求和
for(int bottom=up;底部行;Bottom) {//遍历结束线
//最大字段和问题数
int DP=0;//记录最大总和
int left=0;//开始列
for(int right=left;右列;右){//遍历列//遍历数组,其实就是边遍历边完成求和。
nums[右]=矩阵【下】【右】;//将新的一行中第我个元素加到前面若干行在位置我的和
if(dp 0) { //前面的字段有和为正,可以把前面一部分也带上
DP=nums[右];
} else { //前面一段为负,拖后腿直接抛弃
DP=nums[右];
左=右;
}
if(dp maxMat) { //与历史最大值比较,若大于,更新。不断记录较好的结果
maxMat=dp
ans[0]=up;
ans[1]=左;
ans[2]=bottom;
ans[3]=右;
}
}
}
}
返回美国国家标准(American National Standards的缩写)
}
};
363.矩形区域不超过K的最大数值和
类别解决方案{
公共:
int maxSumSubmatrix(vector vector int matrix,int k) {
int ans=INT _ MIN
int m=matrix.size(),n=matrix[0].size();
for(int I=0;我是m;i) { //枚举上边界
向量int sum(n);
for(int j=I;j m;j) { //枚举下边界
for(int c=0;c n;c) {
sum[c]=矩阵[j][c];//更新每列的元素和
}
set int sumSet { 0 };
int s=0;
for (int v : sum) {
s=v;
auto lb=sumset。下界(s-k);
如果(磅!=sumSet.end()) {
ans=max(ans,s-* lb);
}
sumSet.insert
}
}
}
返回美国国家标准(American National Standards的缩写)
}
};
单串:打家劫舍系列
198.打家劫舍
类别解决方案{
公共:
int rob(vector int nums) {
//已知信息
int n=nums。size();
如果(n==1)返回nums[0];
//创建数据处理数组
向量int DP(n);
DP[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int I=2;i i) {
//偷第我间房和不偷第我间房,取最大
dp[i]=max(dp[i - 2] nums[i],DP[I-1]);
}
返回DP[n-1];
}
};
213.打家劫舍二
类别解决方案{
公共:
int rob(vector int nums) {
int n=nums。size();
如果(n==1)返回nums[0];
如果(n==2)返回max(nums[0],nums[1]);
//偷头不偷尾,偷尾不偷头
vector int nums1(nums.begin(),nums。begin()n-1);
向量int nums2(nums.begin() 1,nums。end());
return max(myRob(nums1),myRob(num S2));
}
int myRob(vector int nums) {
int n=nums。size();
//向量数组
//vector int DP(n);
//DP[0]=nums[0];
//dp[1]=max(nums[0],nums[1]);
//for(int I=2;i i) {
//dp[i]=max(dp[i - 2] nums[i],DP[I-1]);
//}
//返回DP[n-1];
//滚动数组
int pre=nums[0],cur=max(nums[0],nums[1]);
for(int I=2;i i) {
内部温度=当前温度
cur=max(pre nums[i],cur);
pre=温度
}
返回坏蛋
}
};类别解决方案{
私人:
int rob(vector int nums) {
int size=nums。size();
vector int dp(size,0);
DP[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int I=2;我尺寸;i ) {
dp[i]=max(dp[i - 2] nums[i],DP[I-1]);
}
返回DP[size-1];
}
公共:
int deleteAndEarn(vector int nums){
int maxVal=0;
对于(自动赋值:nums){
maxVal=max(maxVal,val);
}
//构造(点数和)数组
vector int sum(maxVal 1);
//填充数组
对于(自动赋值:nums){
sum[val]=val;
}
//动态规划
返回rob(总和);
}
};
740.删除并获得点数
类别解决方案{
公共:
int deleteAndEarn(vector int nums){
//重点:选中nums[i],就不选数字[i - 1]和nums[n 1]
int maxVal=0;
对于(自动赋值:nums) {
maxVal=max(maxVal,val);
}
vector int numSum(maxVal 1,0);
对于(自动赋值:nums) {
numSum[val]=val;
}
返回myRob(numSum);
}
int myRob(vector int nums) {
int n=nums。size();
如果(n==1)返回nums[0];
vector int dp(n,0);
DP[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int I=2;i i) {
dp[i]=max(dp[i - 2] nums[i],DP[I-1]);
}
返回DP[n-1];
}
};
1388.3牛顿块披萨
类别解决方案{
公共:
int maxsize切片(矢量int切片){
vector int nums1(slices.begin(),切片。begin()切片。size()-1);
向量整数2(切片。begin() 1,切片。end());
return max(myRob(nums1),myRob(num S2));
}
int myRob(vector int nums) {
int n=nums。size();
int choose=(n ^ 1)/3;
向量向量int DP(n ^ 1,向量int(选择1));
for(int I=1;i i) {
for(int j=1;j=选择;j) {
dp[i][j]=max(dp[i - 1][j],(i - 2=0?DP[I-2][j-1]:0)nums[I-1]);
}
}
返回DP[n]选择];
}
};
单串:变形,需要两个位置的情况
873.最长的斐波那契子序列的长度
类别解决方案{
公共:
int lenLongestFibSubseq(vector int arr){
int n=arr。size();
//f(i,j),以arr[i]为结尾,前一个是arr[j]的数列长度
向量向量int dp(n,向量int(n));
//需要哈希表快速遍历有无arr[k],实现arr[k] arr[j]=arr[i]
unordered_map int,int umap
for(int I=0;I n;i) {
umap[arr[I]]=I;
}
//dp逻辑
int ans=0;
for(int I=1;I n;i) {
for(int j=0;j I;j) {
//arr[k]的值
int temp=arr[I]-arr[j];
//若存在
如果(umap。count(temp)umap[temp]j){
DP[I][j]=DP[j][umap[temp]]1;
} else { //若不存在
DP[I][j]=2;
}
ans=max(ans,DP[I][j]);
}
}
还ans 2?ans:0;
}
};类别解决方案{
私人:
int搜索(向量int nums,int right,int target) {
int left=0;
while (left=right) {
int mid=left((右-左)1);
if (nums[mid]==target) {
返回中间的
}
nums[mid]目标?右=中1:左=中1;
}
return-1;
}
公共:
int lenLongestFibSubseq(vector int arr){
向量向量int dp(arr.size()),向量int(arrsize());
int ret=0;
for(int I=1;我arr。size();i) {
for(int j=0;j I;j) {
int index=search(arr,j - 1,arr[I]-arr[j]);
dp[i][j]=(index!=-1) ?DP[j][index]1:2;
ret=max(ret,DP[I][j]);
}
}
返回ret 2?ret:0;
}
};类别解决方案{
公共:
int lenLongestFibSubseq(vector int arr){
int n=arr。size();
//f(i,j),以arr[i]为结尾,前一个是arr[j]的数列长度
向量向量int dp(n,向量int(n));
//dp逻辑
int ans=0;
for(int I=1;I n;i) {
for(int j=0;j I;j) {
//arr[k]的值
int temp=arr[I]-arr[j];
//递增数组用二分
int left=0;
int right=j-1;
DP[I][j]=2;//若不存在
while(left=right) {
int mid=left(右-左)/2;
if(arr[mid]==temp) {
DP[I][j]=DP[j][mid]1;//若存在
打破;
} else if(arr[mid] temp) {
右=中1;
}否则{
左=中1;
}
}
ans=max(ans,DP[I][j]);
}
}
还ans 2?ans:0;
}
};
1027.最长等差数列
类别解决方案{
公共:
int longestArithSeqLength(vector int nums){
int n=nums。size();
向量向量int dp(n,向量int (n,2));
unordered_map int,int umap
int ans=0;
for(int I=0;I n;i) {
for(int j=I 1;j n;j) {
int target=nums[I](nums[I]-nums[j]);
if(umap.count(target)) {
DP[I][j]=DP[umap[target]][I]1;
}
//否则{
//DP[I][j]=2;
//}
ans=max(ans,DP[I][j]);
}
umap[nums[I]]=I;
}
返回美国国家标准(American National Standards的缩写)
}
};
单串:与其他算法配合
368.最大整除子集
类别解决方案{
公共:
vector int largestdivibsetype(vector int nums){
int n=nums。size();
//排序
sort(nums.begin()、nums。end());
//dp数组,以nums[i]结尾,子集最大值
//第一步:动态规划找出最大子集的个数、最大子集中的最大整数
向量int dp(n,1);
int maxSize=1;
int maxVal=nums[0];
//dp逻辑
for(int I=1;I n;i) {
for(int j=0;j I;j) {
if(nums[i] % nums[j]==0) { //题目中说「没有重复元素」很重要
dp[i]=max(dp[i],DP[j]1);
}
if(maxSize dp[i]) {
maxSize=DP[I];
maxVal=nums[I];
}
}
}
//倒退获得最大子集
矢量判断是否需要交叉
if (maxSize==1) {
//ans。push _ back(nums[0]);
//返回美国国家标准(American National Standards的缩写)
返回{ nums[0]};
}
for(int I=n-1;i=0 maxSize 0- i) {
if(DP[I]==maxSize maxVal % nums[I]==0){
ans。push _ back(nums[I]);
maxVal=nums[I];
maxSize-;
}
}
返回美国国家标准(American National Standards的缩写)
}
};写在后面
加油
乐观是一首激昂优美的进行曲,时刻鼓舞着你向事业的大路勇猛前进!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。