leetcode刷题记录2021年4月23日

363. 矩形区域不超过 K 的最大数值和

第一道昨天做的
我直接暴力求的,没有去进行进一步有优化,有机会再去研究吧,用到的是二维前缀和的思想,就不多说了。

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
        //能优化 状态不好 不想做了 以后再说
        int m=matrix.size(),n=matrix[0].size();
        int sum[m+1][n+1];
        sum[0][0]=0;
        for(int i=0;i<n+1;i++)sum[0][i]=0;
        for(int j=0;j<m+1;j++)sum[j][0]=0;
        for(int i=1;i<m+1;i++)
        {
            for(int j=1;j<n+1;j++)
            {
                //cout<<i<<' '<<j<<endl;
                sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+matrix[i-1][j-1];
                //cout<<sum[i][j]<<' ';
            }
            //cout<<endl;
        }

        int res=INT_MIN;
        for(int ui=0;ui<m;ui++)
            for(int uj=0;uj<n;uj++)
                for(int di=ui;di<m;di++)
                    for(int dj=uj;dj<n;dj++)
                    {
                        int sub_sum = sum[di+1][dj+1]-sum[di+1][uj]-sum[ui][dj+1]+sum[ui][uj];
                        //cout<<ui<<' '<<uj<<' '<<di<<' '<<dj<<' '<<sub_sum<<endl;
                        if(sub_sum <= k && sub_sum > res)
                        {
                            res = sub_sum;
                        }
                    }
        return res;
    }
};

368. 最大整除子集

自力更生动态规划第二集,希望继续保持。。。

这题我一开始思路的暴力搜索,枚举所有的情况,结果超时了,后来意识到可以动态规划。暴力搜没啥好说的

class Solution {
public:
    vector<int> res;
    vector<int> tmp;
    vector<int> largestDivisibleSubset(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size();i++)
            dfs(nums,i);
        return res;
    }
    void dfs(vector<int>& nums,int idx)
    {
        if(idx > nums.size())
        {
            if(tmp.size()>res.size())
            {
                res = tmp;
            }
            return;
        }
        int top = tmp.size()==0?1:tmp[tmp.size()-1];
        bool pan=false;
        for(int i=idx;i<nums.size();i++)
        {
            if(nums[i]%top == 0)
            {
                pan = true;
                tmp.push_back(nums[i]);
                dfs(nums,i+1);
                tmp.pop_back();
            }
        }
        if(pan == false)
        {
            if(tmp.size()>res.size())
            {
                res = tmp;
            }
            return;
        }
    }
};

还是详细讲讲动态规划的思路吧,其实做的还是挺艰难的,什么时候提升到中等能很快的一次过就好了。。。

整除有一个传递的特性,因此对于一个整除子集,只要某一个数能够整除这个子集里最大的一个数,那么就可以把这个数放进整除子集里,基于这种想法,我们先对数组排个序,然后从头到尾遍历。
首先当然是子问题和状态转移方程,这里的子问题不同于常规的那种,它加了一个条件:dp[i]代表以nums[i-1]为结尾的[0,i-1]区间的最大整除子集的大小,那么dp[0]=0,为了计算,我们保存一个top数组,代表dp[i]代表的最大整除子集的最大的元素,这样的话就有状态转移方程了:
dp[i] = max(dp[j])(0<=j<=i-1&&nums[i-1]%top[j]==0)
这让就能求出最大长度了,只要再加一个back_up数组,保存dp的变化轨迹,就能够回溯出结果数组了。

class Solution {
public:
    vector<int> res;
    vector<int> largestDivisibleSubset(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<int> top(nums.size()+1);
        vector<int> dp(nums.size()+1);
        vector<int> back_up(nums.size()+1);

        dp[0]=0;
        back_up[0]=-1;
        top[0]=1;

        for(int i=1;i<dp.size();i++)
        {
            dp[i] = -1;
            for(int j=0;j<i;j++)
            {
                //cout<<i<<' '<<j<<endl;
                if(dp[j]>=dp[i] && nums[i-1]%top[j] == 0)
                {
                    dp[i] = dp[j];
                    back_up[i] = j;
                    top[i] = nums[i-1];
                }
            }
            dp[i]++;
        }
        /*for(int i=0;i<dp.size();i++)
            cout<<dp[i]<<' ';
        cout<<endl;
        for(int i=0;i<dp.size();i++)
            cout<<back_up[i]<<' ';
        cout<<endl;
        for(int i=0;i<dp.size();i++)
            cout<<top[i]<<' ';
        cout<<endl;*/
        int end = 0;
        for(int i=0;i<dp.size();i++)
        {
            if(dp[i] > dp[end])
            {
                end = i;
            }
        }
        int start = end;
        while(start!=0)
        {
            //cout<<start<<' ';
            res.push_back(nums[start-1]);
            start = back_up[start];
        }
        reverse(res.begin(),res.end());
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值