0
点赞
收藏
分享

微信扫一扫

面经整理计划——第八弹

算法&&八股文&&其他

文章目录


一、算法篇

  1. 有一个长度为 n 的按严格升序排列的整数数组 nums ,在实行 search 函数之前,在某个下标 k 上进行旋转,使数组变为

     [nums[k],nums[k+1],.....,nums[nums.length-1],nums[0],nums[1],.......,nums[k-1]]
    

    给定旋转后的数组 nums 和一个整型 target ,请你查找 target 是否存在于 nums 数组中并返回其下标(从0开始计数),如果不存在请返回-1。

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if not nums:
            return -1
        l, r = 0, len(nums) - 1
        while l <= r:
            mid = (l + r) // 2
            if nums[mid] == target:
                return mid
            if nums[0] <= nums[mid]:
                if nums[0] <= target < nums[mid]:
                    r = mid - 1
                else:
                    l = mid + 1
            else:
                if nums[mid] < target <= nums[len(nums) - 1]:
                    l = mid + 1
                else:
                    r = mid - 1
        return -1
  1. 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)
class Solution_bfs {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector <vector <int>> ret;
        if (!root) {
            return ret;
        }

        queue <TreeNode*> q;
        q.push(root);    //i = 1 的时候,队列里面只有 root
        while (!q.empty()) {
            int currentLevelSize = q.size();
            ret.push_back(vector <int> ());
            for (int i = 1; i <= currentLevelSize; ++i) {
                auto node = q.front(); q.pop();
                ret.back().push_back(node->val);
                if (node->left) q.push(node->left);
                if (node->right) q.push(node->right);
            }
        }
        
        return ret;
    }
};
//******************************************//
class Solution_dfs {
public:
    /**
     * 
     * @param root TreeNode类 
     * @return int整型vector<vector<>>
     */
    //前序遍历模板;
    void f(TreeNode* root,int level,vector<vector<int>> &res){
        if(!root)return ;
        if(level>=res.size()){//最新的深度,申请一个数组存储;
            res.push_back(vector<int> {});
        }
        res[level].push_back(root->val);
        f(root->left,level+1,res);//遍历左子树;
        f(root->right,level+1,res);//遍历右子树;
    }

    vector<vector<int> > levelOrder(TreeNode* root) {
        // write code here
        vector<vector<int>> res;//存储最终结果;
        f(root,0,res);//前序遍历;
        return res;//返回结果;
    }
};
  1. 给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false
class Solution(object):
    def validateStackSequences(self, pushed, popped):
        j = 0
        stack = []
        for x in pushed:
            stack.append(x)
            while stack and stack[-1] == popped[j]:
                stack.pop()
                j += 1

        return j == len(popped)
  1. 给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值,整数除法仅保留整数部分。
class Solution:
    def calculate(self, s: str) -> int:
        n = len(s)
        stack = []
        preSign = '+'
        num = 0
        for i in range(n):
            if s[i] != ' ' and s[i].isdigit():
                num = num * 10 + ord(s[i]) - ord('0')
            if i == n - 1 or s[i] in '+-*/':
                if preSign == '+':
                    stack.append(num)
                elif preSign == '-':
                    stack.append(-num)
                elif preSign == '*':
                    stack.append(stack.pop() * num)
                else:
                    stack.append(int(stack.pop() / num))
                preSign = s[i]
                num = 0
        return sum(stack)
  1. 判断一个点是否在给定五角星内部
  1. 对于一个长度为 n 字符串,我们需要对它做一些变形
    首先这个字符串中包含着一些空格,就像"Hello World"一样,然后我们要做的是把这个字符串中由空格隔开的单词反序,同时反转每个字符的大小写。
    比如"Hello World"变形后就变成了"wORLD hELLO"。
class Solution_stack {
public:
    string trans(string s, int n) {
        stack<string> sk;
        string str;
        s.push_back(' ');//避免特判
        for(int i = 0; i <= n; ++i) {//注意此时单词长度为n+1
            if(s[i] == ' ') {
                sk.push(str);//以空格为界进行压栈
                str = ""; 
            } else {
                if(s[i] >= 'a' && s[i] <= 'z') { 
                    str += (s[i] - 'a' + 'A'); 
                } else { 
                    str += (s[i] - 'A' + 'a'); 
                } 
            }
        } 
        string ans; 
        while(!sk.empty()) { 
            //从栈中逐个弹出单词 
            ans += sk.top(); sk.pop(); 
            ans.push_back(' '); 
        } 
        ans.pop_back();//去除最后一个单词后的空格 
        return ans;
    }
};

class Solution_twoPtr {
public:
    string trans(string s, int n) {
         reverse(s.begin(), s.end());//将整个字符串进行翻转
        int i = 0, j = 0;
        while(i < n) { 
            j = i; 
            while(j < n && s[j] != ' ') { 
                //读取一个单词并同时进行大小写转换 
                if(s[j] >= 'a' && s[j] <= 'z') { 
                    s[j] += ('A' - 'a'); 
                } else { 
                    s[j] += ('a' - 'A'); 
                } 
                ++j; 
             }
            reverse(s.begin() + i, s.begin() + j);//翻转这个单词 
            i = j + 1; 
        }
        return s;
    }
};
  1. 给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow = head, *fast = head;
        while (fast != nullptr) {
            slow = slow->next;
            if (fast->next == nullptr) {
                return nullptr;
            }
            fast = fast->next->next;
            if (fast == slow) {
                ListNode *ptr = head;
                while (ptr != slow) {
                    ptr = ptr->next;
                    slow = slow->next;
                }
                return ptr;
            }
        }
        return nullptr;
    }
};
  1. 搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。
    分析:middle(lc面试题 10.03)
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if not nums:
            return -1
        left, right = 0, len(nums) - 1
        while left < right:                                         # 循环结束条件left==right
            mid = (left + right) >> 1
            if nums[left] < nums[mid]:                              # 如果左值小于中值,说明左边区间升序 
                if nums[left] <= target and target <= nums[mid]:    # 如果目标在左边的升序区间中,右边界移动到mid
                    right = mid
                else:                                               # 否则目标在右半边,左边界移动到mid+1
                    left = mid + 1
            elif nums[left] > nums[mid]:                            # 如果左值大于中值,说明左边不是升序,右半边升序
                if nums[left] <= target or target <= nums[mid]:     # 如果目标在左边,右边界移动到mid
                    right = mid
                else:                                               # 否则目标在右半边的升序区间中,左边界移动到mid+1
                    left = mid + 1
            elif nums[left] == nums[mid]:                           # 如果左值等于中值,可能是已经找到了目标,也可能是遇到了重复值
                if nums[left] != target:                            # 如果左值不等于目标,说明还没找到,需要逐一清理重复值
                    left += 1                                        
                else:                                               # 如果左值等于目标,说明已经找到最左边的目标值
                    right = left                                    # 将右边界移动到left,循环结束
        return left if nums[left] == target else -1                 # 返回left,或者-1
  1. 给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能从 s 获得的 有效 IP 地址 。你可以按任何顺序返回答案。
    有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。
    例如:“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “192.168@1.1” 是 无效 IP 地址。
class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        SEG_COUNT = 4
        ans = list()
        segments = [0] * SEG_COUNT
        
        def dfs(segId: int, segStart: int):
            # 如果找到了 4 段 IP 地址并且遍历完了字符串,那么就是一种答案
            if segId == SEG_COUNT:
                if segStart == len(s):
                    ipAddr = ".".join(str(seg) for seg in segments)
                    ans.append(ipAddr)
                return
            
            # 如果还没有找到 4 段 IP 地址就已经遍历完了字符串,那么提前回溯
            if segStart == len(s):
                return

            # 由于不能有前导零,如果当前数字为 0,那么这一段 IP 地址只能为 0
            if s[segStart] == "0":
                segments[segId] = 0
                dfs(segId + 1, segStart + 1)
            
            # 一般情况,枚举每一种可能性并递归
            addr = 0
            for segEnd in range(segStart, len(s)):
                addr = addr * 10 + (ord(s[segEnd]) - ord("0"))
                if 0 < addr <= 0xFF:
                    segments[segId] = addr
                    dfs(segId + 1, segEnd + 1)
                else:
                    break
                    
        dfs(0, 0)
        return ans

二、八股文

1.卷积是如何实现INT8纯整型计算的 (1, 2, 3)
2. auc指标及其实现(1,  2, code)
3. 交叉熵的优缺点(1, 2)
4.xgboost原理,xgboost特征选择,如何评估特征重要性(1, 2, 3, 4)


三、其他


待解决 (欢迎评论区或私信解答)

  1. 给出一个有序数组A和一个常数C,求所有长度为C的子序列中的最大的间距D。
    一个数组的间距的定义:所有相邻两个元素中,后一个元素减去前一个元素的差值的最小值. 比如[1,4,6,9]的间距是2.
    例子:A:[1,3,6,10], C:3。最大间距D应该是4,对应的一个子序列可以是[1,6,10]。

  2. 给定一个数字矩阵和一个数字target,比如5。从数字1开始(矩阵中可能有多个1),每次可以向上下左右选择一个方向移动一次,可以移动的条件是下个数字必须是上个数字+1,比如1必须找上下左右为2的点,2必须找上下左右为3的点,以此类推。求到达target一共有几个路径。

  3. 给定一个只包含0和1的字符串,判断其中有无连续的1。若有,则输出比该串大的无连续1的最小值串。若无,则不做操作
    例:给定 ‘11011’ ,则输出 ‘100000’ ;给定 ‘10011’ ,则输出 ‘10100’
    (参考:感觉有点像字符串匹配,只要第一次匹配到’011’模式串就改成’100’,然后后面全部置0,仅供参考)

  4. 给定两个字符串 target 和 block,对bolck进行子串选取,选取出的子串可对target进行重构。问最少需要选取多少block子串进行重构。(子串须保持相对顺序,但不要求连续)
    例:(1)target = ‘aaa’ ,block = ‘ab’ ,输出为3。即分别选取block子串中的 ‘a’、 ‘a’、 ‘a’;(2)target = ‘abcd’ ,block = ‘bcad’ ,输出为2。即分别选取子串 ‘a’、‘bcd’

    (参考:双指针 i,j 分别遍历target和block,j会回溯。时间复杂度是len(target)*len(block))


举报

相关推荐

0 条评论