LeetCode冲刺:Day6

发布于 2022-11-13  34 次阅读


今天第一次参加周赛,结果有点让我羞愧……继续加油吧。

赛前随便写了几个Easy放松,再就是竞赛题四道,今天七题结束。

1. 将有序数组转换为二叉搜索树

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

代码

2. 平衡二叉树

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

代码

3. 路径总和

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

回溯法,时间超过82.9%,空间超过45%。

第一遍写完之后为了一些特例改了三四次。比如targetSum为负的情况,不能随便剪枝。

代码

// struct TreeNode {
//     int val;
//     TreeNode *left;
//     TreeNode *right;
//     TreeNode() : val(0), left(nullptr), right(nullptr) {}
//     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
//     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
// };

class Solution {
private:
    int path;
    bool flag=false;
    void backtracking(int targetSum,TreeNode* root) {
        if (root->left==nullptr&&root->right==nullptr) {
            if (path==targetSum) flag=true;
            return;
        }
        if (root->left!=nullptr) {
            path+=root->left->val;
            backtracking(targetSum,root->left);
            path-=root->left->val;
        }
        if (root->right!=nullptr) {
            path+=root->right->val;
            backtracking(targetSum,root->right);
            path-=root->right->val;
        }        
    }
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if (root==nullptr) return false;
        path=root->val;
        flag=false;
        backtracking(targetSum,root);
        return flag;
    }
};

4. 温度转换

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

周赛简单题,毋须多言,第一眼看到的时候还想有没有这么简单……

代码

class Solution {
public:
    vector<double> convertTemperature(double celsius) {
        vector<double> ans(2,0);
        ans[0]=celsius+273.15;
        ans[1]=celsius*1.80+32.00;
        return ans;
    }
};

5. 最小公倍数为 K 的子数组数目

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

周赛中等题。第一眼看到就想用DP,然后死磕,然后我的第一次周赛就这么结束了……

事后看评论区,原来暴力解法不会超时。

需要一些数学知识。竞赛中虽然去百度得到了求最小公倍数的公式,但不以为意,以为强行求一定超时。

写两个辅助函数,一个求最小公因子,一个求最小公倍数,后者要调用前者。

然后两层遍历,即每次起点+1,遍历至终点。还要假设在首元素前存在一个元素1。

一旦发现当前元素不满足条件,这一轮遍历跳出。

代码

class Solution {
private:
    long long gcd(long long a,long long b) {
        if (a<b) {
            long long temp=a;
            a=b;
            b=temp;
        }
        if (b!=0) {
            return gcd(b,a%b);
        }
        else return a;
    }
    long long lcm(long long a,long long b) {
        return a*b/gcd(a,b);
    }
public:
    int subarrayLCM(vector<int>& nums, int k) {
        int res=0;
        for (int i=0;i<nums.size();++i) {
            int init=1;
            for (int j=i;j<nums.size();++j) {
                init=lcm(init,nums[j]);
                if (k%init!=0) break;
                if (init==k) ++res;
            }
        }
        return res;
    }
};

6. 逐层排序二叉树所需的最少操作数目

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

这题我是直接想到了暴力法,取出每一层的所有数组成一个序列,计算交换操作数,加和即可。但我的做法性能不佳,直接超时了。

评论区有一样思路的解法,正常通过。

我的想法是用广度遍历得到每一层所有元素,但答案依然使用深度遍历,记录当前深度,并将每一个元素push到层数对应的二维数组中去,这样比较好理解和实现。dfs函数执行完后,就得到一个二维数组,里面是每一层元素的一维数组。

计算每个数组中需要执行交换的次序,是个经典问题。理解了这题相当于多学了一个经典题目的解法,赚到了。

主程序调用dfs获得含有分层元素的二维数组,再遍历每一个一维数组,调用minOps计算其最小操作数,累加到res上,最后返回。

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    vector<vector<int>> vec;
    void dfs(TreeNode* root,int d) {
        if (root==nullptr) return;
        while(vec.size()<=d) vec.push_back(vector<int>());
        vec[d].push_back(root->val);
        dfs(root->left,d+1);
        dfs(root->right,d+1);
    }
    int minOps(vector<int>& nums) {
        vector<int> B=nums;
        sort(B.begin(),B.end());
        unordered_map<int,int> mp;
        for (int i=0;i<nums.size();++i) mp[B[i]]=i;
        int res=0;
        for (int i=0;i<nums.size();++i) {
            while(nums[i]!=B[i]) {
                swap(nums[i],nums[mp[nums[i]]]);
                ++res;
            }
        }
        return res;
    }
public:
    int minimumOperations(TreeNode* root) {
        vec.clear();
        dfs(root,0);
        int res=0;
        for (auto &nums:vec) res+=minOps(nums);
        return res;

    }
};

7. 不重叠回文子字符串的最大数目

难度

  • Easy
  • Medium
  • Hard

完成情况

  • 独立完成
  • 参考思路
  • 参考答案

思路

竞赛中完全没看这题。

参考答案

答案使用了DP,但应该说不是单纯DP,而是先使用了中心扩散法去找到以l为起始,r为终止的子串是否为回文串。再使用DP数组f表示到i为止,最大的选取数。状态转移方程有点复杂。

i每前进一位,面对选择,加上这一位还是不加上这一位。在这两个之间选最大的。不加都的话就等于i-1的值。加的话要看条件是否满足。

代码

class Solution {
public:
    int maxPalindromes(string s, int k) {
        int n=s.size();
        vector<vector<bool>> flag(n,vector<bool>(n,false));
        for (int i=0;i<n;++i) {
            for (int l=i,r=i;l>=0&&r<n&&s[l]==s[r];--l,++r) {
                flag[l][r]=true;
            }
        }
        for (int i=0;i<n-1;++i) {
            for (int l=i,r=i+1;l>=0&&r<n&&s[l]==s[r];--l,++r) {
                flag[l][r]=true;
            }
        }
        vector<int> f(n+1,0);
        for (int i=1;i<=n;++i) {
            f[i]=f[i-1];
            for (int j=i-k;j>=0;--j) {
                if (flag[j][i-1]) {
                    f[i]=max(f[i],f[j]+1);
                }
            }
        }
        return f[n];
    }
};