LeetCode之Weekly Contest 101

Stella981
• 阅读 582

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

第一题:问题

问题:900. RLE 迭代器

编写一个遍历游程编码序列的迭代器。

迭代器由 RLEIterator(int[] A) 初始化,其中 A 是某个序列的游程编码。更具体地,对于所有偶数iA[i] 告诉我们在序列中重复非负整数值 A[i + 1] 的次数。

迭代器支持一个函数:next(int n),它耗尽接下来的  n 个元素(n >= 1)并返回以这种方式耗去的最后一个元素。如果没有剩余的元素可供耗尽,则  next 返回 -1

例如,我们以 A = [3,8,0,9,2,5] 开始,这是序列 [8,8,8,5,5] 的游程编码。这是因为该序列可以读作 “三个零,零个九,两个五”。

示例:

输入:["RLEIterator","next","next","next","next"], [[[3,8,0,9,2,5]],[2],[1],[1],[2]]
输出:[null,8,8,5,-1]
解释:
RLEIterator 由 RLEIterator([3,8,0,9,2,5]) 初始化。
这映射到序列 [8,8,8,5,5]。
然后调用 RLEIterator.next 4次。

.next(2) 耗去序列的 2 个项,返回 8。现在剩下的序列是 [8, 5, 5]。

.next(1) 耗去序列的 1 个项,返回 8。现在剩下的序列是 [5, 5]。

.next(1) 耗去序列的 1 个项,返回 5。现在剩下的序列是 [5]。

.next(2) 耗去序列的 2 个项,返回 -1。 这是由于第一个被耗去的项是 5,
但第二个项并不存在。由于最后一个要耗去的项不存在,我们返回 -1。

提示:

  1. 0 <= A.length <= 1000
  2. A.length 是偶数。
  3. 0 <= A[i] <= 10^9
  4. 每个测试用例最多调用 1000 次 RLEIterator.next(int n)
  5. 每次调用 RLEIterator.next(int n) 都有 1 <= n <= 10^9 。

链接:https://leetcode-cn.com/contest/weekly-contest-101/problems/rle-iterator/

分析:

看到例子没怎么想,直接试图构建原始数据,然后next更新下标,根据下标直接返回,结果测试中数据很大,懒惰,想当然了。

最终做法是将原始数据建立坐标和值的映射关系,一个data数组,一个index数组(其实就相当于map),然后有变量记录下标,下标值大于index值后,更新到下一个,如果在其范围内,返回对应的数字。

比如例子给出的数据,处理后是:

3 8

5 5

表示坐标3一下的对应值是8,5一下的对应值是5。

 AC Code:

class RLEIterator {
public:
        vector<long long> datas; //保存数据
    vector<long long> sizes; //保存坐标
    long long location; //数组坐标
    long long datalocation; //当前数字坐标
        long long size; //总个数
        int endflag; //一旦某个坐标返回-1,后面next都返回-1,做一个优化
public:
    RLEIterator(vector<int> A)
    {
        this->location = 0; this->datalocation = 0; this->size = 0; this->endflag = 0; for (int i = 0; i < A.size(); i+=2) { this->size += A[i]; if (A[i] == 0) { continue; } if (i == 0) { this->sizes.emplace_back(A[i]); } else { this->sizes.emplace_back(A[i] + this->sizes[this->sizes.size()-1]); } this->datas.emplace_back(A[i+1]); } } int next(int n) { if (this->endflag == 1) { return -1; } if (this->datalocation + n>=this->size) { this->endflag = 1; return -1; } this->datalocation += n; while (this->datalocation > this->sizes[this->location]) { this->location += 1; } return this->datas[this->location]; } }; 

其他:

1.第一code

class RLEIterator {
        int[] a;
        int p = 0;
        
        public RLEIterator(int[] A) {
            a = A;
            p = 0;
        }
        
        public int next(int n) {
            if(p >= a.length)return -1;
            n--;
            int ret = -1;
            while(n > 0){
                if(p >= a.length)return -1;
                int ex = Math.min(a[p], n);
                n -= ex;
                a[p] -= ex;
                if(a[p] > 0){
                    break;
                }else{
                    p += 2;
                }
            }
            while(p < a.length && a[p] == 0)p += 2;
            if(p < a.length)ret = a[p+1];
            n = 1;
            
            while(n > 0){
                if(p >= a.length)return -1;
                int ex = Math.min(a[p], n);
                n -= ex;
                a[p] -= ex;
                if(n == 0)break;
                p += 2;
            }
            return ret;
        }
    }    

2.中间有遇到一个问题,思路什么都多,提交错误,然后调试发现数据范围int是不够的。

第二题:901. 股票价格跨度

问题:

编写一个 StockSpanner 类,它收集某些股票的每日报价,并返回该股票当日价格的跨度。

今天股票价格的跨度被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。

例如,如果未来7天股票的价格是 [100, 80, 60, 70, 60, 75, 85],那么股票跨度将是 [1, 1, 1, 2, 1, 4, 6]

示例:

输入:["StockSpanner","next","next","next","next","next","next","next"], [[],[100],[80],[60],[70],[60],[75],[85]]
输出:[null,1,1,1,2,1,4,6]
解释:
首先,初始化 S = StockSpanner(),然后:
S.next(100) 被调用并返回 1,
S.next(80) 被调用并返回 1,
S.next(60) 被调用并返回 1,
S.next(70) 被调用并返回 2,
S.next(60) 被调用并返回 1,
S.next(75) 被调用并返回 4,
S.next(85) 被调用并返回 6。

注意 (例如) S.next(75) 返回 4,因为截至今天的最后 4 个价格
(包括今天的价格 75) 小于或等于今天的价格。

提示:

  1. 调用 StockSpanner.next(int price) 时,将有 1 <= price <= 10^5
  2. 每个测试用例最多可以调用  10000StockSpanner.next
  3. 在所有测试用例中,最多调用 150000 次 StockSpanner.next
  4. 此问题的总时间限制减少了 50%。

链接:https://leetcode-cn.com/contest/weekly-contest-101/problems/online-stock-span/

分析:

如果前一天的股票不大于今天的股票,就可以将其添加的今天的上面,然后将前一天的边界处再次进行判断。

如给出的例子中,

1

2

3

4

5

6

7

100

80

60

70

60

75

85

第一天100,最大连续天数1

第二天80,小于昨天,最大连续天数1

第三条60,小于昨天,最大连续天数1

第四天70,大于昨天,最大连续天数为1+昨天的连续天数1=2,同时查看前一天的80,大于70,第四天最大连续天数2

第五天60,小于昨天,最大连续天数1

第六天75,大于昨天,加上昨天的连续天数1+1,同时查看边界,即第四天,70<75,加上第四天的连续长度2,查看这一天的边界,即第二天,80>75,则最终最大连续天数为1+1+2=4

第七天85,大于昨天,最大连续天数1+4,查看前一天的边界,即第2天,80<85,加上改天的长度1,查看对比边界100>85,最终连续长度1+4+1=6

AC Code:

class StockSpanner {
public:
private:
    vector<long long> datas;
    vector<long long> longest;
public:
    StockSpanner()
    {

    }

    int next(int price)
    {
        if (this->datas.size() == 0)
        {
            //diyici
            this->datas.emplace_back(price);
            this->longest.emplace_back(1);
            return 1;
        }
        else
        {
            this->datas.emplace_back(price);
            if (this->datas[this->datas.size() - 2] > price)
            {
                this->longest.emplace_back(1);
                return 1;
            }
            else
            {
                
                int localindex = this->longest.size()-1;
                int ret = 1+this->longest[localindex];
                localindex -= this->longest[localindex];
                while (localindex>=0 && price>= this->datas[localindex])
                {
                    ret += this->longest[localindex];
                    localindex -= this->longest[localindex];
                }
                this->longest.emplace_back(ret);
                return ret;

            }
                        
        }
    }
};

其他:

1.第一code

class StockSpanner {
        int[] stack;
        int[] value;
        int sp;
        int gen = 0;

        public StockSpanner() {
            stack = new int[11000];
            value = new int[11000];
            sp = 0;
            gen = 0;
        }
        
        public int next(int price) {
            while(sp > 0 && value[sp-1] <= price){
                sp--;
            }
            int ret = gen - (sp == 0 ? -1 : stack[sp-1]);
            stack[sp] = gen++;
            value[sp] = price;
            sp++;
            return ret;
        }
    }    

第三题:最大为 N 的数字组合

问题:

我们有一组排序的数字 D,它是  {'1','2','3','4','5','6','7','8','9'} 的非空子集。(请注意,'0'不包括在内。)

现在,我们用这些数字进行组合写数字,想用多少次就用多少次。例如 D = {'1','3','5'},我们可以写出像 '13', '551', '1351315' 这样的数字。

返回可以用 D 中的数字写出的小于或等于 N 的正整数的数目。

示例 1:

输入:D = ["1","3","5","7"], N = 100
输出:20
解释:
可写出的 20 个数字是:
1, 3, 5, 7, 11, 13, 15, 17, 31, 33, 35, 37, 51, 53, 55, 57, 71, 73, 75, 77.

示例 2:

输入:D = ["1","4","9"], N = 1000000000
输出:29523
解释:
我们可以写 3 个一位数字,9 个两位数字,27 个三位数字,
81 个四位数字,243 个五位数字,729 个六位数字,
2187 个七位数字,6561 个八位数字和 19683 个九位数字。
总共,可以使用D中的数字写出 29523 个整数。

提示:

  1. D 是按排序顺序的数字 '1'-'9' 的子集。
  2. 1 <= N <= 10^9

链接:https://leetcode-cn.com/contest/weekly-contest-101/problems/numbers-at-most-n-given-digit-set/

分析:

1.如果数字位数低于目标数字,肯定满足要求

2.如果位数相同,如果首位小于目标数字最高位,则剩下数字可以随意组合

通用的,如果最高位数字、次高位数字相同,剩下的位数可以随意组合,如此递归直到数字完全相同。

3.n个数字,组成m位数字,有n^m种组发。

AC Code:

class Solution {
public:

int atMostNGivenDigitSet(vector<string>& D, int N)
    {
        //先组成所有的数字,然后挑选满足条件的结果
        //首先拿到N的位数length,从D中挑选任意数字累计重复length次,得到所有可能的数字
        //大小为D.size^length,太多了,需要优化
        //关键是位数相同的一个,低于的位数可以直接计算指数,位数低一定满足
        //更关键的是最高位,
        
        long long ret = 0;
        vector<int> datas;
        for (long long i = 0; i < D.size(); i++)
        {
            datas.emplace_back(D[i][0] - '0');
        }
        if (GetLength(N) == 1)
        {
            return GetLessOrEqlN(datas, N).size();
        }
        long long num1 = GetSameLengthNums(datas, N);
        long long num2 = GetLowLengthNums(datas.size(), N / 10);
        ret = num1 + num2;
        return ret;
    }
    long long GetLowLengthNums(int size, int N)
    {        
        long long length = GetLength(N);
        if (size == 1)  //1个数字组成任何位数数字都只有1种组发
        {
            return length;
        }
        long long ret = 0;
        while (length>0)
        {
            ret += (int)pow(size, length);
            length--;
        }
        return ret;
    }
    long long GetSameLengthNums(vector<int> datas, int N)
    {
        long long ret = 0;
   
        while (N)
        {
            if (N < 10)
            {
                ret += GetLessOrEqlN(datas, N).size();  //如果是10以下的数字,直接找到所有不大于该数的个数即可
                break;
            }
            int length = GetLength(N);
            int num = N / ((int)pow(10, length-1));
            ret += GetLessN(datas, num).size()*(int)pow(datas.size(), length-1);
            int findflag = 0;      //如果高位有相同的,还需要对比次高位,直到拼出相等数字       
            for (int i = 0; i < datas.size(); i++)
            {
                int tmp = datas[i] - num;
                if (tmp==0)
                {
                    findflag = 1;
                    break;
                }
            }
            if (findflag == 0)
            {
                //cout << "no target,break" << endl;
                break;
            }            
            N %= ((int)pow(10, length - 1));
                if (GetLength(N) + 1 != length)
            {
                break;
            }
        }

        return ret;
    }
    vector<int> GetLessN(vector<int> org, int n)
    {
        vector<int> ret;
        for (int i = 0; i < org.size(); i++)
        {
            if (org[i] < n)
            {
                ret.emplace_back(org[i]);
            }
        }
        return ret;
    }
    vector<int> GetLessOrEqlN(vector<int> org, int n)
    {
        vector<int> ret;
        for (int i = 0; i < org.size(); i++)
        {
            if (org[i] <= n)
            {
                ret.emplace_back(org[i]);
            }
        }
        return ret;
    }
    int GetLength(int N)
    {
        int ret = 0;
        while (N)
        {
            ret++;
            N /= 10;
        }
        return ret;
    }
};

其他:

1.第一code

class Solution {
        public int atMostNGivenDigitSet(String[] D, int N) {
            int mask = 0;
            for(String s : D){
                mask ^= 1<<s.charAt(0)-'0';
            }
            char[] s = Integer.toString(N+1).toCharArray();
            long dp = 0;
            int e = 1;
            for(int i = 0;i < s.length;i++){
                dp *= Integer.bitCount(mask);
                
                for(int j = 1;j < s[i]-'0';j++){
                    if(mask<<~j<0){
                        dp+=e;
                    }
                }
                if(i > 0){
                    dp += Integer.bitCount(mask);
                }
                if(mask<<~(s[i]-'0')>=0){
                    e = 0;
                }
            }
            return (int)dp;
        }
    }    

直接将N+1,避免了==的额外处理,这个思路非常好。

2.手残将复制写作==,折腾了半天才发现,单步调试直接优化跳过了,还以为数据类型问题导致不能直接对比。

3.做的时候大体code完成之后简单测试通过,提价错误,解决提交,又有错误,再次解决,感觉在不停的在打补丁,一方面说明思路不完整,没能直接覆盖到所有情况,另一方面进一步暴露出测试数据设计上的不足,之前就有发现这个问题,不过感觉没多少提高,实际上在周赛的时候一般只是测试下例子,基本没有构造数据测试,关键是没时间,其次能力不足,难以短时间构建出合理的数据。好在编写的测试函数能够将所有的测试用例都保存下,一旦修改code可以将之前测过的所有数据测一遍,避免解决一个问题导致前面的测例failed。

第四题:DI 序列的有效排列

问题:

我们给出 S,一个源于 {'D', 'I'} 的长度为 n 的字符串 。(这些字母代表 “减少” 和 “增加”。)
有效排列 是对整数 {0, 1, ..., n} 的一个排列 P[0], P[1], ..., P[n],使得对所有的 i

  • 如果 S[i] == 'D',那么 P[i] > P[i+1],以及;
  • 如果 S[i] == 'I',那么 P[i] < P[i+1]

有多少个有效排列?因为答案可能很大,所以请返回你的答案模 10^9 + 7.

示例:

输入:"DID"
输出:5
解释:
(0, 1, 2, 3) 的五个有效排列是:
(1, 0, 3, 2)
(2, 0, 3, 1)
(2, 1, 3, 0)
(3, 0, 2, 1)
(3, 1, 2, 0)

提示:

  1. 1 <= S.length <= 200
  2. S 仅由集合 {'D', 'I'} 中的字符组成。

链接:https://leetcode-cn.com/contest/weekly-contest-101/problems/valid-permutations-for-di-sequence/

分析:

这种大数据类型一直都很头疼,放弃不折腾了 

AC Code:

其他:

第一code

class Solution {
        public int numPermsDISequence(String S) {
            int n = S.length();
            int[] a = new int[n+1];
            int p = 0;
            int len = 0;
            for(int i = 0;i < n;i++){
                if(S.charAt(i) == 'D'){
                    len++;
                }else{
                    a[p++] = len+1;
                    len = 0;
                }
            }
            a[p++] = len+1;
            
            int mod = 1000000007;
            long[][] C = new long[400 + 1][400 + 1];
            for (int i = 0; i <= 400; i++) {
                C[i][0] = 1;
                for (int j = 1; j <= i; j++) {
                    C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
                    if (C[i][j] >= mod)
                        C[i][j] -= mod;
                }
            }

            a = Arrays.copyOf(a, p);
            long[] dp = new long[p+1];
            dp[0] = 1;
            int all = 0;
            for(int i = 1;i <= p;i++){
                all += a[i-1];
                int s = 0;
                for(int j = i-1, sgn = 1;j >= 0;j--, sgn = -sgn){
                    s += a[j];
                    dp[i] += dp[j] * C[all][s] * sgn;
                    dp[i] %= mod;
                }
                if(dp[i] < 0)dp[i] += mod;
            }
            return (int)dp[p];
        }
    }    
检举作弊 

总结:

TI8那一次没参加周赛,其他的几次都参加了,但是总结没做,有的是有完成四道题,有的还没做完,还有一个有写到草稿箱,第四个没完成所以没发布。工作了,有很多事情要做,很难专注算法的提高与练习,而且本身天赋有限,有些问题如果想搞懂需要花太多的时间与精力,虽说当初开始的目的就是增长见识,性格使然还是一直在尽量做出所有问题,努力追求完美,结果更不完美。以后要逐渐学会放弃,不管做到什么程度,尽量周二晚前完成总结。

学习不易,坚持更难,继续努力吧。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
OpenCV访问像素点
三种方法迭代器创建一个Mat::Iterator对象it,通过itMat::begin()来的到迭代首地址,递增迭代器知道itMat::end()结束迭代;while(it!Scr.end<Vec3b()){//(it)00;//蓝色通道置零;
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这