商品折扣後的最終價格 | 子矩形查詢 | 找兩個和爲目標值且不重疊的子數組 | 安排郵筒 |
---|---|---|---|
3分 簡單 | 4分 中等 | 5分 中等 | 6分 困難 |
1475 商品折扣後的最終價格
用結構體node存商品,index爲第i件商品,val是價格
從0到n,依次將商品丟入優先隊列按價格從大到小排,每次隊首的價格大於等於當前第i件商品的價格時,此時(now.val-prices[i])爲題目所要求的最終需要支付的價格,然後將隊首元素彈出
class Solution { struct node{ int index,val; bool operator<(const node&b)const{ return val<b.val; } }; public: vector<int> finalPrices(vector<int>& prices) { int n=prices.size(); if(n==0) return prices; priority_queue<node>Q; vector<int>ans(n,0); node now; now.index=0; now.val=prices[0]; Q.push(now); for(int i=1;i<n;i++){ while(!Q.empty()&&Q.top().val>=prices[i]){ now=Q.top(); ans[now.index]=(now.val-prices[i]); Q.pop(); } now.index=i; now.val=prices[i]; Q.push(now); } while(!Q.empty()){ now=Q.top(); ans[now.index]=now.val; Q.pop(); } return ans; } };
1476 子矩形查詢
題目沒要求最優的複雜度,只是按照題意最簡單暴力地更新,求值
class SubrectangleQueries { public: SubrectangleQueries(vector<vector<int>>& rectangle) { rec=rectangle; row=rectangle.size(); col=rectangle[0].size(); } void updateSubrectangle(int row1, int col1, int row2, int col2, int newValue) { for(int i=row1;i<=row2;i++){ for(int j=col1;j<=col2;j++){ rec[i][j]=newValue; } } } int getValue(int row, int col) { return rec[row][col]; } vector<vector<int>> rec; int row,col; };
1477 找兩個和爲目標值且不重疊的子數組
滑動窗口,寫的有點搓
mi[i]爲從左到右,到i的滿足要求的一個子數組長度的 最小值
mi_R[i]爲從右到左,到i的滿足要求的一個子數組長度的 最小值
所以答案就是min(mi[i-1]+mi_R[i])
注意考慮不存在的情況,最小值爲-1
class Solution { public: int minSumOfLengths(vector<int>& arr, int target) { int n=arr.size(); vector<int>mi(n,-1); vector<int>mi_R(n,-1); int len=0,sum=0; for(int i=0;i<n;i++){ len++; sum+=arr[i]; if(sum>target){ while(sum>target){ sum-=arr[i-len+1]; len--; } } if(sum==target){ mi[i]=len; if(i>0&&mi[i-1]!=-1&&mi[i-1]<mi[i]) mi[i]=mi[i-1]; } else{ if(i>0&&mi[i-1]!=-1) mi[i]=mi[i-1]; } } len=sum=0; int ans=-1; for(int i=n-1;i>=0;i--){ len++; sum+=arr[i]; if(sum>target){ while(sum>target){ sum-=arr[i+len-1]; len--; } } if(sum==target){ mi_R[i]=len; if(i<n-1&&mi_R[i+1]!=-1&&mi_R[i+1]<mi_R[i]) mi_R[i]=mi_R[i+1]; } else{ if(i<n-1&&mi_R[i+1]!=-1) mi_R[i]=mi_R[i+1]; } if(i>0&&mi_R[i]!=-1&&mi[i-1]!=-1){ if(ans==-1) ans=mi_R[i]+mi[i-1]; else ans=min(ans,mi_R[i]+mi[i-1]); } } return ans; } };
1478 安排郵筒
轉化下題意,其實就是讓我們求將n個點分成k條線段的最小貢獻,就是最簡單的DP
討論下一條線段的貢獻怎麼求
分奇偶討論:
1)奇數情況,如1,2,3,4,5 五個點 .把五個點視爲在同一條線段中,郵筒可以設置在對中間的點,此時的距離和是最小的,貢獻是(1和5之間的距離)+(2和4之間的距離),對應爲下列代碼
int right=sum[i]-sum[k+len/2+1]; int left=sum[k+len/2]-sum[k]; (right-left)即該線段的貢獻
sum[]表示前綴和,i爲線段右端點,k+1爲線段左端點,len爲線段長度
2)偶數情況,類似.郵筒可以設置在最中間的兩點之間的任意位置
int right=sum[i]-sum[k+len/2]; int left=sum[k+len/2]-sum[k]; (right-left)即該線段的貢獻
class Solution { public: int minDistance(vector<int>& houses, int k) { int n=houses.size(); sort(houses.begin(),houses.end()); vector<int>h(n+1,0); vector<int>sum(n+1,0); for(int i=1;i<=n;i++){ h[i]=houses[i-1]; sum[i]=sum[i-1]+h[i]; } int f[105][105]; memset(f,0x3f,sizeof(f)); f[0][0]=0; for(int i=1;i<=n;i++){ for(int j=1;j<=k;j++){ for(int k=i-1;k>=0;k--){ int len=i-k; if(len&1){ int right=sum[i]-sum[k+len/2+1]; int left=sum[k+len/2]-sum[k]; f[i][j]=min(f[i][j],f[k][j-1]+(right-left)); } else{ int right=sum[i]-sum[k+len/2]; int left=sum[k+len/2]-sum[k]; f[i][j]=min(f[i][j],f[k][j-1]+(right-left)); } } } } return f[n][k]; } };