209. 长度最小的子数组;445. 两数相加 II;836. 矩形重叠;892. 三维形体的表面积;289. 生命游戏;392. 判断子序列

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

 

示例:

输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。


 

进阶:


    如果你已经完成了 O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。

class Solution {//滑动窗口
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        if(nums.size()==0)return 0;
        int le=0,ri=0,sum=0,res=INT_MAX;
        while(ri<nums.size()){
            sum+=nums[ri++];
            while(sum>=s){
                res=min(res,ri-le);
                sum-=nums[le++];
            }
        }
        return res==INT_MAX?0:res;
    }
};
    int minSubArrayLen(int s, vector<int>& nums){
        if(nums.size()==0)return 0;
        vector<int>sum(nums.size()+1,0);//s<=sumij=sum[j+1]-sum[i];
        int res=INT_MAX;
        for(int i=1;i<sum.size();++i)
            sum[i]=sum[i-1]+nums[i-1];
        for(int i=0;i<nums.size();++i){//
            int pos=search(sum,i,sum.size()-1,s+sum[i]);
            if(pos!=-1)res=min(res,pos-i);
        }
        return res==INT_MAX?0:res;
    }
    //lower_bound(nums.begin(),nums.end(),target)
    int search(vector<int>&nums,int low,int high,int target){
        if(low>high)return -1;
        int le=low,ri=high,pos=-1;
        while(le<=ri){
            int mid=le+((ri-le)>>1);
            if(nums[mid]>=target){
                pos=mid;
                ri=mid-1;
            }
            else le=mid+1;
        }
        return pos;
    }

 

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

 

进阶:

如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。

 

示例:

输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 8 -> 0 -> 7

class Solution {
//如果输入链表不能修改该如何处理?用vector存储起来,从后遍历相加
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        l1=reverse(l1);
        l2=reverse(l2);
        ListNode *LN=new ListNode(0),*cur=LN;
        int carry=0;
        while(l1&&l2){
            int sum=l1->val+l2->val+carry;
            carry=sum/10;            
            auto tmp=new ListNode(sum%=10);
            cur->next=tmp;
            cur=tmp;
            l1=l1->next;
            l2=l2->next;
        }
        while(l1){
            int sum=l1->val+carry;
            carry=sum/10;            
            auto tmp=new ListNode(sum%=10);
            cur->next=tmp;
            cur=tmp;
            l1=l1->next;
        }
        while(l2){
            int sum=l2->val+carry;
            carry=sum/10;            
            auto tmp=new ListNode(sum%=10);
            cur->next=tmp;
            cur=tmp;
            l2=l2->next;
        }
        if(carry){
            auto tmp=new ListNode(1);
            cur->next=tmp;
        }
        cur=LN->next;
        delete LN;
        return reverse(cur);
    }
    ListNode* reverse(ListNode* head){
        ListNode *pre=nullptr,*cur=head,*next=nullptr;
        while(cur){
            next=cur->next;
            cur->next=pre;
            pre=cur;
            cur=next;
        }
        return pre;
    }
};

矩形以列表 [x1, y1, x2, y2] 的形式表示,其中 (x1, y1) 为左下角的坐标,(x2, y2) 是右上角的坐标。

如果相交的面积为正,则称两矩形重叠。需要明确的是,只在角或边接触的两个矩形不构成重叠。

给出两个矩形,判断它们是否重叠并返回结果。

 

示例 1:

输入:rec1 = [0,0,2,2], rec2 = [1,1,3,3]
输出:true


示例 2:

输入:rec1 = [0,0,1,1], rec2 = [1,0,2,1]
输出:false


 

提示:


    两个矩形 rec1 和 rec2 都以含有四个整数的列表的形式给出。
    矩形中的所有坐标都处于 -10^9 和 10^9 之间。
    x 轴默认指向右,y 轴默认指向上。
    你可以仅考虑矩形是正放的情况。

class Solution {
public:
    //横坐标+纵坐标重叠的情况
    bool isRectangleOverlap(vector<int>& rec1, vector<int>& rec2) {
        int lx1=rec1[0],ly1=rec1[1],lx2=rec1[2],ly2=rec1[3];
        int rx1=rec2[0],ry1=rec2[1],rx2=rec2[2],ry2=rec2[3];
        return max(lx1,rx1)<min(lx2,rx2)&&max(ly1,ry1)<min(ly2,ry2);
    }
    /*反向思考:不重叠的情况
    bool isRectangleOverlap(vector<int>& rec1, vector<int>& rec2) {
        int lx1=rec1[0],ly1=rec1[1],lx2=rec1[2],ly2=rec1[3];
        int rx1=rec2[0],ry1=rec2[1],rx2=rec2[2],ry2=rec2[3];
        return !(lx2<=rx1||lx1>=rx2||ly1>=ry2||ly2<=ry1);
    }
    */
};

在 N * N 的网格上,我们放置一些 1 * 1 * 1  的立方体。

每个值 v = grid[i][j] 表示 v 个正方体叠放在对应单元格 (i, j) 上。

请你返回最终形体的表面积。

 

 


示例 1:

输入:[[2]]
输出:10


示例 2:

输入:[[1,2],[3,4]]
输出:34


示例 3:

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


示例 4:

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


示例 5:

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


 

提示:


    1 <= N <= 50
    0 <= grid[i][j] <= 50

class Solution {
    vector<int>dx={1,0,-1,0},dy={0,1,0,-1};
public:
    int surfaceArea(vector<vector<int>>& grid){
        int n=grid.size();
        int cnt=0;
        for(int i=0;i<n;++i)
            for(int j=0;j<n;++j){
                if(grid[i][j]==0)continue;
                cnt+=2;//上下
                for(int k=0;k<4;++k){//四周
                    auto x=i+dx[k],y=j+dy[k];
                    if(x<0||y<0||x==n||y==n){
                        cnt+=grid[i][j];
                        continue;
                    }
                    cnt+=max(grid[i][j]-grid[x][y],0);
                }
            }
        return cnt;
    }
    /*每一次遍历没有充分利用上下左右,虽然都是O(n^2)
    int surfaceArea(vector<vector<int>>& grid) {
        int n=grid.size();
        int cnt=0;
        for(auto &i:grid)
            for(auto &j:i)
                cnt+=j==0?0:6*j-2*(j-1);//6*j:总 2*(j-1):自身重叠
        for(int i=0;i<n;++i)
            for(int j=0;j<n-1;++j){
                auto tmp=min(grid[i][j],grid[i][j+1]);//每一行左右重叠
                cnt-=tmp==0?0:2*tmp;
            }
        for(int i=0;i<n;++i)
            for(int j=0;j<n-1;++j){
                auto tmp=min(grid[j][i],grid[j+1][i]);//每一列上下重叠
                cnt-=tmp==0?0:2*tmp;
            }
        return cnt;
    }*/
};

根据 百度百科 ,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。

给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态:1 即为活细胞(live),或 0 即为死细胞(dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:


    如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
    如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
    如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
    如果死细胞周围正好有三个活细胞,则该位置死细胞复活;


根据当前状态,写一个函数来计算面板上所有细胞的下一个(一次更新后的)状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。

 

示例:

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

 

进阶:


    你可以使用原地算法解决本题吗?请注意,面板上所有格子需要同时被更新:你不能先更新某些格子,然后使用它们的更新后的值再更新其他格子。
    本题中,我们使用二维数组来表示面板。原则上,面板是无限的,但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题?

class Solution {
public:
    void gameOfLife(vector<vector<int>>& board){
        /*更新后状态<-当前状态:二进制第1位为更新后的状态,第0位为当前状态
        0<-0:00 0//
        1<-0:10 2
        0<-1:01 1//
        1<-1:11 3
        */
        int n,m;
        if((m=board.size())==0||(n=board[0].size())==0)return;
        vector<int>dx={1,0,-1,0,1,1,-1,-1};
        vector<int>dy={0,1,0,-1,1,-1,1,-1};
        for(int i=0;i<m;++i)
            for(int j=0;j<n;++j){
                int cnt=0;
                for(int k=0;k<8;++k){
                    int x=i+dx[k],y=j+dy[k];
                    if(x<0||y<0||x==m||y==n)continue;
                    cnt+=board[x][y]&1?1:0;//判断(x,y)当前状态是0是1
                }
                if(board[i][j]&1){//判断(i,j)当前状态是0是1
                    if(cnt==2||cnt==3)board[i][j]=0b11;//1<-1
                    //else board[i][j]=0b01;//0<-1 起始值就是1所以可以省略
                }
                else if(cnt==3)board[i][j]=0b10;//1<-0 
                //else board[i][j]=0b00;//0<-0 起始值就是0所以可以省略
            }
        for(auto &i:board)
            for(auto &j:i)
                j>>=1;//因为二进制第1位为更新后的状态,第0位为当前状态
    }
    /*
    void gameOfLife(vector<vector<int>>& board) {
        int n,m;
        if((m=board.size())==0||(n=board[0].size())==0)return;
        vector<int>dx={1,0,-1,0,1,1,-1,-1};//2
        vector<int>dy={0,1,0,-1,1,-1,1,-1};
        vector<vector<int>>res(m,vector<int>(n,0));
        for(int i=0;i<m;++i)
            for(int j=0;j<n;++j){
                int cnt=0;
                for(int k=0;k<8;++k){
                    int x=i+dx[k],y=j+dy[k];
                    if(x<0||y<0||x==m||y==n)continue;
                    cnt+=board[x][y]==1?1:0;
                }
                if(board[i][j]==1){
                    if(cnt==2||cnt==3)res[i][j]=1;
                }
                else if(cnt==3)res[i][j]=1;
            }
        board=res;//1 board.swap(res);
    }*/
};

 

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

示例 1:
s = "abc", t = "ahbgdc"

返回 true.

示例 2:
s = "axc", t = "ahbgdc"

返回 false.

后续挑战 :

如果有大量输入的 S,称作S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

方法一:双指针
思路及算法
本题询问的是,sss 是否是 ttt 的子序列,因此只要能找到任意一种 sss 在 ttt 中出现的方式,即可认为 sss 是 ttt 的子序列。
而当我们从前往后匹配,可以发现每次贪心地匹配靠前的字符是最优决策。

假定当前需要匹配字符 ccc,而字符 ccc 在 ttt 中的位置 x1x_1x1​ 和 x2x_2x2​ 出现(x1<x2x_1 < x_2x1​<x2​),那么贪心取 x1x_1x1​ 是最优解,因为 x2x_2x2​ 后面能取到的字符,x1x_1x1​ 也都能取到,并且通过 x1x_1x1​ 与 x2x_2x2​ 之间的可选字符,更有希望能匹配成功。

这样,我们初始化两个指针 iii 和 jjj,分别指向 sss 和 ttt 的初始位置。每次贪心地匹配,匹配成功则 iii 和 jjj 同时右移,匹配 sss 的下一个位置,匹配失败则 jjj 右移,iii 不变,尝试用 ttt 的下一个字符匹配 sss。
最终如果 iii 移动到 sss 的末尾,就说明 sss 是 ttt 的子序列。

class Solution {
public:
    bool isSubsequence(string s, string t) {
        int n = s.length(), m = t.length();
        int i = 0, j = 0;
        while (i < n && j < m) {
            if (s[i] == t[j]) {
                i++;
            }
            j++;
        }
        return i == n;
    }
};

 

class Solution {
public:
    bool isSubsequence(string s, string t) {
        int sl=s.size(),tl=t.size();
        vector<vector<int>>dp(tl+1,vector<int>(26,-1));
        for(int i=tl-1;i>=0;--i)
            for(int j=0;j<26;++j)
                if(t[i]==j+'a')
                    dp[i][j]=i;
                else dp[i][j]=dp[i+1][j];
        for(int i=0,j=0;i<sl;++i){
            j=dp[j][s[i]-'a'];
            if(j++==-1)return false;
        }
        return true;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值