LeetCode Contest 90

好久没有打比赛了,今天的题还算简单,比较适合练手。

Buddy Strings

问题

给出两个字符串,问第一个字符串交换两个字母能否得到第二个字符串。

思路

如果两个字符串相同,那就只能交换相同的字母,当且仅当某一个字母出现两次以上时满足条件;如果两个字符串不相同,当且仅当两个位置的字母不同且交换后相同时满足条件。扫一遍字符串,记录每一个字母出现的次数以及字母不同的位置数,判断是否满足条件。实际写代码的时候尽量不要抠细节,思路清晰,好写就行。

代码

class Solution {
public:
  bool buddyStrings(string A, string B) {
    if (A.size() != B.size()) return false;
    int counts[200] = {};  // 直接开足够的空间,无需转换字母
    int sum = 0;
    char tmp1, tmp2;
    bool dupli = false;
    for (int i = 0; i < A.size(); ++i) {
      if (A[i] != B[i]) {
        ++sum;
        if (sum == 1) {
          tmp1 = A[i];
          tmp2 = B[i];
        } else if (sum != 2 || B[i] != tmp1 && A[i] != tmp2) {
          return false;  // 根据思路嵌套分支,容易debug,不过性能有损失
        }
      }
      ++counts[A[i]];  // 无需A[i] - 'a'
      if (counts[A[i]] >= 2) dupli = true;  // 直接判断,不再另写循环
    }
    return (sum == 0 && dupli) || sum == 2;
  }
};

Score of Parentheses

问题

给出正确的括号匹配序列,要求计算得分,每一对无嵌套括号得1分,嵌套括号得分为内部括号得分之和(将所有括号得分加起来即,整个嵌套模块得分为内部括号得分的两倍)。

思路

一开始思考了很久,后来发现可以不用栈,因为不需要检查括号匹配情况。本质上是递归的思想,因为计分规则就是,每个括号模块的得分等于内部括号得分之和的两倍,至少得1分。子函数递归和用栈深搜都不好写,直接用数组模拟就好。

代码

class Solution {
public:
  int scoreOfParentheses(string S) {
    vector<int> v(S.size(), 0);  // 直接开数组也可以,如果要初始化vector比较好写
    int pos = 0;
    for (int i = 0; i < S.size(); ++i) {
      if (S[i] == '(') {
        ++pos;
        v[pos] = 0;  // 直接写v[++pos] = 0很爽,但最好还是避免养成这些影响实际开发的坏习惯
      } else {
        v[pos-1] += v[pos] == 0 ? 1 : 2*v[pos];
        --pos;
      }
    }
    return v[0];
  }
};

Mirror Reflection

问题

正方形房间中四面墙壁都是镜子,问从一个角落以一定角度发射的激光经过反射最先到达哪一个角落。

思路

这是一道数学题,需要比较灵活的空间想象。激光在镜面上的反射轨迹可以看作关于镜面的对称,由于这是一个由镜面围成的房间,可以建立坐标系,以左下角反射激光处为(0, 0),往右为x轴正方向,往上为y轴正方向,以无数与x轴或y轴平行且与房间相切的直线为对称轴,填充整个第一象限,那么每一个正方形块的每一个角落都对应原房间的一个角落。如果以房间的边长为单位,那么激光经过反射必定会到达某一个点(x, y)的左下角落,观察可得,该角落对应原房间哪一个角落与点的坐标有关

(x, y) (偶数, 偶数) (偶数, 奇数) (奇数, 偶数) (奇数, 奇数)
对应角落 无法到达 2 0 1

那么,只要确定激光最先到达的整数坐标就行了。激光发射的角落坐标为(0, 0),题目给出的pq分别对应x轴和y轴的距离,首先求pq的最简比,即各自除以最大公约数,然后根据pq的奇偶性得出答案。

代码

class Solution {
public:
  int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
  }
  int mirrorReflection(int p, int q) {
    int tmp = gcd(p, q);
    p /= tmp;
    q /= tmp;
    if (p % 2 == 0) return 2;
    if (q % 2 == 0) return 0;
    return 1;
  }
};

Minimum Cost to Hire K Workers

问题

N个工人,每个工人的工作质量和最低工资各不相同。雇佣工人的工资必须满足最低工资要求并且工资之比等于工作质量之比,问雇佣K个工人最少需要支付多少工资。

思路

感觉应该有相关模型和算法,不过最后没想明白。本质上就是优化问题,参数是工作质量和最低工资,二维的优化很难用贪心找最优解,不过这题可以用上贪心的思想。首先,当雇佣一组工人时,每单位工作质量对应的工资是相等的,乘上总工作质量就可以算出总工资;然后,每个工人的单位工作质量最低工资为最低工资除以工作质量,一组工人单位工作质量最低工资中的最大值,就是这组工人每单位工作质量对应的工资;因此,在一组工人每单位工作质量对应的工资确定之后,任意替换单位工作质量最低工资能够得到满足的工人以减少总工作质量可以找到最优解。具体操作就是先计算所有工人的单位工作质量最低工资,按从小到大排序,选择前K个工人,然后每次将所有工人中工作质量最高的工人替换为下一个工人,虽然单位工作质量对应工资必然提高了,但总工作质量有可能下降,这样就遍历了所有单位工作质量对应工资对应的最低总工资,每次比较保留较小值即可。

代码

class Solution {
public:
  double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int K) {
    int n = wage.size();
    vector<pair<double, int> > v(n);
    for (int i = 0; i < n; ++i) {
      v[i] = make_pair(wage[i]*1.0 / quality[i], quality[i]);
    }
    sort(v.begin(), v.end());  // 排序
    priority_queue<int> pq;  // 队首为工作质量最高的工人
    double sum = 0;
    for (int i = 0; i < K; ++i) {  // 选择前K个工人
      pq.push(v[i].second);
      sum += v[i].second;
    }
    double ans = sum * v[K-1].first;
    for (int i = K; i < n; ++i) {
      sum += v[i].second - pq.top();  // 计算替换后的总工作质量
      pq.pop();  // 每次替换工作质量最高的工人
      pq.push(v[i].second);
      ans = min(ans, sum * v[i].first);
    }
    return ans;
  }
};

猜你喜欢

转载自blog.csdn.net/fast_g/article/details/80790831
今日推荐