网易雷火19春招实习笔试题(Leetcode 440 && 845)

网易雷火3.17 人工智能研究员(NLP方向)笔试题:两道算法题都是Leetcode原题。(Leetcode) 440 && 845)

LeetCode 386:

再做440之前,可以先做做386;可以算是440的基础题。

题目描述:

Given an integer n, return 1 - n in lexicographical order.

For example, given 13, return: [1,10,11,12,13,2,3,4,5,6,7,8,9].

Please optimize your algorithm to use less time and space. The input size may be as large as 5,000,000.

题解:

题意其实和440是差不多的,给你一个数n,返回一个字典序的数组。
从给的样例推测出字典序是怎么定义的:

  1. 一个数x,如果x*10 < n, 那么x后就是x*10
  2. 如果x*10 >= n, 那么x后接的就是x+1,这里需要注意的需要进位的情况,假如x=19,n= 21,它后面接的应该是2。

下面看看代码:

class Solution {
public:
    vector<int> lexicalOrder(int n) {
        vector<int> res;
        int cur = 1;
        for(int i=1; i<=n; i++){
            res.push_back(cur);
            if(cur * 10 <= n){
                cur *= 10;   
            }else{
                if(cur >= n){
                    cur /= 10;  
                }
                cur += 1;
                while(cur % 10 == 0){
                    cur /= 10;    // 对进位进行处理
                }
            }
        }
        return res;
    }
};

Leetcode 440:

题目链接: https://leetcode.com/problems/k-th-smallest-in-lexicographical-order/

1.题目描述:

输入正整数n, k,n >= k, 找出[1,n]范围内按照字典排序的最小第k个值。

输入描述:
输入两个正整数n,k

输出描述:
一个正整数

示例:
输入
15, 3

输出
11

2.题解:

题意:题意其实其实很明确,就是给你一个数n,输出字典序最小的第k个值;如果之前对字典序不是很熟悉的话,这道题会没什么思路,可以先做一下Leetcode 386,可以说是这道题的基础了。

做完386之后,就会有一个这样的想法,直接拿386的结果输出不就行了吗?事实证明那样做会超时。

可以当成10叉树来处理,先序遍历10叉树的结果就是字典序。但是这里可以借用这种思想,不用真正实现一个10叉树。

思路:

  1. 假如我们从cur节点开始遍历,其实我们只需知道从cur到cur+1节点之间经历了多少节点,如果经历的节点<=k, 那我们再从cur+1往后遍历,k= k-经历的节点。
  2. 如果经历的节点数>k, 说明第k个节点就在cur,cur+1之后,我们就把cur*10(cur的第一个子节点),继续往后遍历。
  3. 怎么计算cur到cur+1 之间经历的节点数量呢?假设n1=curn2=cur+1,n2总是n1最右子节点之后的右节点。
  4. 如果n2<=n,它们之间的节点数为n2 - n1, 如果n2>n,说明最大节点n在n1到n2之间,它们的节点数为n+1-n1;然后n110,n210往后遍历。

代码如下:

class Solution {
public:
    int findKthNumber(int n, int k) {
        long long cur = 1;
        k = k - 1;
        while(k > 0){
            int steps = caldistance(n, cur, cur+1);
            if(steps <= k){
                cur += 1;
                k -= steps;
            }else{
                cur *= 10;  //10叉树的子节点
                k -= 1;
            }
        }
        return cur;
    }
    //计算n1和n2之间的节点数
    int caldistance(int n,long long n1, long long n2){
        int steps = 0;
        while(n1 <= n){
            steps += min((long long)(n+1), n2) - n1;
            n1 *= 10;   
            n2 *= 10;
        }
        return steps;
    }
};

Leetcode 821

同样的做845之前,我们也可以先做1道简单点的练练手,821的方法也和845用的方法类似。

1.题目描述:

Given a string S and a character C, return an array of integers representing the shortest distance from the character C in the string.

Example 1:

Input: S = “loveleetcode”, C = ‘e’
Output: [3, 2, 1, 0, 1, 0, 0, 1, 2, 2, 1, 0]

Note:

S string length is in [1, 10000].
C is a single character, and guaranteed to be in string S.
All letters in S and C are lowercase.

题解:

这道题比较简单,有多种方法可以做,这里推荐2-pass,用一个数组存储最小距离,前后遍历各遍历一次,更新最小距离。

代码如下:

class Solution{
public:
    vector<int> shortestToChar(string S, char C) {
        int n = S.length(),pos = -n;
        vector<int> res(n,n); // 存储
        for(int i=0; i<n; i++){
            if(S[i] == C) pos = i;    //记录当前C的位置
            res[i] = min(res[i], abs(i - pos));
        }
        for(int i=n-1; i>=0; i--){
            if(S[i] == C) pos = i;
            res[i] = min(res[i], abs(i-pos));
        }
        return res;
    }
};

下面这种写法可能更好理解一些,首先先找到所有的C的位置,然后再计算其他点到C的距离。

class Solution {
public:
    vector<int> shortestToChar(string S, char C) {
        int n = S.length();
        vector<int> res(n,n);
        for(int i=0; i<n; i++){
            if(S[i] == C)
                res[i] = 0;   //将所有C的位置标记为0
        }
        for(int i=1; i<n; i++){
            res[i] = min(res[i], res[i-1]+1);  //更新距离
        }
        for(int i=n-2; i>=0; i--){
            res[i] = min(res[i], res[i+1]+1);
        }
        return res;
    }
};

Leetcode 845

1.题目描述:

给定一个数组,代表海拔高度,输出最长连续山脉的长度。以山脉M为例,要求:
1.M.length >= 3, 如果不存在则输出0;
2.存在0, 使得M[0]<......>M[M.length-1]

输入描述:
一系列非负整数

输出描述:
非负整数

示例:
输入
2,1,7,2,5

输出
3

题解:

845也可以用821那种方法,分为两个阶段,山脉的上升阶段和下降阶段,分别用两个数组分别存储上升阶段和下降阶段,然后更新上升阶段,下降阶段和的最大值。

class Solution {
public:
    int longestMountain(vector<int>& A) {
        int n = A.size(), res = 0;
        vector<int> up(n,0),down(n,0);
        for(int i=0; i < n; i++){
            if(i > 0 && A[i] > A[i-1]) up[i] = up[i-1] + 1;  //上升过程
        }
        for(int i=n-2; i>=0; i--){
            if(A[i] > A[i+1]) down[i] = down[i+1] + 1; //下降过程
            if(down[i] && up[i])
                res = max(res, down[i] + up[i] + 1);
        }
        return res;
    }
};

//不使用额外内存
class Solution{
public:
    int longestMountain(vector<int>& A) {
        int res = 0, down = 0, up = 0;
        for(int i=1; i<A.size(); i++){
            if(down && A[i] > A[i-1] || A[i-1] == A[i]) //山脉结束条件
                up = down = 0;
            down += A[i-1] > A[i];
            up += A[i] > A[i-1];
            if(down && up)
                res = max(res, down + up + 1);
        }
        return res;
    }
};

也可以使用双指针法:

class Solution{
public:
    int longestMountain(vector<int>& A) {
        int n = A.size(), down = 0 ,up = 0, res = 0;
        while(up < n-1){
            while(up < n-1 && A[up] >= A[up+1]){ //跳过不是山脉的情况
                up++;
            }
            down = up;  // 起点
            while(down<n-1 && A[down] < A[down+1]){
                down++;  // 上升阶段
            }
            while(down<n-1 && A[down] > A[down+1]){
                down++;  //下降阶段
                res = max(res, down - up + 1);
            }
            up = down; // 更新起点
        }
        return res;
    }
};

更多代码可以查看Github

你可能感兴趣的:(Leetcode,笔试)