题意:一个数组,找到和最大的子串
我记得好像On的动态规划来做的?但是想不起来了,先死做,用的前缀和——TLE超时
那就只能想想dp怎么做了
假设dp[i]表示的是以 i 为右端点的最大的子串,dp[0]是自己;
i=1时,如果dp[0]小于0,dp[1]=nums[1],否则dp[1]=dp[0]+nums[1]
i=2时,如果dp[1]小于0,dp[2]=nums[2],否则dp[2]=dp[2-1]+nums[2]
所以状态转移方程为:如果dp[i - 1]小于0,dp[ i ]=nums[ i ],否则dp[ i ]=dp[i -1]+nums[ i ]
On解决,同时dp换成nums还能更省空间
class Solution {
public:
int maxSubArray(vector& nums) {
int n=nums.size();
int maxx=nums[0];
for(int i=1;i0) nums[i]=nums[i]+nums[i-1];
maxx=max(maxx,nums[i]);
}
return maxx;
}
};
如果想跟快的话,取消同步 Runtime 50 ms Beats 99.91% Memory 67.7 MB Beats 81.53%
class Solution {
public:
int maxSubArray(vector& nums) {
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
int n=nums.size();
int maxx=nums[0];
for(int i=1;i0) nums[i]=nums[i]+nums[i-1];
maxx=max(maxx,nums[i]);
}
return maxx;
}
};
看看分治的代码
分成左右中三个部分,左边部分是左边最大的子串和,右边部分得到右边最大字串和;
左边部分是所有包含了m-1位置的字符串的最大子串和 lmax,右边部分是包含了m+1位置的字符串的最大字串和 rmax,返回max(lmax. rmax ),ml+mr+nums[m]两者之中大的那一个
class Solution {
public:
int maxSubArray(vector& nums) {
return maxSubArray(nums, 0, nums.size() - 1);
}
private:
int maxSubArray(vector& nums, int l, int r) {
if (l > r) return INT_MIN;
int m = l + (r - l) / 2, ml = 0, mr = 0;
int lmax = maxSubArray(nums, l, m - 1);
int rmax = maxSubArray(nums, m + 1, r);
for (int i = m - 1, sum = 0; i >= l; i--) {
sum += nums[i];
ml = max(sum, ml);
}
for (int i = m + 1, sum = 0; i <= r; i++) {
sum += nums[i];
mr = max(sum, mr);
}
return max(max(lmax, rmax), ml + mr + nums[m]);
}
};
死做
class Solution {
public:
vector spiralOrder(vector>& matrix) {
int dy[]={1, 0,-1,0};
int dx[]={0, 1, 0,-1};
bool vis[19][19]={0};
int m=matrix.size(),n=matrix[0].size();
int nowx=0,nowy=0,mod=0;
int nx=0,ny=0;
vector ans;
for(int i=0;i=m||ny<0||ny>=n||vis[nx][ny]==1){
mod=(mod+1)%4;nx=nowx+dx[mod];ny=nowy+dy[mod];
}
}
return ans;
}
};
题意:问能不能从索引0到索引n-1
既然是问能不能到到终点,用贪心或者动态规划都可以,上次用了动态规划,这次就贪心吧
注意:记得 if(nums[0]==0&&n!=1)return 0;要特判
class Solution {
public:
bool canJump(vector& nums) {
int n=nums.size();
if(nums[0]==0&&n!=1)return 0;
for(int i=1;i
题意:返回重叠部分
应该是要维护两端端点的,好像是-1 +1什么的?
做着做着发现这个interval还有start==end,这个-1和+1怎么做??
点的话就找一个bool数组特判吧
class Solution {
public:
vector> merge(vector>& in) {
int vis[10004]={0};int n=in.size();int maxx=0;
bool fl[10004]={0};//判点
vector> ans;
for(int i=0;i0){st=i;mod=-mod;}
else if(mod==-1&&sum==0){
en=i;mod=-mod;
ans.push_back({st,en});
}
else if(fl[i]&&mod==1){
ans.push_back({i,i});
}
}
return ans;
}
};
标答的时间复杂度为O(n+logn)
首先将interval排序,应该是按照覆盖的起点排序,起点从小到大排序;
遍历每个覆盖域,首先是第一个覆盖区域,初始化start和end;之后不断地找大的end,直到目前最大的end小于新来的start,这时把起点和重点放到答案列表中,更新起点和终点
class Solution {
public:
vector> merge(vector>& intervals) {
vector> ans;
int n=intervals.size();
sort(intervals.begin(),intervals.end());
int start=intervals[0][0];
int end=intervals[0][1];
for(int i=1;i
题意:机器人只能向下或者向右走,要从grid[0][0]走到grid[m-1][n-1]
好像是组合数?按按计算器看看能不能推出来,没推出来
好像递归也是能够做出来的?不过走楼梯是一维的c[i+1]+c[i+2]得到的?
那么假设c是方案数,就先按照下面这个图建立一个二维数组做?
【看标答,这种方法居然是dp】
class Solution {
public:
int uniquePaths(int m, int n) {
int st[104][104]={0};st[m-1][n-1]=1;
for(int i=m-1;i>=0;i--)
for(int j=n-1;j>=0;j--)
st[i][j]+=(st[i+1][j]+st[i][j+1]);
return st[0][0];
}
};
在这个图上,一共要走m+n-2步,其中有m-1步是向下的,n-1步是向右的,这可以转换成m-1个向下和n-1个向右的排序(图源知乎)
class Solution {
public:
int uniquePaths(int m, int n) {
int N = n+m-2; // total steps = n-1 + m-1
int r = min(n,m)-1;
// will iterate on the minimum for efficiency = (total) C (min(right, down)
double res = 1;// compute nCr
for(int i=1; i<=r; ++i, N--)
res = res*(N)/i;
return (int)res;
}
};
题意:二维地图,只能向下或者向右走,找到所有路径上的最小的值。
这个肯定是dp吧;还是相同的道理,但是要注意边缘处理
dp[i][j]=num[i][j]+min(dp[i+1][j],dp[i][j+1])
class Solution {
public:
int minPathSum(vector>& grid) {
int m=grid.size(),n=grid[0].size();
for(int i=m-1;i>=0;i--){
for(int j=n-1;j>=0;j--){
if(i==m-1 && j==n-1)continue;
if(i==m-1)grid[i][j]+=grid[i][j+1];
else if(j==n-1)grid[i][j]+=grid[i+1][j];
else grid[i][j]+=min(grid[i+1][j],grid[i][j+1]);
}
}
return grid[0][0];
}
};
题意:爬楼梯,只能走1或2步,问到终点要走多少步
n=1,c=1;n=2,c=2;n=3,c=3;c[i]=c[i-1]+c[i-2]
class Solution {
public:
int climbStairs(int n) {
if(n<3) return n;
int a=1,b=2,c=0;
for(int i=3;i<=n;i++){
c=a+b;a=b;b=c;
}
return c;
}
};
题意:三个操作:插入一个字母,删除一个字母,替换一个字母;问从字符串1变成字符串2最少需要多少步?
(因为之前没保存,就只贴图片了)
如果word1[0..i-1)+word2[j-1]=word2[0..j),要在i中插入word2[j-1],所以dp[i][j]=dp[i][j-1]+1
Q:为什么是dp[i][j]=dp[i][j-1]+1?
因为word1[0..i-1)+word2[j-1]=word1[0..i)=word2[0..j),有word2[0..j)之前先有word2[0..j-1)所以知道了word1[0..i-1)如何转换成word2[0..j-1),因此word1[0..i)转换为word2[0..j)就是在word1[0..i-1)上增加了一步操作
所以当word1[i - 1] != word2[j - 1]时,从三种操作中找出最小的那个
class Solution {
public:
int minDistance(string word1, string word2) {
int m=word1.size(), n=word2.size();
int dp[505][505]={0};
for(int i=1;i<=m;i++)dp[i][0]=i;//注意初始化的范围
for(int i=1;i<=n;i++)dp[0][i]=i;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(word1[i-1]==word2[j-1])
dp[i][j]=dp[i-1][j-1];//注意这里的等于号
else
dp[i][j]=min(min(dp[i-1][j-1],dp[i-1][j]),dp[i][j-1])+1;
}
}
return dp[m][n];
}
};
接下来把二维数组改成一维数组,从上面的代码可以看到,只需要dp[i - 1][j - 1],
dp[i][j - 1]
和 dp[i - 1][j]
,所以可以用pre数组来代替dp[i-1]
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
vector pre(n + 1, 0), cur(n + 1, 0);
for (int j = 1; j <= n; j++) {//因为是dp[i-1]的初始化,所以长度为word2的长度
pre[j] = j;
}
for (int i = 1; i <= m; i++) {
cur[0] = i;
for (int j = 1; j <= n; j++) {
if (word1[i - 1] == word2[j - 1]) {
cur[j] = pre[j - 1];
} else {
cur[j] = min(pre[j - 1], min(cur[j - 1], pre[j])) + 1;
}
}
fill(pre.begin(), pre.end(), 0);
swap(pre, cur);
}
return pre[n];
}
};
最后可以直接将pre数组省略成pre
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size(), pre;
vector cur(n + 1, 0);
for (int j = 1; j <= n; j++) //初始化
cur[j] = j;
for (int i = 1; i <= m; i++) {
pre = cur[0];
cur[0] = i;
for (int j = 1; j <= n; j++) {
int temp = cur[j];
if (word1[i-1] == word2[j-1])
cur[j] = pre;
else
cur[j] = min(pre, min(cur[j - 1], cur[j])) + 1;
pre = temp;
}
}
return cur[n];
}
};
题意:set its entire row and column to 0
方案一 创建一个vis用来记录0,之后按照vis来修改,空间是O(mn)【这肯定做得出来】
方案二 设计一个创建一个长为n行的数组a,长为m的数组b;a记录下0在哪几行出现,b记录一下0在哪几列出现,之后修改,空间 Om+n 同时也符合"devise a constant space solution"
class Solution {
public:
void setZeroes(vector>& ma) {
int m=ma.size(),n=ma[0].size();
bool a[204]={0};bool b[204]={0};
for(int i=0;i
先把行全部处理了,之后再把列全部处理了
首先遍历行
void setZeroes(vector > &matrix) {
int col0 = 1, rows = matrix.size(), cols = matrix[0].size();
for (int i = 0; i < rows; i++) {
if (matrix[i][0] == 0) col0 = 0;
for (int j = 1; j < cols; j++)
if (matrix[i][j] == 0)
matrix[i][0] = matrix[0][j] = 0;
}
for (int i = rows - 1; i >= 0; i--) {
for (int j = cols - 1; j >= 1; j--)
if (matrix[i][0] == 0 || matrix[0][j] == 0)
matrix[i][j] = 0;
if (col0 == 0) matrix[i][0] = 0;
}
}
题意:矩阵中是否存在target
两次查找
class Solution {
public:
int bis(int l,int r,vector>& mat, int target){
while(l<=r){
int mid=(l+r)/2;
if(mat[mid][0]>& mat, int target){
while(l<=r){
int mid=(l+r)/2;
if(mat[q][mid]>& matrix, int target) {
int n=matrix.size();int i=0;
if(target
ummm就这样吧,标答是先On,之后Ologn的
class Solution {
public:
bool searchMatrix(vector>& matrix, int target) {
int lent = matrix.size();
int widt= matrix[0].size();
int tart=0;
for(int i=0; i= target){
tart = i; break;
}
}
int low = 0;
int high = widt-1;
int mid;
while(low<=high){
mid = (low+((high-low)/2));
if(matrix[tart][mid] == target)
return true;
else if (matrix[tart][mid] < target)
low = mid+1;
else
high = mid-1;
}
return false;
}
};