Leetcode Top 100 Liked Questions(序号394~1143)

394. Decode String ​

题意:给一个加密的字符串,返回原字符串

我的思路

递归,模拟题

代码 Runtime0 ms Beats 100% Memory6.5 MB Beats 70.76%

class Solution {
public:
    string decodeString(string s) {
        int i=0,num=0,cnt=0;string ans="",sub="";
        while(i<s.size()){
            if(s[i]<='9'&&s[i]>='0'){
                num=num*10+s[i]-'0';i++;
            }
            else if(s[i]=='['){
                cnt++;
                while(cnt){
                    i++;
                    if(s[i]==']'){cnt--;if(!cnt)break;}
                    else if(s[i]=='[')cnt++;
                    sub+=s[i];
                }
                i++;
                sub=decodeString(sub);
                for(int i=0;i<num;i++) ans+=sub;
                num=0;sub="";cnt=0;
            }
            else {
                ans+=s[i];i++;
            }
        }
        return ans;
    }
};

416. Partition Equal Subset Sum

题意:分成两个子集使得两部分相等

我的思路

问是否能找到一个方法选择数组中的数字使得和为sum/2

动态规划,但首先要sort一边,同时要注意是01背包还是完全背包

要怎么才能不同时加同样的数呢?

改写dfs+记忆化了,但TLE了

代码 

class Solution {
public:
    bool dfs(vector<int>& nums,int id,int res,vector<bool>& dp){
        if(res<0)return 0;
        if(dp[res])return 1;
        if(id==nums.size())return 0;
        if(nums[id]==res){
            dp[res]=1;return 1;
        }
        bool flag=( dfs(nums,id+1,res-nums[id],dp) | dfs(nums,id+1,res,dp) );
        if(flag)dp[res]=1;
        return flag;
    }
    bool canPartition(vector<int>& nums) {
        ios::sync_with_stdio(0);cin.tie(0);
        int n=nums.size();int sum=0;
        for(int i=0;i<n;i++)sum+=nums[i];
        if(sum%2)return 0;
        sum=sum/2; vector<bool>dp(sum,0);
        return dfs(nums,0,sum,dp);
    }
};

应该是01背包和分组背包类似的,但是忘记了

标答 递归+记忆化

标答的记忆化是如何过的呢?

        它的记忆化不止记录了返回true的答案,也记录了返回false的答案;

返回false的答案是如何记录的呢?

        首先是二维dp[id][res]来记忆结果,同时初始化为-1,这样false就记为0,True就记为1

1. 判断是否为双数可以用&1

2. 返回的时候用or,这样可以快80ms

代码 Runtime 99 ms Beats 91.9% Memory27.4 MB Beats 54.2%

class Solution {
public:
    int dp[201][20001];
    bool dfs(vector<int>& nums,int id,int res){
        if(res<0)return 0;
        if(res==0)return 1;
        if(dp[id][res]!=-1)return dp[id][res];
        if(id==nums.size())return 0;
        return dp[id][res]=(dfs(nums,id+1,res-nums[id]) or dfs(nums,id+1,res) );
    }
    bool canPartition(vector<int>& nums) {
        ios::sync_with_stdio(0);cin.tie(0);
        int n=nums.size();int sum=0;
        for(int i=0;i<n;i++)sum+=nums[i];
        if(sum&1)return 0;sum=sum>>1;
        memset(dp,-1,sizeof(dp));
        return dfs(nums,0,sum);
    }
};

标答 动态规划

把数字放在最外层,把sum放在第二层循环里

注意第二层循环的sum是从大到小的!!!这样可以避免重拿

代码 Runtime30 ms Beats 98.21% Memory9.8 MB Beats 90.95%

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        ios::sync_with_stdio(0);cin.tie(0);
        int n=nums.size();int sum=0;
        for(int i=0;i<n;i++)sum+=nums[i];
        if(sum&1)return 0;sum=sum>>1;
        vector<bool> dp(sum+1,0);dp[0]=1;
        for(int q:nums){
            for(int i=sum;i>=0;i--){
                if(q<=i&&dp[i-q]) dp[i]=1;
            }
        }
        return dp[sum];
    }
};

438. Find All Anagrams in a String

题意:给字符串p,主串s,返回index,使得以s[i]开头的子串包括字符串p的所有形式

我的思路

写了暴力 TLE了

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        if(s.size()<p.size())return {};
        int l=0,r=0;vector<int> ans;int pn=p.size();
        bool flag=0;
        sort(p.begin(),p.end());
        puts(p);
        for(int i=0;i<s.size();){
            if(!flag){
                string sub=s.substr(i,pn);
                sort(sub.begin(),sub.end());
                if(sub==p){ans.push_back(i);flag=1;}
                i++;
            }
            else{
                if(s[i-1]==s[i+pn-1]){
                    ans.push_back(i);i++;
                }
                else {
                    flag=0;i=i++;
                }
            }
        }
        return ans;
    }
};

标答 滑动窗口

76. Minimum Window Substring思路相同Leetcode Top 100 Liked Questions(序号75~104)​​​​​​

 同时用map(或者vector也可以)加以辅助

代码 Runtime 9 ms Beats 88.5% Memory 8.6 MB Beats 66.45%

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int>goal(26),curr(26);
        int pn=p.size();vector<int> ans;
        for(int i=0;i<pn;i++){
            goal[p[i]-'a']++;
        }
        for(int i=0;i<s.size();i++){
            curr[s[i]-'a']++;
            if(i-pn>=0)curr[s[i-pn]-'a']--;
            if(goal==curr)ans.push_back(i-pn+1);
        }
        return ans;
    }
};

没细看 更优化的版本

phash是p的所有字母,counter是p字符串长度;循环字符串末尾end,将end的字符减去,如果end字符再hash中大于等于0,counter--,代表需要的字符数减少了,end++;如果counter==0表示可以加入ans了;

class Solution {
public:
vector<int> findAnagrams(string s, string p) {
    int pHash[26] = { 0 }, counter = p.length();
    for (char c : p) {
        ++pHash[c - 'a'];
    }
    int start = 0, end = 0, temp = 0;
    vector<int> res;
    while (end < s.length()) {
        temp = s[end] - 'a';
        --pHash[temp];
        if (pHash[temp] >= 0) --counter;
        ++end;
        while (counter == 0) {
            temp = s[start] - 'a';
            ++pHash[temp];
            if (pHash[temp] > 0) ++counter;
            if (end - start == p.length()) {
                res.push_back(start);
            }
            ++start;
        }
    }
    return res;
}
};

543. Diameter of Binary Tree

题意:返回树的直径

我的思路 

每个结点的左边和右边都计算一次,返回长的那一条边

代码 Runtime 3 ms Beats 96.28% Memory 20.3 MB Beats 44.94%


class Solution {
public:
    int dfs(TreeNode* root,int & ans){
        if(root==NULL)return 0;
        int l=dfs(root->left,ans);
        int r=dfs(root->right,ans);
        ans=max(ans,l+r);
        return max(l,r)+1;
    }
    int diameterOfBinaryTree(TreeNode* root) {
        int ans=0;
        dfs(root,ans);
        return ans;
    }
};

560. Subarray Sum Equals K

题意:返回子序列总和等于K的个数

我的思路

动态规划?dfs大概超时,用前缀和

写了一个暴力 超时了

标答

前缀和是对的,但是可以用map辅助看前缀和-k在map中有没有,蓝桥杯的整数拼接(?)也是相同原理

注意:

1. 因为是前缀和,所以不能开两个循环,要在一个循环内搞定;

2. map是<int,int>因为要记录这个前缀和出现次数;

3. 可以初始化map[0]=1,无论k是否为0,以下假设k=0

(1)当不初始化map[0]=1时,假设0在第一个,因为有直接看是否相等的特判,OK;假设0在第i个(i!=0)时,num[i-1]=num[i],所以mp[num[i-1]]存在,OK

(2)当初始化map[0]=1时,因为有直接看是否相等的特判,OK;假设0在第i个(i!=0)时,(已知mp[num[i-1]]是正确的),所以ans+=mp[nums[i-1]]是正确的

4. mp[nums[i]]++要在循环最后,不行的会变成可行的

代码 Runtime 76 ms Beats 67.97% Memory 47 MB Beats 26.84%

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        ios::sync_with_stdio(0);cin.tie(0); 
        unordered_map<int,int>mp;int ans=0;
        if(nums[0]==k)ans++;mp[nums[0]]++;
        for(int i=1;i<nums.size();i++) {
            nums[i]=nums[i-1]+nums[i];
            if(nums[i]==k)ans++;
            if(mp[nums[i]-k])
                ans+=mp[nums[i]-k];
            mp[nums[i]]++;
        }
        return ans;
    }
};

优化 

1. 前缀和不需要专门放在数组里,一个int就可以解决了

2. map的find看有无key,和通关key对应的键值比,速度更快

3. 取消同步这个比较玄学,在条件1和2的情况下,取消同步会慢10ms以上

代码 Runtime 52 ms Beats 99.11% Memory 41.5 MB Beats 74.75%

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int,int>mp;int ans=0;int sum=nums[0];
        if(sum==k)ans++;mp[sum]++;
        for(int i=1;i<nums.size();i++) {
            sum=nums[i]+sum;
            if(sum==k)ans++;
            if(mp.find(sum-k) != mp.end())
                ans+=mp[sum-k];
            mp[sum]++;
        }
        return ans;
    }
};

567. Permutation in String

题意:如果s1的所有排列中有一个是s2的子串,返回1

我的思路 

和上面的438是一样的,但可能有更简单的,但我没想出来

代码 Runtime 7 ms Beats 68.70% Memory7.3 MB Beats 62.76%

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        vector<int>goal(26),curr(26);
        for(int i=0;s1[i];i++)goal[s1[i]-'a']++;
        int len=s1.size();
        for(int i=0;i<s2.size();i++){
            curr[s2[i]-'a']++;
            if(i>=len) curr[s2[i-len]-'a']--;
            if(goal==curr)return 1;
        }
        return 0;
    }
};

标答 更快的方法

少建立的一个vector,通过++和--看能否相互抵消来判断goal是否等于curr

代码 Runtime 0 ms Beats 100% Memory 7.3 MB Beats 40.58%

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        int m = s1.size();
        int n = s2.size();
        if (m > n) return false;
        vector<int> count(26, 0);
        for (int i = 0; i < m; i++) {
            count[s1[i] - 'a']++;
            count[s2[i] - 'a']--;
        }
        if (isPermutation(count))return true;
        for (int i = m; i < n; i++) {
            count[s2[i] - 'a']--;
            count[s2[i-m] - 'a']++;
            if (isPermutation(count)) return true;
        }
        return false;
    }
private:
    bool isPermutation(vector<int>& count) {
        for (int x : count) {
            if (x != 0) {
                return false;
            }
        }
        return true;
    }
};

704. Binary Search

题意:升序数组找数字

我的思路

lower_bound

补充例子1: nums = [-1,0,3,5,9,12], target = 2

lower_bound返回2;upper_bound返回2

补充例子2:nums = [-1,0,3,5,9,12], target = 9

lower_bound返回4;upper_bound返回5

【以上数字都是lower_bound (or upper_bound)-nums.begin() 得到的结果】

代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        ios::sync_with_stdio(0);cin.tie(0);
        int i=lower_bound(nums.begin(),nums.end(),target)-nums.begin();
        if(nums.size()==i||nums[i]!=target)return -1;
        return i;
    }
};

739. Daily Temperatures

题意:给一个温度数组,问第i天后过ans[i]天的天气会更高,返回ans;若第i天之后不会有温度更高的日子返回ans[i]=0

我的思路

单调栈从大到小存?好像可以

代码 WA

看不出什么问题 但是WA了

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& t) {
        stack<int>st;int n=t.size();
        vector<int> ans(n,0);
        for(int i=0;i<n;i++){
            if(st.empty()||st.top()>=t[i])st.push(i);//有等号
            else{
                while(!st.empty()&&t[st.top()]<t[i]){//没有等号
                    int tmp=st.top();
                    ans[tmp]=i-tmp;
                    st.pop();
                }
                st.push(i);
            }
        }
        return ans;
    }
};

标答 单调栈

上面的写法写错了 为什么呢?

注意:上面的写法 if(st.empty()||st.top()>=t[i])应该改成 if(st.empty()||t[st.top()]>=t[i])

改完后就对了

代码 Runtime 130 ms Beats 91.20% Memory107.4 MB Beats 20.42%

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& t) {
        stack<int>st;int n=t.size();
        vector<int> ans(n,0);
        for(int i=0;i<n;i++){
            while(!st.empty()&&t[st.top()]<t[i]){//没有等号
                int tmp=st.top();
                ans[tmp]=i-tmp;
                st.pop();
            }
            st.push(i);
        }
        return ans;
    }
};

标答 不用单调栈 类似动态规划

从右到左记录最高温度;如果现在的温度t[i]大于等于最高温度,更新最高温度;

如果现在的温度t[i]小于等于最高温度,设i之后的一天为j【因为是从右往左,所以ans[j]是有纪录的】,如果t[j]>t[i],更新ans[i],如果t[j]<=t[i],j=j+ans[j]【因为第j+ans[j]天的温度一定比第j天的高】

因为不是现在的最高温度(如果等于最高温的话就不会要找之后的天了),所以ans[i]不会等于0,也就是说总会有一个j(i<j<=n-1)使得t[j]>t[i]

代码 Runtime116 ms Beats 98.10% Memory 98.6 MB Beats 87.47%

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& t) {
        int n=t.size();int hot=t[n-1];
        vector<int> ans(n,0);
        for(int i=n-2;i>=0;i--){
            if(t[i]>=hot){
                hot=t[i];continue;
            }
            int j=i+1;
            while(t[j]<=t[i])
                j=j+ans[j];
            ans[i]=j-i;
        }
        return ans;
    }
};

994. Rotting Oranges

题意:一个格子是腐烂的橘子,周围4个相邻的橘子下一秒也会腐烂,问多久所有橘子都腐烂?

我的思路

用BFS做,队列中的节点存放(x,y,step),记录最大的step,用cnt计算所有橘子的数量,每腐烂一个橘子cnt--,当cnt!=0时返回-1,否则返回最大的step

有很多个腐烂的橘子,那就把他们都放到BFS的队列里

代码 Runtime3 ms Beats 91.7% Memory13.1 MB Beats 73.58%

class Solution {
public:
    struct node{
        int x;int y;int step;
    };
    int orangesRotting(vector<vector<int>>& grid) {
        int m=grid.size(),n=grid[0].size();
        int cnt=0;queue<node>q;int maxx=0;
        int dx[]={0,0,1,-1};
        int dy[]={1,-1,0,0};
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                if(grid[i][j]==1)cnt++;
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++){
                if(grid[i][j]==2){
                    q.push({i,j,0});
                }
            }
        if(!cnt)return 0;
        while(!q.empty()){
            node now=q.front();q.pop();
            for(int i=0;i<4;i++){
                int nx=now.x+dx[i];
                int ny=now.y+dy[i];
                if(nx<0||ny<0||nx>=m||ny>=n||grid[nx][ny]!=1)continue;
                grid[nx][ny]=2;
                q.push({nx,ny,now.step+1});cnt--;
                maxx=max(maxx,now.step+1);
            }
            if(!cnt)break;
        }
        if(cnt)return -1;
        return maxx;
    }
};

1143. Longest Common Subsequence

题意:给出最长公共子序列的长度

我的思路

动态规划,但我不记得怎么做了

标答

class Solution {
public:
   
    int longestCommonSubsequence(string text1, string text2) {
        int m=text1.size(),n=text2.size();
        int dp[m+1][n+1];
        for(int i=0;i<m+1;i++){
            dp[i][0]=0;
        }
        for(int i=0;i<n+1;i++){
            dp[0][i]=0;
        }
        for(int i=1;i<m+1;i++){
            for(int j=1;j<n+1;j++){
               if(text1[i-1]==text2[j-1]){
                  dp[i][j]= 1+dp[i-1][j-1];
               }else{
                   dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
               } 
            }
        }
        return dp[m][n];
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值