LeetCode周练Contest-39代码解析(C++)

写在前面:

LeetCode这个网站相比不必多说了吧,凡是IT圈子的人应该都知道这个网站,最近开始准备找工作,当然也免不了上去刷刷题,做一做比较经典的编程题,刚好看到LeetCode有个周练,便报名参加。


进入正题:

概要: 总共4个题,一个半小时的时间安排。题目分级为,一个easy,两个medium,一个hard。


第一题 633. Sum of Square Numbers

题目描述

Given a non-negative integer c, your task is to decide whether there're two integers a and b such thata2 + b2 = c.


c的范围也不是很大,而且也暂时不知道有什么诀窍可以快速解这道题,除了枚举,所以最好的方法就是枚举,妥妥搞定;

代码如下:

class Solution {
public:
    bool judgeSquareSum(int c) {
        // 枚举出0到c的平方根中的数值即可
        for(int i=0;i<=sqrt(c);i++){
            int a = sqrt(c - i*i);
            if(i*i + a*a == c)  return true;
        }
        return false;
    }
};


第二题 635. Design Log Storage System

题目描述

You are given several logs that each log contains a unique id and timestamp. Timestamp is a string that has the following format: Year:Month:Day:Hour:Minute:Second, for example, 2017:01:01:23:59:59. All domains are zero-padded decimal numbers.

Design a log storage system to implement the following functions:

void Put(int id, string timestamp): Given a log's unique id and timestamp, store the log in your storage system.

int[] Retrieve(String start, String end, String granularity): Return the id of logs whose timestamps are within the range from start to end. Start and end all have the same format as timestamp. However, granularity means the time level for consideration. For example, start = "2017:01:01:23:59:59", end = "2017:01:02:23:59:59", granularity = "Day", it means that we need to find the logs within the range from Jan. 1st 2017 to Jan. 2nd 2017.


最近几周测试都有的LeetCode的类设计的题目,这种题理解起来反而很简单,而且也不难,都是偏向于业务的题目;

首先第一个方法很好实现,主要需要考虑的是文件日志系统用什么类型的数据结构来保存,联想到现在都在使用的日志系统,hash结构会比较有优势,便捷而且设计很快速;所以可以用一个hash表来存储日志信息字符串和日志的id,retrieve方法,如果没有最后那个约束条件,那就很简答了,有了约束条件,认真看看约束条件的两端,发现就是个日期大小的比对,找这个区间的日志,由于插入操作不会超过300次,所以不需要快速索引的结构,每一次遍历一遍日志系统的所有日志即可,遍历到每一条都可以代入条件中比对,符合条件即加入;

代码如下:

class LogSystem {
private:
    unordered_map<string, int> _table;
    unordered_map<string, int> _place;
    unordered_map<string, int> init(){
        return unordered_map<string, int>({
            {"Year", 5},
            {"Month", 8},
            {"Day", 11},
            {"Hour", 14},
            {"Minute", 17},
            {"Second", 19}
        });
    }
public:
    LogSystem() {
        _place = init();
    }
    
    void put(int id, string timestamp) {
        _table[timestamp] = id;
    }
    
    vector<int> retrieve(string s, string e, string gra) {
        // 根据给定的截止条件,选择有用的字符串段来比较
        int lens = _place[gra];
        string start = s.substr(0, lens);
        string finish = e.substr(0, lens);
        vector<int> ret;
        for(auto k=_table.begin();k!=_table.end();k++){
            string tmp = k->first.substr(0, lens);
            // 时间上的对比直接可以用字符串的比较函数来做
            if(tmp.compare(start) >= 0 && tmp.compare(finish)<=0)  ret.push_back(k->second);
        }
        return ret;
    }
};

/**
 * Your LogSystem object will be instantiated and called as such:
 * LogSystem obj = new LogSystem();
 * obj.put(id,timestamp);
 * vector<int> param_2 = obj.retrieve(s,e,gra);
 */


第三题 634. Find the Derangement of An Array

题目描述

In combinatorial mathematics, a derangement is a permutation of the elements of a set, such that no element appears in its original position.

There's originally an array consisting of n integers from 1 to n in ascending order, you need to find the number of derangement it can generate.

Also, since the answer may be very large, you should return the output mod 109 + 7.


其实不难的一个题,这个题难就难在,很多人不知道错排公式,参考维基百科

真正写下来就跟斐波那契数列的题目一样,一个for循环就搞定了,记得取模操作;

代码如下:

// 错排公式
class Solution {
public:
    int findDerangement(int n) {
        const int MOD = 1000000007;
        long long a1 = 0, a2 = 1;
        long long ret = 0;
        // 错排公式是一个类似于斐波那契数列的递归公式
        // 按公式来写就好了
        if(n == 1)  return a1;
        else if(n == 2) return a2;
        else{
            for(int i=3;i<=n;i++){
                ret = (i-1)*(a1%MOD + a2%MOD) % MOD;
                a1 = a2; a2 = ret;
            }
        }
        return int((ret+MOD)%MOD);
    }
};


第四题 632. Smallest Range

题目描述

You have k lists of sorted integers in ascending order. Find the smallest range that includes at least one number from each of the k lists.

We define the range [a,b] is smaller than range [c,d] if b-a < d-c or a < c if b-a == d-c.


比较有意思的一个题,和上周那个上最多的课程有点像,利用了动态规划的思想;

用一个优先队列维护n(序列的数量)个元素,初始每个元素都是每个序列的第一位,那就可以用一个循环来做,循环里面,先统计优先队列两头的元素作为范围区间的两端,统计出这一次的范围区间大小,然后将最小的那个元素弹出,插入和这个元素同在一个序列中的元素的最小值;然后循环继续,直到优先队列大小不满足n停止循环,这个时候返回这段时间内找到的范围最小的区间两端,作为结果输出即可;

代码如下:

class Solution {
private:
    typedef struct Node{
        int _val;
        int _row;
        int _index;
        Node(int row, int index, int val):
        _row(row),_index(index),_val(val){}
    }nd;
    struct cmp{
        bool operator()(nd a, nd b){
            return a._val > b._val;
        }
    };
public:
    vector<int> smallestRange(vector<vector<int>>& nums) {
        int rows = nums.size();
        // 使用一个优先队列来维护,注意优先队列小顶堆的构造方法
        priority_queue<nd, vector<nd>, cmp> pq;
        int max_val = INT_MIN;
        // 先将每一个序列的第一位放入优先队列
        for(int i=0;i<rows;i++){
            nd tmp(i, 0, nums[i][0]);
            pq.push(tmp);
            max_val = max(max_val, tmp._val);
        }
        int min_range = INT_MAX;
        int ret_start = 0, ret_end = 0;
        // 因为每一个序列都有且必须选出一个数值,所以优先队列的大小不能变
        // 每一次找到其中最小的那个值,更新一下当前的区间大小
        // 将下一个和从队列中弹出的数值一个序列的数值压入队列,循环判断
        while(pq.size() == rows){
            nd tmp = pq.top(); pq.pop();
            if(max_val - tmp._val < min_range){
                min_range = max_val - tmp._val;
                ret_start = tmp._val;
                ret_end = max_val;
            }
            if(tmp._index + 1 < (int)nums[tmp._row].size()){
                nd tmp_nd(tmp._row, tmp._index+1, nums[tmp._row][tmp._index+1]);
                pq.push(tmp_nd);
                max_val = max(max_val, tmp_nd._val);
            }
        }
        return vector<int>({ret_start, ret_end});
    }
};


总结:

找工作路漫漫,但求不忘初心,回首对得起走过的路。

代码地址:[luuuyi/leetcode-contest]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值