LeetCode 第28場雙週賽

商品折扣後的最終價格 子矩形查詢 找兩個和爲目標值且不重疊的子數組 安排郵筒
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];
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章