279完全平方数;300最长上升子序列;304 二维区域和检索 - 矩阵不可变;338比特位计数

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

示例 1:

输入: n = 12
输出: 3 
解释: 12 = 4 + 4 + 4.

示例 2:

输入: n = 13
输出: 2
解释: 13 = 4 + 9.

class Solution {//动态规划 一维
public:
    int numSquares(int n) {
        vector<int> dp(n+1);
        dp[0]=0;
        dp[1]=1;
        for(int i=2;i<=n;++i){
            int minN=INT_MAX;
            for(int j=1,temp=1;temp<=i;++j,temp=j*j){
                minN=min(dp[i-temp],minN);
            }
            dp[i]=minN+1;
        }
        return dp[n];
    }
};

 

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:


    可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
    你算法的时间复杂度应该为 O(n2) 。


进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int nSize=nums.size();
        if(nSize<=1)return nSize;
        vector<int> dp(nSize,0);
        int resMax=0,maxN;
        dp[0]=1;
        for(int i=1;i<nSize;++i){
            maxN=0;
            for(int j=0;j<i;++j)
                if(nums[j]<nums[i])
                    maxN=max(maxN,dp[j]);            
            dp[i]=maxN+1;
            resMax=max(dp[i],resMax);
        }
        //return dp[nSize-1];  //错误
        return resMax;
    }
};
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {//nlogn 二分查找
        int nSize=nums.size();
        if(nSize<=1)return nSize;
        vector<int> dp(nSize+1,0);
        dp[1]=nums[0];
        int cur=1;//dp下标表示子序列最长长度;dp数据表示该下标/最长长度对应的末尾数字的最小值
        for(int i=1;i<nSize;++i){
            if(nums[i]>dp[cur])
                dp[++cur]=nums[i];
            else{
                int le=1,ri=cur,pos=0;
                while(le<=ri){//二分查找dp数据从左往右最后一个小于nums[i]的下标
                    int mid=le+((ri-le)>>1);
                    if(dp[mid]<nums[i]){
                        pos=mid;
                        le=mid+1;
                    }
                    else
                        ri=mid-1;
                }
                dp[pos+1]=nums[i];
            }
        }
        return cur;
    }
};
/*二分查找最后一个/第一个 </<= >/>=的位置
0,1,2,3,4,5,6,7,8,9
2,2,2,2,3,3,4,4,6,6*/
le=0,ri=9;
//最后一个index使得nums[index]</<=target	
int pos=-1;
while(le<=ri){
    int mid=(le+ri)>>1;
    if(nums[mid]</<=target)
    pos=mid,le=mid+1;
    else ri=mid-1;
}
return pos;
//第一个index使得nums[index]>/>=target
int pos=-1;
while(le<=ri){
    int mid=(le+ri)>>1;
    if(nums[mid]>/>=target)
    pos=mid,ri=mid-1;
    else le=mid+1;
}
return pos;

给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2)。


上图子矩阵左上角 (row1, col1) = (2, 1) ,右下角(row2, col2) = (4, 3),该子矩形内元素的总和为 8。

示例:

给定 matrix = [
  [3, 0, 1, 4, 2],
  [5, 6, 3, 2, 1],
  [1, 2, 0, 1, 5],
  [4, 1, 0, 1, 7],
  [1, 0, 3, 0, 5]
]

sumRegion(2, 1, 4, 3) -> 8
sumRegion(1, 1, 2, 2) -> 11
sumRegion(1, 2, 2, 4) -> 12


说明:


    你可以假设矩阵不可变。
    会多次调用 sumRegion 方法。
    你可以假设 row1 ≤ row2 且 col1 ≤ col2。

class NumMatrix {
public:
    vector<vector<int>> dp;
    int mSize,nSize;
    NumMatrix(vector<vector<int>>& matrix) {
        mSize=matrix.size();
        if(mSize){
            nSize=matrix[0].size(); 
            if(nSize){
                this->dp=matrix;
                for(int i=1;i<nSize;++i)
                    dp[0][i]+=dp[0][i-1];
                for(int i=1;i<mSize;++i){
                    dp[i][0]+=dp[i-1][0];
                    for(int j=1;j<nSize;++j)
                        dp[i][j]=dp[i][j]+dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1];
                }        
            }       
        }
    }
    
    int sumRegion(int row1, int col1, int row2, int col2) {//讨论繁琐可dp增加一行一列数据如后面所示
        if(row1==0&&col1==0)return dp[row2][col2];
        else if(row1==0)return dp[row2][col2]-dp[row2][col1-1];
        else if(col1==0)return dp[row2][col2]-dp[row1-1][col2];
        else return dp[row2][col2]+dp[row1-1][col1-1]-dp[row2][col1-1]-dp[row1-1][col2];
    }
};
class NumMatrix {
private:
    vector<vector<int>> prefix;
public:
    NumMatrix(vector<vector<int>>& matrix) {
        if(matrix.empty())return;//构造函数可return
        int m=matrix.size(),n=matrix[0].size();
        prefix.resize(m+1,vector<int>(n+1,0));//多一行一列
        for(int i=1;i<=m;++i){
            for(int j=1;j<=n;++j){
                prefix[i][j]=prefix[i-1][j]+prefix[i][j-1]-prefix[i-1][j-1]+matrix[i-1][j-1];//matrix[i-1][j-1]对应prefix[i][j]
            }
        }
    }
    
    int sumRegion(int row1, int col1, int row2, int col2) {
        if(prefix.empty())return 0;
        return prefix[row2+1][col2+1]-prefix[row2+1][col1]-prefix[row1][col2+1]+prefix[row1][col1];
    }
};

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。

示例 1:

输入: 2
输出: [0,1,1]

示例 2:

输入: 5
输出: [0,1,1,2,1,2]

进阶:


    给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?
    要求算法的空间复杂度为O(n)。
    你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。

class Solution {//dp[i]=dp["去掉i最左边的1剩下的值"]+1
public:
    vector<int> countBits(int num) {
        vector<int> dp(num+1,0);
        for(int i=1,lastD=0;i<=num;++i){
            if((i&(i-1))==0)//2次幂
                dp[i]=1,lastD=i;//lastD记录上一个2次幂的下标
            else
                dp[i]=dp[i-lastD]+1;//例如2^3<13<2^4,dp[13]=dp[13-2^3]+1;
        }
        return dp;
    }
};
class Solution {//dp[i]=dp["去掉i最右边的1剩下的值"]+1
public:
    vector<int> countBits(int num) {
        vector<int> dp(num+1,0);
        for(int i=1;i<=num;++i)
            dp[i]=dp[i&(i-1)]+1;
        return dp;
    }
};
class Solution {//dp[i]=dp["去掉i第0位值剩下的值"]+dp["i第0位的值"]
public:
    vector<int> countBits(int num) {
        if(num==0)return vector<int>{0};
        vector<int> dp(num+1,0);
        dp[1]=1;
        for(int i=1;i<=num;++i)
            dp[i]=dp[i>>1]+dp[i%2];
        return dp;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值