LeetCode第90场周赛记录

第一题:亲密字符串

问题:

给定两个由小写字母构成的字符串 A 和 B ,只要我们可以通过交换 A 中的两个字母得到与 B 相等的结果,就返回 true ;否则返回 false 。

示例 1:

  1. 输入: A = "ab", B = "ba"
  2. 输出: true

示例 2:

  1. 输入: A = "ab", B = "ab"
  2. 输出: false

示例 3:

  1. 输入: A = "aa", B = "aa"
  2. 输出: true

示例 4:

  1. 输入: A = "aaaaaaabc", B = "aaaaaaacb"
  2. 输出: true

示例 5:

  1. 输入: A = "", B = "aa"
  2. 输出: false

链接:https://leetcode-cn.com/contest/weekly-contest-90/problems/buddy-strings/

分析:

1.如果两个字符串长度不等,一定不满足

2.如果两个字符串完全相同,需要至少两个完全相同的字符,才能满足交换两个字母后相同,所以如果长度小于2,也一定不满足。

3.其他情况两个字符串需要有且仅有两个不同的字符,差异的两个字符仅仅是顺序不同。

AC Code:

  1. class Solution {
  2. public:
  3. bool buddyStrings(string A, string B) {
  4. if (A.size() != B.size() || A.size()<)
  5. {
  6. return false;
  7. }
  8. //记录不同的,如果两者可以交换,返回true,完全相同,返回true
  9. int counter = ; //记录差异点数
  10. string A1=""; //分别保存差异内容
  11. string A2="";
  12. for (int i = ; i < A.size(); i++)
  13. {
  14. if (A[i] != B[i])
  15. {
  16. counter++;
  17. A1 += A[i];
  18. A2 += B[i];
  19. }
  20. }
  21. if (counter == )
  22. {
  23. //完全一样的两个字符串 //需要有两个完全一样的字符
  24. map<char, int> tmp;
  25. for (int i = ; i < A.size(); i++)
  26. {
  27. if (tmp.count(A[i])==)
  28. {
  29. tmp[A[i]]++;
  30. }
  31. else
  32. {
  33. tmp[A[i]] = ;
  34. }
  35. }
  36. map<char, int>::iterator it;
  37. for (it = tmp.begin(); it != tmp.end(); it++)
  38. {
  39. if (it->second >= )
  40. {
  41. return true;
  42. }
  43. }
  44. return false;
  45. }
  46. if (A1.size()!=)
  47. {
  48. return false;
  49. }
  50. else
  51. {
  52. if (A1[] == A2[] && A1[] == A2[])
  53. {
  54. return true;
  55. }
  56. else
  57. {
  58. return false;
  59. }
  60. }
  61. }
  62. };

其他:

第一的做法:

  1. class Solution {
  2. public boolean buddyStrings(String A, String B) {
  3. int[] l = new int[256];
  4. boolean two = false;
  5. for(int i = 0; i < A.length(); i++) {
  6. if(++l[A.charAt(i)] > 1) two = true;
  7. }
  8. for(int i = 0; i < B.length(); i++) {
  9. --l[B.charAt(i)];
  10. }
  11. for(int out: l) {
  12. if(out != 0) return false;
  13. }
  14. int error = 0;
  15. for(int i = 0; i < A.length(); i++) {
  16. if(A.charAt(i) != B.charAt(i)) {
  17. error++;
  18. }
  19. }
  20. if(error == 2) return true;
  21. if(error > 2) return false;
  22. return two;
  23. }
  24. }

用的好像是Java,思路是先创建256大小字符数组【如果要对空间进行优化的话,可以只创建26个大小数组,因为题目中明确只有a-z,对应做一个-‘a’处理即可,不过区别不大】,用来统计每个字母出现个数,先统计A的数量,一旦有某个字符出现两次及以上,将标志two设为true。然后利用B中字符减去对应个数,结束后一旦某个字符对应位置不是0,则说明A中和B中对应字符个数不一致,一定不满足要求,返回false,然后统计AB中差异个数,如果差异个数是2,返回true,如果差异超过2,返回false,接下来一定是没有差异(如果只有一个字符差异,一定不满足AB中对应字符个数一致要求,前面就会返回false),返回two的值,即是否有某个字符数量达到2.

第二题:括号的分数

题目:

给定一个平衡括号字符串 S,按下述规则计算该字符串的分数:

  • () 得 1 分。
  • AB 得 A + B 分,其中 A 和 B 是平衡括号字符串。
  • (A) 得 2 * A 分,其中 A 是平衡括号字符串。

示例 1:

  1. 输入: "()"
  2. 输出: 1

示例 2:

  1. 输入: "(())"
  2. 输出: 2

示例 3:

  1. 输入: "()()"
  2. 输出: 2

示例 4:

  1. 输入: "(()(()))"
  2. 输出: 6

提示:

  1. S 是平衡括号字符串,且只含有 ( 和 ) 。
  2. 2 <= S.length <= 50

链接:https://leetcode-cn.com/contest/weekly-contest-90/problems/score-of-parentheses/

分析:

1.如果是(),值为1;

2.如果是“”,值为0;

3.对于某个string S,如果形如()S`,结果为1+value(S`)

如果形如(S`)S``,结果为2*value(S`)+value(S``)

已知给出字符串是平衡的,只需要按照规则递归分解求值即可

需要做的就是找出S`以及剩余字符串S``

AC code:

 

  1. class Solution {
  2. public:
  3. int scoreOfParentheses(string S) {
  4. if (S.size() == ) //空串值为0
  5. {
  6. return ;
  7. }
  8. if (S.size() == ) //已知括号匹配,长度2的一定是(),值是1
  9. {
  10. return ;
  11. }
  12. string tmp = ""; //嵌套的字符串
  13. string left = ""; //当前匹配后剩余的字符串
  14. stack<char> tmpstack; //S[0]一定是'('
  15. if (S[] == ')') // ()S`类型
  16. {
  17. for (int j = ; j < S.size(); j++)
  18. {
  19. left += S[j];
  20. }
  21. return + scoreOfParentheses(left);;
  22. }
  23. tmp += S[];
  24. tmpstack.push(S[]);
  25. for (int i = ; i < S.size(); i++)
  26. {
  27. if (tmpstack.empty() == true && S[i] == ')') //完成匹配,形如(S`)S``
  28. {
  29. for (int j = i + ; j < S.size(); j++)
  30. {
  31. left += S[j];
  32. }
  33. return * scoreOfParentheses(tmp) + scoreOfParentheses(left);
  34. }
  35. else
  36. {
  37. tmp += S[i];
  38. if (tmpstack.empty() == true)
  39. {
  40. tmpstack.push(S[i]);
  41. }
  42. else if (tmpstack.top() == '(' && S[i] == ')')
  43. {
  44. tmpstack.pop();
  45. }
  46. else
  47. {
  48. tmpstack.push(S[i]);
  49. }
  50. }
  51. }
  52.  
  53. }
  54. };

其他:

第一的做法:

  1. class Solution {
  2. public int scoreOfParentheses(String S) {
  3. if(S.length() == 0) return 0;
  4. if(S.charAt(0) == '(' && S.charAt(1) == ')') {
  5. return 1 + scoreOfParentheses(S.substring(2));
  6. }
  7. int d = 0;
  8. int end = -1;
  9. for(int i = 0; i < S.length(); i++) {
  10. if(S.charAt(i) == '(') d++;
  11. else d--;
  12. if(d == 0) {
  13. end = i+1;
  14. break;
  15. }
  16. }
  17. return 2 * scoreOfParentheses(S.substring(1, end-1)) + scoreOfParentheses(S.substring(end));
  18. }
  19. }

基本思路基本一致,处理(S`)S``类型时候没有使用栈而是直接通过识别‘('和')’加减计数来找到(S`)

第三题:镜面反射

题目:

有一个特殊的正方形房间,每面墙上都有一面镜子。除西南角以外,每个角落都放有一个接受器,编号为 0, 1,以及 2

正方形房间的墙壁长度为 p,一束激光从西南角射出,首先会与东墙相遇,入射点到接收器 0 的距离为 q

返回光线最先遇到的接收器的编号(保证光线最终会遇到一个接收器)。

示例:

  1. 输入: p = 2, q = 1
  2. 输出: 2
  3. 解释: 这条光线在第一次被反射回左边的墙时就遇到了接收器 2

提示:

  1. 1 <= p <= 1000
  2. 0 <= q <= p

 

链接:https://leetcode-cn.com/contest/weekly-contest-90/problems/mirror-reflection/

分析:

1,利用镜面反射特点,可以假设上面有无限长,光线一直向上走;

2,在1的前提下,每反射一次,向上高度增加q;

3,如果被某个接收器接收到了,说明当前高度是p的整数倍;

4,如果反射偶数次被接收到,则必定是2号接收到;

5,如果最终达到的“高度”是墙面高度p的奇数倍,则被1号接收到;

6,如果最终达到的“高度”是墙面高度p的偶数倍,则被0号接收到;

分析完成后问题就变得很简单了。

AC code:

  1. class Solution {
  2. public:
  3. int mirrorReflection(int p, int q) {
  4. //无限向上延伸,虚拟节点,整数倍获得结果
  5. int counter = ;
  6. while (true)
  7. {
  8. if (q*counter % p == )
  9. {
  10. if (counter % == )
  11. {
  12. return ;
  13. }
  14. if (q*counter / p % == )
  15. {
  16. return ;
  17. }
  18. return ;
  19. }
  20. counter++;
  21. }
  22. }
  23. };

其他:

第一code

  1. class Solution {
  2. public int mirrorReflection(int p, int q) {
  3. int curr = ;
  4. for(int i = ; true; i++) {
  5. curr += q;
  6. curr %= (*p);
  7. if(curr == p) {
  8. if(i% == ) {
  9. return ;
  10. }
  11. else {
  12. return ;
  13. }
  14. }
  15. if(curr == ) {
  16. return ;
  17. }
  18. }
  19. }
  20. }

假设房间向上翻转一次,得到一个p宽,2*p高的长方形,curr记录当前高度(高度范围[0,2*p)),每次反射高度增加q,如果高度等于0,则会被0号接受,如果高度等于p,则被1或者2接收,其中反射奇数次被1号接收,反射偶数次被2号接收。

感觉自己的code有一点不好的就是如果pq很大且数据巧合有可能溢出,映射到2p范围内会更好。

第四题:雇佣 K 名工人的最低成本

题目:

  • 用户通过次数0
  • 用户尝试次数0
  • 通过次数0
  • 提交次数0
  • 题目难度Hard

有 N 名工人。 第 i 名工人的工作质量为 quality[i] ,其最低期望工资为 wage[i] 。

现在我们想雇佣 K 名工人组成一个工资组。在雇佣 一组 K 名工人时,我们必须按照下述规则向他们支付工资:

  1. 对工资组中的每名工人,应当按其工作质量与同组其他工人的工作质量的比例来支付工资。
  2. 工资组中的每名工人至少应当得到他们的最低期望工资。

返回组成一个满足上述条件的工资组至少需要多少钱。

示例 1:

  1. 输入: quality = [10,20,5], wage = [70,50,30], K = 2
  2. 输出: 105.00000

示例 2:

  1. 输入: quality = [3,1,10,10,1], wage = [4,8,2,2,7], K = 3
  2. 输出: 30.66667

提示:

  1. 1 <= K <= N <= 10000,其中 N = quality.length = wage.length
  2. 1 <= quality[i] <= 10000
  3. 1 <= wage[i] <= 10000
  4. 与正确答案误差在 10^-5 之内的答案将被视为正确的。

链接:https://leetcode-cn.com/contest/weekly-contest-90/problems/minimum-cost-to-hire-k-workers/

分析:

速度有点慢,最后20分钟开始处理,没想太多,测试数据到第41个超时了,O(n*n)毫无前途。

TimeOut COde:

  1. class Solution {
  2. public:
  3. double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int K) {
  4. double min = 9999999.0;
  5. for (int i = ; i < quality.size(); i++)
  6. {
  7. vector<double> tmpmin;
  8. double tmp = wage[i]*1.0 / quality[i];
  9. for (int j = ; j < quality.size(); j++)
  10. {
  11. if (quality[j] * tmp < wage[j])
  12. {
  13. continue;
  14. }
  15. else
  16. {
  17. tmpmin.push_back(quality[j] * tmp);
  18. }
  19. }
  20. if (tmpmin.size() < K)
  21. {
  22. continue;
  23. }
  24. else
  25. {
  26. sort(tmpmin.begin(), tmpmin.end());
  27. double tmpsum = ;
  28. for (int index = ; index < K; index++)
  29. {
  30. tmpsum += tmpmin[index];
  31. }
  32. if (tmpsum < min)
  33. {
  34. min = tmpsum;
  35. }
  36. }
  37. }
  38. return min;
  39. }
  40. };

之前想法是算出每个人的“性价比”,即最低要求和工作质量的比值,然后按照该比值衡量所有人,如果该比值下的工资低于最低期望,则不会加入,然后在加入里面选出最低的K个,得到一个总和,按照每个人的标准衡量一遍,所有总和中最低的一个即为符合要求的结果。但是显然O(n*n)效率太低。

比赛到时见后参考别人code,发现按照性价比排序后只需要过一遍就能得到结果。

AC 思路:

单位工作质量所要工资其实和性价比相反,越低越好。但是并不是说比值越低总价就越低,比如一个工作质量/最低工资分别是[1,10]和[20,40],前者比值10,后者比值2,但是只要1个人的话显然需要选择前者。

按照wget/quality进行升序排序,则只需要获得quality总和即可,因为所采用的单位质量价值都是相同的,都采用的最低的一个。由于采用的单位质量价值相同,影响最终结果的只有quality值了,则每次需要将前k个中quality最大的一个移除进行后面的尝试。

在给出的第一组测试数据中,

[10,20,5]

[70,50,30]

计算wget/quality以及排序后结果如下:

[20,5.10]

[50,30,40]

[2.5,,6,7]

从中选择2个,则第一次尝试结果选择前两个,按照6计算,值为(20+5)*6=150

前面有分析过并非wget/quality低的总和就会少,所以需要进行遍历尝试后面的所有值,

当选择下一个时候,由于确定比例会选择7,影响到结果的只有quality值了,20>5,移除20,得到新的组合(5+10)*7=105

对于第二组测试数据,按照同样方式处理排序后结果如下

[10,10,3,1,1]

[2,2,4,7,8]

[0.2,0.2,1.3333,7,8]

选择3个,第一次前三个组合得到(10+10+3)*1.333=30.6667

接下来尝试比例7的,移除前面quality最大的10,(10+3+1)*7=98

尝试比例8 ,移除quality最大的10,(3+1+1)*8=40,则最小值30.6667

AC code:

  1. class Solution {
  2. public:
  3. typedef struct Worker
  4. {
  5. int quality;
  6. int wage;
  7. double ratio;
  8. bool operator< (const Worker &w1)
  9. {
  10. return ratio < w1.ratio;
  11. }
  12. }Worker;
  13.  
  14. double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int K)
  15. {
  16. vector < Worker > workers;
  17. for (int i = ; i < quality.size(); i++)
  18. {
  19. Worker w = { quality[i], wage[i], wage[i] * 1.0 / quality[i] };
  20. workers.push_back(w);
  21. }
  22. //按照性价比排序
  23. sort(workers.begin(), workers.end());
  24. double ret = INT_MAX;
  25. vector<int> tmpqs;//由于性价比是下降的(wget/qualite 上升),即单位质量花费是增加的,所以每次都把前面qualities最大的除去
  26. for (int i = ; i < workers.size(); i++)
  27. {
  28. if (tmpqs.size() < K)
  29. {
  30. tmpqs.push_back(workers[i].quality);
  31. }
  32. if (tmpqs.size() == K)
  33. {
  34. //得到一个组合,判断是否更小
  35. int tmpsumquality=;
  36. int tmpmaxindex = ;
  37. int tmpmaxquality = INT_MIN;
  38. for (int j = ; j < K; j++)
  39. {
  40. tmpsumquality += tmpqs[j];
  41. if (tmpqs[j]>tmpmaxquality)
  42. {
  43. tmpmaxindex = j;
  44. tmpmaxquality = tmpqs[j];
  45. }
  46. }
  47. ret = min(ret, tmpsumquality*workers[i].ratio);
  48. //然后需要移除当前最大qualities
  49. tmpqs.erase(tmpqs.begin() + tmpmaxindex);
  50. }
  51. }
  52. return ret;
  53. }
  54.  
  55. };

其他:

1.DBL_MAX默认是不认的,所以应改为INT_MAX

2.第一code

  1. class Solution {
  2. public double mincostToHireWorkers(int[] quality, int[] wage, int K) {
  3. State[] l = new State[quality.length];
  4. for(int i = 0; i < quality.length; i++) {
  5. l[i] = new State(quality[i], wage[i]);
  6. }
  7. Arrays.sort(l);
  8. double ret = Double.MAX_VALUE;
  9. PriorityQueue<Integer> q = new PriorityQueue<Integer>();
  10. long sum = 0;
  11. for(int i = 0; i < l.length; i++) {
  12. q.add(-l[i].quality);
  13. sum += l[i].quality;
  14. if(q.size() > K) {
  15. sum += q.poll();
  16. }
  17. if(q.size() == K) {
  18. ret = Math.min(ret, sum * l[i].ratio());
  19. }
  20. }
  21. return ret;
  22. }
  23. class State implements Comparable<State> {
  24. public int quality;
  25. public int wage;
  26. public State(int quality, int wage) {
  27. super();
  28. this.quality = quality;
  29. this.wage = wage;
  30. }
  31. public double ratio() {
  32. return wage / (double) quality;
  33. }
  34. public int compareTo(State s) {
  35. return Double.compare(ratio(), s.ratio());
  36. }
  37. @Override
  38. public String toString() {
  39. return "State [quality=" + quality + ", wage=" + wage + "]";
  40. }
  41.  
  42. }
  43. }
  1. a.利用了PriorityQueue自动调整结构的特定,通过poll将最大quality移除掉
    b.通过*-1将最小堆转换为最大堆
    c.
  1. for(int i = 0; i < l.length; i++) {
  2. q.add(-l[i].quality);
  3. sum += l[i].quality;
  4. if(q.size() > K) {
  5. sum += q.poll();
  6. }
  7. if(q.size() == K) {
  8. ret = Math.min(ret, sum * l[i].ratio());
  9. }
  10. }

中,q.poll的有可能就是刚插入进去的,比如某个quality最大,同时ratio也比较大的,完全可以直接跳过,也许能够进一步优化,不过这样做的好处就是形式的统一。

总结:

第四次参加周赛了,虽说仍然没能完成四道题,不过至少四个都懂了,也算是有所收获。和高手比起来,感觉最欠缺的一是速度,二是对语言特性的掌握,三是对常用算法的掌握。

1.速度上来讲第一四道题做完不到20分钟,自己第一个AC都快18分钟了,即使会做没时间做也是白搭,即使是实际项目中,也是越早做出来越早发现问题有时间完善改进。

2.虽说C/C++/C#/Java/Go/Python/Swift/Kotlin/VB等都稍有涉猎,能拿来用,尤其C/C++从开始于到现在都六七年了,不过仅仅限于基础用法的使用,好多高阶用法并没掌握,所以一旦需要要么临时搜索查询,要么根本就不知道有只能笨拙的自己实现,掌握多门语言固然不错,但是要有自己的核心技能语言,暂且选择C++/C#好了,今后不仅要能用,更要用好,要深入理解掌握。

3.见多方能识广,承认有天才,但自认为不是,而大多数问题其实都已经存在且被解决,一方面固然需要提高自己的独立思考能力,另一方面也不能闭门造车,多学习其他人,才能更快的提高。

化用老师的一句话:大量练习,大量做题,大量阅读,自然能够提高。

practice makes prefect

LeetCode之Weekly Contest 90的更多相关文章

  1. LeetCode之Weekly Contest 102

    第一题:905. 按奇偶校验排序数组 问题: 给定一个非负整数数组 A,返回一个由 A 的所有偶数元素组成的数组,后面跟 A 的所有奇数元素. 你可以返回满足此条件的任何数组作为答案. 示例: 输入: ...

  2. LeetCode之Weekly Contest 93

    第一题:二进制间距 问题: 给定一个正整数 N,找到并返回 N 的二进制表示中两个连续的 1 之间的最长距离. 如果没有两个连续的 1,返回 0 . 示例 1: 输入:22 输出:2 解释: 22 的 ...

  3. LeetCode之Weekly Contest 91

    第一题:柠檬水找零 问题: 在柠檬水摊上,每一杯柠檬水的售价为 5 美元. 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯. 每位顾客只买一杯柠檬水,然后向你付 5 美元.10  ...

  4. LeetCode之Weekly Contest 101

    前一段时间比较忙,而且做这个对于我来说挺耗时间的,已经间隔了几期的没做总结了,后面有机会补齐.而且本来做这个的目的就是为了防止长时间不做把编程拉下,不在追求独立作出所有题了.以后完赛后稍微尝试下,做不 ...

  5. LeetCode之Weekly Contest 92

    第一题:转置矩阵 问题: 给定一个矩阵 A, 返回 A 的转置矩阵. 矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引. 示例 1: 输入:[[1,2,3],[4,5,6],[7,8,9] ...

  6. LeetCode Weekly Contest 8

    LeetCode Weekly Contest 8 415. Add Strings User Accepted: 765 User Tried: 822 Total Accepted: 789 To ...

  7. Leetcode Weekly Contest 86

    Weekly Contest 86 A:840. 矩阵中的幻方 3 x 3 的幻方是一个填充有从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等. 给定一个 ...

  8. leetcode weekly contest 43

    leetcode weekly contest 43 leetcode649. Dota2 Senate leetcode649.Dota2 Senate 思路: 模拟规则round by round ...

  9. LeetCode Weekly Contest 23

    LeetCode Weekly Contest 23 1. Reverse String II Given a string and an integer k, you need to reverse ...

随机推荐

  1. Java中对象拷贝的两种方式

    引用的拷贝 //引用拷贝 private static void copyReferenceObject(){ Person p = new Person(23, "zhang") ...

  2. [Android]Android四大组件之Service总结

    一.Service介绍 Service是Android中实现程序后台运行的解决方案,它非常适合用于去执行那些不需要和用户交互而且还要长期运行的task.Service的运行不需要依赖于任何用户界面,即 ...

  3. 硬盘MBR和GPT区别

    似乎人人都可以张嘴就说"我懂电脑",但是总有一些看起来完全不懂但实际上非常基础的东西让"懂"与"不懂"清晰地划清界限.比如UEFI+GPT就 ...

  4. 从两个不同的ServiceProvider说起

    从两个不同的ServiceProvider说起 我们一致在说 ASP.NET Core广泛地使用到了依赖注入,通过前面两个系列的介绍,相信读者朋友已经体会到了这一点.由于前面两章已经涵盖了依赖注入在管 ...

  5. 类成员函数的重载、覆盖和隐藏区别 (C++)

    这是本人第一次写博客,主要是想记录自己的学习过程.心得体会,一是可以方便以后回顾相关知识,二是可以与大家相互学习交流. 关于C++中类成员函数的重载.覆盖和隐藏区别,第一次看到这个问题是在准备找工作的 ...

  6. opencv 形态学膨胀和腐蚀以及开运算和闭运算

  7. 《javascript设计模式》笔记之第十二章:装饰者模式

    一.装饰者模式的作用 为函数或者对象的方法添加一些行为.     二.装饰者模式的原理 装饰者模式不是直接修改对象,而是以要修改的对象为基础,新建一个对象.不过这个新建的对象看起来就像在原对象的基础上 ...

  8. All boundaries are conventions, waiting to be transcended.

    All boundaries are conventions, waiting to be transcended.所有界限都是陈规,等着被打破.

  9. mui实现图片更换(暂未上传)

    页面中有默认的图片,触发type为file的input时,更换图片,这个是mui移动端的项目,算了,不多说,开码 首先,先在html页面中设置样式,样式我就不给了,贴个布局 <div class ...

  10. iOS VIPER架构(一)

    洋葱模型 洋葱模型,是从冰山模型上演变而来的,用来进行层次分析的模型,这是Redux的洋葱模型. action从最外层传入,层层传递直至核心后,经过逐层事件触发,再次被分发出来,执行后续操作. 洋葱模 ...