LeetCoder_____周赛(159)

1.缀点成线(5230)

题目链接: 5230. 缀点成线

这个题目做过很多次了,其实考察点就是用斜率判断三个点是否在一个直线上的时候要化除法为乘法,只不过还需要注意的是乘法是否会溢出,不过这个题目给的数据范围保证了不会溢出。

class Solution {
public:
    typedef long long ll;
    bool checkStraightLine(vector<vector<int>>& coordinates) {
        
        int size = coordinates.size();
        if(size <= 2)
        {
            return true;
        }
        
        for(int i = 2; i < size; ++i)
        {
            ll x1 = coordinates[i - 2][0];
            ll y1 = coordinates[i - 2][1];
            
            ll x2 = coordinates[i - 1][0];
            ll y2 = coordinates[i - 1][1];
            
            ll x3 = coordinates[i][0];
            ll y3 = coordinates[i][1];
            
            if((x2 - x1)*(y3-y2) != (x3 - x2)*(y2-y1))
            {
                return false;
            }
        }
        return true;
    }
};




2.删除子文件夹(5231)

题目链接: 5231. 删除子文件夹

这个题目其实就是通过判断一个字符串是不是另一个字符串的前缀。然后去掉有前缀的字符串。所以先按照字符串长度排序,然后再维护一个字典树来判断是否拥有前缀。

需要注意的是: ab/cd/e 和 ab/cd/ef 这种样例,虽然说前者是后者的前缀,但是后者并不是前者的子文件夹,所以只需要判断前缀的时候在判断后面一个字符是不是’/'即可。

class Trie {
public:
    struct TrieNode {
        bool end;
        TrieNode* next[128];
        TrieNode() {
            end = false;
            for (int i = 0; i < 128; ++i) {
                next[i] = NULL;
            }
        }
    };
    Trie() {
        this->clear();
    }
    void insert(string s) {
        TrieNode* cur = this->curNode;
        for (int i = 0; i < s.length(); ++i)
        {
            int offset = s[i];
            if (cur->next[offset] == NULL)
            {
                cur->next[offset] = allocNode();
            }
            cur = cur->next[offset];
        }
        cur->end = true;
    }
    bool find(string s) {
        TrieNode* cur = this->curNode;
        for (int i = 0; i < s.length(); ++i)
        {
            int offset = s[i];
            if (s[i] == '/' && cur->end)
            {
                return true;
            }
            if (cur->next[offset] == NULL)
            {
                return false;
            }
            cur = cur->next[offset];

        }
        return cur->end;
    }
    void clear() {
        this->curNode = allocNode();
    }

private:

    TrieNode* allocNode() {
        return new TrieNode();
    }
    TrieNode* curNode;
};

class Solution {
public:
    vector<string> removeSubfolders(vector<string>& folder) {

        vector<string> paths;
        for (int i = 0; i < folder.size(); ++i)
        {
            if (check(folder[i]))
            {
                paths.push_back(folder[i]);
            }
        }
        sort(paths.begin(), paths.end(), cmp);
        folder.clear();
        Trie tree;
        for (int i = 0; i < paths.size(); ++i)
        {
            if (!tree.find(paths[i]))
            {
                folder.push_back(paths[i]);
            }
            tree.insert(paths[i]);
        }
        return folder;
    }

    bool check(string& path)
    {
        if (path == "") return false;
        if (strstr(path.c_str(), "//") != NULL) return false;
        return true;
    }

    static bool cmp(const string& a, const string& b)
    {
        return (int)a.length() < (int)b.length();
    }
};




3.替换子串得到平衡字符串(5232)

题目链接: 5232. 替换子串得到平衡字符串

周赛结束后看评论,好像有的人会理解错题意,其实这个题目只能替换一个子串,求这个子串的最小长度。

这个题目的思路很简单,首先统计每个字符出现个数,因为我们知道总长度,所以每个字符应该出现的次数也知道,所以每个字符多余的字符数Si是可以算出来的。
那么我们问题就转化为,找到一个区间使得这个区间字符出现的个数不少于这个字符多余的字符数Si。

class Solution {
public:
    int balancedString(string s) {
        
        vector<int> q,w,e,r;
        
        int size = s.length();
        int n = size / 4;
        
        q.resize(size+1);
        w.resize(size+1);
        e.resize(size+1);
        r.resize(size+1);
        q[0] = w[0] = e[0] = r[0] = 0;
        int Q = 0, W = 0, E = 0, R = 0;
        for(int i = 0 ; i < size; ++i)
        {
            q[i+1] = q[i];w[i+1] = w[i];
            e[i+1] = e[i];r[i+1] = r[i];
            
            if(s[i] == 'Q'){
                Q ++;q[i+1] ++;
            }
            else if(s[i] == 'W'){
                W ++;w[i+1] ++;
            }
            else if(s[i] == 'E'){
                E ++; e[i+1] ++;
            }
            else if(s[i] == 'R'){
                R ++; r[i+1] ++;
            }
        }
        
        Q = max(0, Q-n);
        W = max(0, W-n);
        E = max(0, E-n);
        R = max(0, R-n);
        
        int ret = size,left = 1, right = 1;
        while(true)
        {
            if(q[right] - q[left-1] >= Q &&
              w[right] - w[left-1] >= W &&
              e[right] - e[left-1] >= E &&
              r[right] - r[left-1] >= R)
            {
                ret = min(ret, right - left + 1);
                left ++;
            }
            else
            {
                right++;
            }
            if(right > size || left > size)break;
        }
        return ret;
    }
};




4.规划兼职工作(5233)

题目链接: 5233. 规划兼职工作

这个题目做过很多次,不过在这里不一样的是时间范围给得很大,传统的dp思路肯定不行。但是看了一下

1 <= startTime.length == endTime.length == profit.length <= 5 * 10^4

这个范围,所以可以进行离散化操作,因为我们知道工作数量不多于50000,那么时间边界不多于100000,所以我们先将出现的时间按照从小到大排序离散,那么时间的范围就变为100000。那么这个题目dp就是变得可行的。

dp[i] = j 表示在i时间结束工作可以得到的最大价值
class HashNum
{
public:

    void insert(int number)
    {
        numset.insert(number);
    }

    void rehash()
    {
        nummap.clear();
        set<int>::iterator iter = numset.begin();
        s = 0;
        while (iter != numset.end())
        {
            nummap[*iter] = s++;
            iter++;
        }
    }

    int hash(int num)
    {
        return nummap[num];
    }
    int size()
    {
        return s;
    }


private:
    set<int> numset;
    map<int, int> nummap;
    int s;
};


class Solution {
public:

    struct WorkData
    {
        int stime;
        int money;
    };
    int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
        HashNum hashnum;

        for (int i = 0; i < startTime.size(); ++i)
        {
            hashnum.insert(startTime[i]);
        }
        for (int i = 0; i < endTime.size(); ++i)
        {
            hashnum.insert(endTime[i]);
        }
        hashnum.rehash();

        vector<int> dp;
        map<int, vector<WorkData>> workmap;
        for (int i = 0; i < endTime.size(); ++i)
        {
            WorkData data;
            data.stime = hashnum.hash(startTime[i]);
            data.money = profit[i];
            workmap[hashnum.hash(endTime[i])].push_back(data);
        }
        int size = hashnum.size();
        dp.resize(size + 1);
        dp[0] = 0;
        int ret = 0;
        for (int i = 0; i < size; ++i)
        {
            vector<WorkData>& worklist = workmap[i];
            if (i != 0)
            {
                dp[i] = max(dp[i], dp[i - 1]);
            }
            for (int j = 0; j < worklist.size(); ++j)
            {
                dp[i] = max(dp[i], dp[worklist[j].stime] + worklist[j].money);
                ret = max(ret, dp[i]);
            }
        }
        return ret;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值