文章目录
0918畅行智能
第一题青蛙爬楼梯(leetcode 70)
简单分析就是个斐波拉契数列
class Solution {
public:
// n是一个正整数
//本问题其实常规解法可以分成多个子问题,爬第n阶楼梯的方法数量,等于 2 部分之和
//爬上 n-1n−1 阶楼梯的方法数量。因为再爬1阶就能到第n阶
//爬上 n-2n−2 阶楼梯的方法数量,因为再爬2阶就能到第n阶
int climbStairs(int n) {
if(n<=2){
return n;
}
// base case
//因为n是需要我们求的变量,也就是第n阶个楼梯, 而对于数组来说就是dp[n]所以数组的size为n+1
vector<int> dp(n+1); // 我个人是不建议为f[0]设置值的,循环里面应该从3开始。 题目说到了n是一个正整数
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n; i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
};
第二题 55. 跳跃游戏
主要思路:
见题解
调用递归树:
根据所画的递归树代码如下:
class Solution
{
public:
bool canJump(vector<int> &nums)
{
if (0 == nums.size())
return false;
return dfs(0, nums);
}
bool dfs(int index, vector<int> &nums)
{
//递归的终止条件
if (index >= nums.size() - 1)
{
return true;
}
//根据nums[index]表示要循环多少次,index是当前我们能到达的位置
//在这个基础上有 index+1,index+2.... index+i=nums[index]种跳跃选择
for (int i = 1; i <= nums[index]; i++)
{
# index+i为新的index
if (dfs(index+i, nums))
{
return true;
}
}
return false;
}
};
超时,那么加memo, 比较特殊memo用unordered_map
class Solution
{
public:
bool canJump(vector<int> &nums)
{
if (0 == nums.size())
return false;
unordered_map<int, bool> memo;
return dfs(0, nums, memo);
}
bool dfs(int index, vector<int> &nums,unordered_map<int, bool>& memo)
{
//递归的终止条件
if (index >= nums.size() - 1)
{
return true;
}
// if memo里面有这个f(i)的值直接返回
//if(cache.containsKey(index))
if(memo.find(index)!=memo.end()){
return memo[index];
}
//根据nums[index]表示要循环多少次,index是当前我们能到达的位置
//在这个基础上有 index+1,index+2.... index+i=nums[index]种跳跃选择
for(int i=1; i<=nums[index];i++){
if(dfs(index+i, nums, memo)){
memo[index]=true;
return true;
}
}
memo[index]=false;
return false;
}
};
用这个方法比较好理解:(贪心大法好)[https://leetcode-cn.com/problems/jump-game/solution/tan-xin-cong-qian-wang-hou-tiao-cong-hou-wang-qian/]
bool canJump(vector<int> &nums)
{
int start =0;
int end=0;
while(start<=end && end<nums.size()-1){
end=max(end, nums[start]+start);
start++;
}
return end>=nums.size()-1;
}
类似的题:
主线科技的交流:
收获很多,因为很多东西做的类似(有禾赛科技的面试感觉,说明大家做的东西很类似)
- 首先说,就是这个depth_cluster, 如何针对过分割现象进行改进,我提到通过skip的方式去搜索,然后提到隔行隔格子去搜索,面试官很专业提到可以用降采样的方式
- 就是这个cvc cluster问我他的一些比较特别的点,中间密,两边疏,问我curved voxel有没有作相应的划分,我回答没有,但是可以根据这个特点去进行改进
- l-shape面试官问我为什么要用l的shape,这样有什么优点,我说车身侧面看是l形的点云,然后面试官的回答,l shape是和后面的基于l feature的跟踪息息相关的,首先这个l型估计的角点很稳定,其次就是目标的开并角变化需要运动模型的转换这个和角点有关,什么时候需要转换这个是需要设置相应的条件的不然就是转换太频繁,这个也和本车的传感器布置有关,布置在不同的位置,转换的条件也可以设置。
- 最后考察了我一点多线程的知识,就是主线程想获得分支线程的共享内存上的值,目前分支线程没有执行完,这个我就提到用c++11 std::future类对象来解决。
主线科技的笔试题:
一个是链表的倒序,链表的归并排序
tostring的底层实现
虚函数的调用,实现不同类指针调用,不同的输出;
但是我在想友元函数能够实现这样的功能吗?
笔试题目1tostring()的底层实现
// tostring的底层实现
华为919机试
9.9华为机试第一题
- @author tangjf (ryontang@163.com)
- @brief 完美排列
- 现在店员记录下了玩具店里面N个玩具的排列顺序,现在想让你帮忙找找这个排列里面有没有完美排列。如果有,返回最先出现的下标(下标从1开始计算),如果没有,返回0。
输入:
第一行一个整数K表示完美排列的长度
第二行K个整数Ai,表示完美排列从左到右的外观值
第三行K个整数Bi,表示完美排列从左到右的价格值
第四行一个正整数N,表示当前玩具店里面排列的玩具数量
第五行N个整数Ci,表示玩具店里从左到右的外观值
第六行N个整数Di,表示玩具店里从左到右的价格值
例子
3
1 2 3
3 2 1
1 2 3 3 2 1
3 2 1 1 2 3
返回1,因为从1号开始满足完美排列
#include <iostream>
#include <vector>
using namespace std;
struct good
{
int outlook;
int price;
};
bool isEqual(const good& v1, const good& v2)
{
if (v1.outlook == v2.outlook && v1.price == v2.price) return true;
return false;
}
int main()
{
int n; // 完美排列的长度
cin >> n;
vector<good> perfect_order(n);
for (int i = 0; i < n; ++i)
{
cin >> perfect_order[i].outlook;
}
for (int i = 0; i < n; ++i)
{
cin >> perfect_order[i].price;
}
int N; // 表示当前玩具店里面排列的玩具数量
vector<good> tool_order(N);
for (int i = 0; i < N; ++i)
{
cin >> tool_order[i].outlook;
}
for (int i = 0; i < N; ++i)
{
cin >> tool_order[i].price;
}
// 完成输入,开始kmp匹配
// 相等tool_order[i]=perfect_order[i]定义一个条件即里面的元素都相等
// 模式串:perfect_order
// 文本串:tool_order
// 也可以用暴力的写法:比较适合实战
}
// KMP求前缀表即next数组:由模式串abaf推导得来
// 再拿模式串abaf去匹配文本串aabaabaaf
void getNext(int* next, const string& s)
{
// 1.初始化
int j = 0; // abaf:前缀末尾位置aba_last,j指向a
// j的含义还包含:/i之前的子串包括i/的最大相等前后缀的长度(PMT)
next[0] = 0; // 一个字母a,PMT=0
// 2.前后缀不相同的情况:j要向前回退
for (int i = 1; i < s.size(); ++i) // i是后缀末尾位置,j指向f
{
while (j > 0 && s[i] != s[j])
{ // j要保证大于0,因为下面有取j-1作为数组下表的操作
// 2.1 遇见冲突看前一位
j = next[j - 1]; // 注意这里在前缀表中找前一位的对应的回退位置了
}
// 前后缀相同的情况
if (s[i] == s[j])
{
++j;
}
next[i] = j;
}
}
/**
* @brief
* 参考:https://leetcode-cn.com/problems/implement-strstr/solution/bang-ni-ba-kmpsuan-fa-xue-ge-tong-tou-ming-ming-ba/
*
* @param pat
* @param txt
* @return int
*/
int KMP_search(string pat, string txt, const vector<int> next)
{
int j = 0; // 因为next数组里记录的起始位置为0
for (int i = 0; i < txt.length(); ++i)
{
while (j > 0 && txt[i] != pat[j])
{ // 不匹配
j = next[j - 1]; // j 寻找之前匹配的位置
}
if (txt[i] != pat[j])
{
++j; // i在for循环会加
}
if (j == pat.size())
{
return (i - pat.size() + 1); // 返回在txt中的索引
}
}
}
// kmp的暴力匹配算法
// 时间复杂度: o(MN)
// 空间复杂度:o(1)
int search(string pat, string txt)
{
int M = pat.length(); // 模式串
int N = txt.length(); // 文本串
for (int i = 0; i <= N - M; ++i)
{
int j;
for (j = 0; j < M; ++j)
{
if (pat[j] != txt[i + j]) break;
}
// pat全都匹配了
if (j == M) return i;
}
// txt中不存在pat子串
return -1;
}
第二题: 最小递减子串
参考链接
题目大意:给出n*m的矩阵,单次可以向四方向中小于自己权值的地方走,要求自选一个起点,求一条长度最长的路径。
n , m < = 1000 n,m<=1000n,m<=1000
主要思路:
记忆化搜索,考虑dp[i][j]为在(i,j)位置的最长路。
那么由于每个点只会被dfs一遍,所以整体复杂度就是O ( n ∗ m ) O(n*m)O(n∗m)了…
可能不太好理解,但是详见代码吧…代码挺是很好理解的
#include <vector>
#include <iostream>
#include <limits.h>
#include <algorithm>
using namespace std;
int dx[4] = {0, 0, 1, -1}; // 对应下、上、右。左
int dy[4] = {1, -1, 0, 0};
//int maxSize = 0;
bool inArea(vector<vector<int>> &data, int i, int j)
{
return (i >= 0 && i < data.size()) && (j >= 0 && j < data[0].size());
}
// 因为要相邻点之间的递减关系,因此这个dfs的结构和岛屿问题不同
// 需要dx[4]与dy[4],这样便能在一个dfs()中探究data[row][col]与相邻点递减的关系
int dfs(vector<vector<int>> &data, int row, int col, vector<vector<int>> &memo)
{
// base case
int t = 1; // 就算只有遍历[x,y],路径也为1
if (memo[row][col] > 0) // 有答案
{
return memo[row][col];
}
// 状态转移
for (int i = 0; i < 4; i++)
{
int xx = dx[i] + row;
int yy = dy[i] + col;
// 这题这个条件相当于一个visited数组:data[row][col] > data[xx][yy]
// 因为若你访问过这个数组data[row][col], 后续你dfs()过程中,若又搜索到[row,col]
// 此时[row,col]一定比当前访问的节点大,因此是不会重复访问[row,col]节点的
if (inArea(data, xx, yy) && data[row][col] > data[xx][yy])
{
int tmp = dfs(data, xx, yy, memo) + 1;
if (tmp > t)
{
t = tmp;
}
}
}
memo[row][col] = t; // 保存到备忘录
return t;
}
int main()
{
int rows, cols;
cin >> rows >> cols;
if (rows == 0 || cols == 0)
{
return 0;
}
vector<vector<int>> data(rows, vector<int>(cols));
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
cin >> data[i][j];
}
}
vector<vector<int>> memo(rows, vector<int>(cols));
int ans = INT_MIN;
// 开始dfs找最长水沟
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
// 这题每个点出发有可能,所以我们每个点都要开始dfs,最后取他们的最大值
// 初始化从(0,0)开始出发
ans = max(ans, dfs(data, i, j, memo));
}
}
cout << ans << endl;
return 0;
}
第三题 二叉树最大XOR(^)路径
// 关于XOR(^)
// 树最大异或路径:给定一棵树,问最大亦或路径/二叉树最大异或路径和
// 异或的性质:0^0=0 1^1=0 0^1=1
// 任何一个数字异或它自己都等于0。也就是说,如果我们从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现一次的数字
// 因为那些出现两次的数字全部在异或中抵消掉了
// 题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字
// 设res =0, 使用异或操作,先让res和 下标+1
// 异或,然后同每一个数异或。其中出现两次的数刚好异或为0.剩下的则是结果
// 这道题求树最大异或(XOR)操作的结果
#include <iostream>
#include <unordered_map>
using namespace std;
struct node
{
int id;
int weight;
int left_id;
int right_id;
};
int res = 0;
unordered_map<int, node> node_map;
void dfs(int id, int cache)
{
if (-1 == id) return; // 叶子节点id为-1
node temp = node_map[id];
int left_id = temp.left_id;
int right_id = temp.right_id;
cache = cache ^ temp.weight;
res = res < cache ? cache : res;
dfs(left_id, cache);
dfs(right_id, cache);
}
int main()
{
int N;
cin >> N;
for (int i = 0; i < N; ++i)
{
int id, weight, left, right;
cin >> id >> weight >> left >> right;
node temp{id, weight, left, right};
node_map.insert({id, temp});
}
for (auto item : node_map)
{
dfs(item.second.id, 0);
}
cout << res << endl;
return 0;
}