leetcode 159周赛题解

题目1

题意

给出二维平面n个点,问是否全部在一条直线上?

思路

根据已知两点(x1,y1),(x2,y2)的直线公式: (y-y1)/(y2-y1)=(x-x1)/(x2-x1)

代码

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

题目2

题意:

给出n个文件路径名,过滤掉其中是别的路径名的子目录的路径名。

思路:

对路径名排序后,名称里最后一个‘/’之前出现过,就过滤掉。O(nlgn)

代码:
class Solution {
public:
    vector<string> removeSubfolders(vector<string>& folder) {
        vector<string> ans;
        sort(folder.begin(),folder.end());
        for(int i=0;i<folder.size();i++){
           if(i==0){
                ans.push_back(folder[i]);
           }
           else{
                if(folder[i].find(ans[ans.size()-1])!=0 || folder[i][ans[ans.size()-1].length()]!='/'){
                    ans.push_back(folder[i]);
                }
           }
        }
        return ans;
    }
};

题目3

题意

替换掉长度为4的倍数且只含'QWER'四个字母的一个子串,让整个字符串的每个字母出现次数一样。

思路

首先可以想到满足要求的子串的条件是:子串外’QWER’个数小于等于总长度/4, 于是我们就可以用一个滑动窗口或者二分去找到这个子串区间。

我用的二分,滑动窗口好久没写了,快忘了。

代码
class Solution {
public:
    int id[150], sum[100010][4], length;
    bool check(int len){
        if(len == 0){
           for(int i=0;i<4;i++)
            if(sum[length-1][i] != length/4) return false;
           return true;
        }
        for(int i=0;i+len-1<length;i++){
           int cnt = 0;
           for(int j=0; j<4; j++){
               int num = sum[length-1][j] - sum[i+len-1][j];
               if(i>0) num += sum[i-1][j];
               if(num<=length /4) cnt+=1;
           }
           if(cnt == 4) return true;
        }
        return false;
    }

    int balancedString(string s){
        length = s.size();
        id['Q'] = 0; id['W'] = 1; id['E'] =2; id['R'] = 3;
        memset(sum,0,sizeof(sum));
        for(int i=0;s[i];i++){
          for(int j=0 ;j<4;j++){
            if(id[s[i]] == j) sum[i][id[s[i]]] = i == 0 ? 1 : sum[i-1][id[s[i]]] +1 ;
            else  sum[i][j] = i==0 ?  0 : sum[i-1][j];
          }
        }
        int l=0,r = length, mid, ans;
        while(l<=r){
          mid = (l+r)>>1;
          if(check(mid)) r= mid-1;
          else l = mid+1;
        }
        return r+1;
    }
};

题目4

题意

在一个区间上,给出活动起始时间,和对应报酬,每个活动选择不能重叠,问最大报酬是?

思路

一个贪心思想结合0-1背包,先对活动时间排个序,保证选择不重复和尽量的贪心思想。
然后就是0-1背包问题,对于每个活动选或不选,dp[i]表示前i个活动里报酬最大值:
dp[i] = min(dp[i], dp[p]+ profit[i])p是满足与i区间不重叠的上个区间位置。

代码
class Solution {
public:
    int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
       int n = startTime.size();
       vector<int> id(n);
       for(int i=0;i<n;i++) id[i] = i;
       sort(id.begin(), id.end(), [&](int a, int b){
             if(endTime[a] == endTime[b])
               return startTime[a]<= startTime[b];
             else return endTime[a] < endTime[b];
           });
       vector<int> dp(n+1, 0);
       vector<int> endsort(n);
       for(int i=0;i<n;i++) endsort[i] = endTime[id[i]];
       for(int i=0;i<n;i++){
         int p = upper_bound(endsort.begin(), endsort.end(), startTime[id[i]]) - endsort.begin();
         p = min(p ,i); //如果找不到,upper_bound会返回最后一个位置
         dp[i+1] = max(dp[id[i]], dp[p] + profit[id[p]]);
       }
       return dp[n];
    }
};

总结

周赛中做出来前三道题,但不熟悉leetcode提交,一道都没过…,另外好久没有写C++,很多语法特性都是补题预习…

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值