2021.6.10:
晚上突然收到乐鑫科技的笔试通知,随便打开看了下,有两道编程题,第二题有点难讲的是树的问题。讲公司员工按照K叉完全数排列填入树。输入公司员工和K,且领导和直接下属不能同时选择。输出能在树上的加入的员工最大数量。这个问题有点难,直接放弃。
第一个题目讲的是输入一个数字n,输出他的最小因式和,之前一直超时,只通过百分之70,然后尝试了下用最小堆来求解。而且i选择一半元素即可通过。
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
int main(){
int n;
cin>>n;
int minvalue=2*n; //因式都是小于n的
priority_queue<int,vector<int>, greater<int> >q;
for(int i=1; i<=n/2; i++){
int m=n/i;
if(m*i==n)
q.push(m+i);
}
cout<< q.top()<<endl;
return 0;
}
vivo春招:数位之积
题目:
现给定任意正整数 n,请寻找并输出最小的正整数 m(m>9),使得 m 的各位(个位、十位、百位 … …)之乘积等于n,若不存在则输出 -1。
思路:
分析一下这道题: 当 n < 10 时,比如说n == 4,符合条件的数就是14;即return (10 + n); 当 n >= 10 时,要将 n 分解为各个数位的乘积,范围是2-9,并且要求位数尽可能少,而且越大的数位往低位放。
代码:
class Solution {
public:
int solution(int n) {
// 因为题目限制了输入参数n>9,所以不需要进行判断
int res = 0, base = 1;
for(int i = 9; i > 1; i--) {
while(n % i == 0) {
res += (i * base);
base *= 10;
n /= i;
}
}
return n > 1 ? -1 : res;
}
};
vivo春招 智能手机产量
题目:
在vivo产线上,每位职工随着对手机加工流程认识的熟悉和经验的增加,日产量也会不断攀升。
假设第一天量产1台,接下来2天(即第二、三天)每天量产2件,接下来3天(即第四、五、六天)每天量产3件 … … 以此类推,请编程计算出第n天总共可以量产的手机数量。
思路:
这道题目感觉非常简单,在o(N)时间内设置变量来控制加法就行啦。
代码:
class Solution {
public:
int solution(int n) {
int nock=1;
int count=0;
int sum=0;
for(int i=1;i<=n;i++){
sum+=nock;
count++;
if(count==nock){
count=0;
nock=nock+1;
}
}
return sum;
}
};
vivo春招 手机屏幕解锁模式
题目:
现有一个 3x3 规格的 Android 智能手机锁屏程序和两个正整数 m 和 n ,请计算出使用最少m 个键和最多 n个键可以解锁该屏幕的所有有效模式总数。
其中有效模式是指:
1、每个模式必须连接至少m个键和最多n个键;
2、所有的键都必须是不同的;
3、如果在模式中连接两个连续键的行通过任何其他键,则其他键必须在模式中选择,不允许跳过非选择键(如图);
4、顺序相关,单键有效(这里可能跟部分手机不同)。
输入:m,n
代表允许解锁的最少m个键和最多n个键
输出:
满足m和n个键数的所有有效模式的总数
思路:
用深搜来解决,起始为止,和按键来循环累加。在深搜时,一共24个方向,前8个常规方向如果走过,再尝试都再增加一层的方向。还是走过就再循环到另外8个方向。当搜索最后一层的时候,如果能进去,说明没走过这个地方,那不用说了直接+1,这是一条路啊,同一层循环方向不同num累加。然后返回给上一层,dfs,这就是走这个方向的累加结果,也就是每次dfs最多返回24这么大的数值! 代表走这边有多少解,每层都是不断累加累加最终就出来了。因为这边搜的话,nm都是小于等于9的,最多9层嘛,其实还好这点小层数可以接受
代码:
class Solution {
public:
bool check(int i, int j) {
if ((i >= 0 && i <= 2) && (j >= 0 && j <= 2) && !isVisit(i, j)) {
return true;
}
return false;
}
bool isVisit(int i, int j) { return visited[i][j] == 0 ? false : true; }
int visited[5][5] = {0};
int map[16][2] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1},
{0, -1}, {-1, -1}, {-2, 1}, {-1, 2}, {1, 2}, {2, 1},
{2, -1}, {1, -2}, {-1, -2}, {-2, -1}};
int dfs(int i, int j, int depth) {
if (depth == 1) {
return 1;
}
int num = 0;
visited[i][j] = 1;
for (int k = 0; k < 16; k++) {
int pi = i + map[k][0];
int pj = j + map[k][1];
if (check(pi, pj)) {
num += dfs(pi, pj, depth - 1);
} else if (k < 8) {
pi += map[k][0];
pj += map[k][1];
if (check(pi, pj)) {
num += dfs(pi, pj, depth - 1);
}
}
}
visited[i][j] = 0;
return num;
}
/**
* 实现方案
* @param m int整型 最少m个键
* @param n int整型 最多n个键
* @return int整型
*/
int solution(int m, int n) {
int count = 0;
m = m >= 0 && m <= 9 ? m : 0;
n = n >= 0 && n <= 9 ? n : 9;
for (; m <= n; m++) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
count += dfs(i, j, m);
}
}
}
return count;
}
};
vivo 拆礼盒
题目:
小v所在的公司即将举行年会,年会方案设计过程中必不可少的一项就是抽奖活动。小v在本次活动中被委以重任,负责抽奖活动的策划;为了让中奖的礼物更加精美且富有神秘感,打算采用礼品盒来包装奖品,此时小v发挥了自己的创意想捉弄一下获奖的同事,便采取了多重包装来包装奖品。
现给出一个字符串,并假定用一对圆括号( )表示一个礼品盒,0表示奖品,你能据此帮获奖者算出最少要拆多少个礼品盒才能拿到奖品吗?
#include<iostream>
#include<string>
#include<stack>
using namespace std;
int solution(string str)
{
int sum = 0;
//我的策略就是遇到左括号就进栈,遇到右括号出一个栈
//直到遇到0,看下栈的大小就是最少要拆的
stack<char> stack1;
int n=str.size();
for(int i=0;i<n;i++){
if(str[i]=='(')
stack1.push(str[i]);
else if(str[i]==')')
stack1.pop();
else if(str[i]=='0'){
sum=stack1.size();
break;
}
}
return sum;
}
int main()
{
string str("");
getline(cin, str);
int sum = solution(str);
cout << sum << endl;
return 0;
}
== ==
题目:
今年7月份vivo迎来了新入职的大学生,现在需要为每个新同事分配一个工号。人力资源部同事小v设计了一个方法为每个人进行排序并分配最终的工号,具体规则是:
将N(N<10000)个人排成一排,从第1个人开始报数;如果报数是M的倍数就出列,报到队尾后则回到队头继续报,直到所有人都出列;
最后按照出列顺序为每个人依次分配工号。请你使用自己擅长的编程语言帮助小v实现此方法。
思路:
抽到谁谁出列,删掉这个数,M的倍数==》每隔M-1个就抽一个,i从0开始抽,抽到最后一个接着从头开始算就是i=i%v.size();直到都抽完了就结束了。
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include<vector>
using namespace std;
void solution(int N, int M)
{
//这边cout就行了吧
vector<int> v(N);
for(int i=0; i<N; i++)
v[i]=i+1;
int i=0;
while(v.size()>0){
i+=M-1;
if(i>=v.size()){
i=i%v.size();
}
cout<<v[i]<<" ";
v.erase(v.begin()+i);
}
cout<<endl;
}
vivo 跳盒子 Leetcode45题原题
题目:
给定一个非负整数数组,你最初位于数组的第一个位置。数组中的每个元素代表你在该位置可以跳跃的最大长度。你的目标是使用最少的跳跃次数到达数组的最后一个位置。假设你总是可以到达数组的最后一个位置。
思路:
下面的思路是基于贪心法则的,这里考虑到可能无解的情况,leetcode让我们假设的是总是可以到达数组的最后一个位置。那么为什么贪心法则在这里是可以使用的呢?思考下假如前面某个元素能跳到终点,他前面还有元素能跳到终点,我肯定选择最前面那个啊,有人可能考虑我可能先跳到较后面的一点是为了前面跳更少的路,然而从到这一步了我们要求步数最少,A E是两个都能跳到终点的点,他们中间还有B C等等啊,那么如果E能更快达到,肯定不是依赖BC,因为这些苦路我完全可以在A一步到位,那么依赖谁,只能依赖A前面的路,而A前面的路和E是一视同仁的,这意味着这道题用贪心就行了。能到B的肯定能到A。有人说是不是A存在不可能到达的情况! 这不可能,因为注意到A是最先能够直接到达终点的。我们说假设有解的话,肯定存在一条路能走向终点,那假设这条路前面腰斩,注意到我们的赋值是这个位置最大能走到哪里,意味着最大走不到A这个位置,是矛盾的!
这道题目还有正向的贪心走法,看代码2. 这个方法其实更好理解为什么贪心原理可以用,因为我每次在这个位置看能跳到最远的地方是哪里! 然后这个地方作为边界去检查起点到现在的最远点之间哪个点能跳低比当前终点还要远,因为这些点都是当前跳跃能够够到的,一旦选择到了,就更新边界再回溯搜索,搜索是不断递进的,之前没选择后面也不可能选择。所以是到边界搜索结束更新下一次的。第一次就肯定要跳。
代码:
//i+a[i]即i位置最多可跳至i+a[i]位置,最后一个位置为N-1,假如我们想跳至位置j,
//我们只需在j前面中找出不小于j的数就代表可跳至j,取最前面的那一个不小于j的就
//可得到最小步数。
int solution(int a[], int N)
{
// TODO Write your code here
vector<int> v;
for(int i = 0;i < N;i++){
v.push_back(i+a[i]);
}
if(v.size() == 1)
return 0;
int tmp = N-1;
int step = 0;
bool bark = false;
for(int i = 0;i < tmp;i++){
if(v[i] >= tmp){
step++;
if(i != 0){
tmp = i;
i = -1;
}
else{
bark = true;
break;
}
}
}
return (bark)?step:-1;
}
class Solution {
public:
int jump(vector<int>& nums) {
int maxPos = 0, n = nums.size(), end = 0, step = 0;
for (int i = 0; i < n - 1; ++i) {
if (maxPos >= i) {
maxPos = max(maxPos, i + nums[i]);
if (i == end) {
end = maxPos; //end代表边界,到了边界代表前面的路已经选择好了哪个最远 意味着可以说跳了一次了
++step;
}
}
}
return step;
}
};
2021vivo提前批第一题
题目:
输入公司员工编号6位,连续的用空格隔开,如果员工序号能被7整除或者序号中包含数字7,那么这个员工是幸运员工,不知道员工数量多少,反正少于99999,输出幸运员工的数量。
代码:
#include <iostream>
#include<vector>
#include<string>
#include<vector>
using namespace std;
int main(){
int i = 0;
int sum=0;
char c;
int x;
vector<int> num;
while((c=getchar())!='\n')
{
if(c!=' ')//把这句判断条件改动
{
ungetc(c,stdin); //原来输入了c,现在回退到流中,我没输入,下次如果输入了,那就放在他前面因为在流中了。 然后搜下第二种方法我记得CSDN搜到过
//
cin>>x;
num.push_back(x);
}
}
主函数输出啦///
for(int i=0;i<num.size();i++){
if(num[i]%7==0){
sum=sum+1;
}
else{
int temp=num[i];
while(temp>0){
if(temp % 10==7){
sum+=1;
break;
}
temp=temp/10;
}
}
}
cout<<sum;
return 0;
}
关于输入输出:
这篇博客讲的非常详细
注意到就是cin之后如果继续使用getline等函数需要加一个cin.get()吃掉回车,因为cin是不吃忽略回车的,然后getline不忽略,让程序以为走完getline了!分析可以这篇博客
在这里统一做个汇总把,上面vivo的提前批第一题,没有告诉我们这行终止的个数是多少,因此我们只能通过出现回车来判断是否结束输入。可以怎么做呢:
方法1:
方法1的好处是针对字符串处理的,有时候我们输入的是字符串不是数字,那就可以用方法1.
#include <iostream>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
int main(){
string s;
getline(cin,s); //将某一行获得的元素输入到s中
string temp;
vector<int> str;
for(int i=0; i<s.size();i++){
if(s[i]!=" "){
temp+=s[i];
}
else{
str.push_back(stoi(temp));
temp.clear();
}
}
str.push_back(stoi(temp));
cout<<str[1];
return 0;
}
方法2:
#include <iostream>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
int main(){
int sum=0;
char c;
int x;
vector<int> num;
while((c=getchar())!='\n')
{
if(c!=' ')//把这句判断条件改动
{
ungetc(c,stdin); //原来输入了c,现在回退到流中,我没输入,下次如果输入了,那就放在他前面因为在流中了。 然后搜下第二种方法我记得CSDN搜到过
//上面就是加了个缓存 就是让第一次的输入不丢失还能被cin进去
cin>>x;
num.push_back(x);
}
}
return 0;
}
注意到,方法2只能针对空格的字符或者int类型,不能针对分号或者逗号的类型 因为!注意到getchar只是对上一次的读取,接下来cin的过程是无法读取的,所以就依赖空格让cin跳出去了,或者是回车跳出去,getchar读取的是最近一次的流~在出现他这个函数的时候开始读,如果没有就先操作再读,有了就读最近的。
因此,针对有分号,逗号或者针对字符类型的,还是得靠方法1啊万精油方法1.基本思路就是靠getline和循环操作。
上面讲的是一行的输入,针对字符或者数字,针对空格或者逗号的存在如何使用,那么当需要我们输入多行数字,而且也是数量位置呢?思考下其实可以使用getline来操作2次或者多次即可。我们以背包问题为例,第一行输入背包最大容量,第二行输入物品的重量,逗号隔开,第三行输入物品的价值,逗号隔开。
#include <iostream>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
int main(){
string temp;
string s;
string s2;
vector<int> w;
vector<int> v;
int n;
cin>>n; //cin忽略回车 要吃掉
cin.get();
getline(cin,s);
getline(cin,s2);
vector<int> str;
for(int i=0; i<s.size();i++){
if(s[i]!=' '){
temp+=s[i];
}
else{
w.push_back(stoi(temp));
temp.clear();
}
}
w.push_back(stoi(temp));
//对第二行操作
temp.clear();
for(int i=0; i<s2.size();i++){
if(s2[i]!=' '){
temp+=s2[i];
}
else{
v.push_back(stoi(temp));
temp.clear();
}
}
v.push_back(stoi(temp));
cout<<v[1];
return 0;
}
那么,当我们需要输入3行,乃至4行数字怎么办?可以用下面的代码:
#include<bits/stdc++.h> //其实这个一个头文件就够了
#include<string>
#include<cstring> //给stoi的
#include<vector>
#include<numeric> // 给accumulate的
using namespace std;
vector<int> helper(string s);
int main(){
int n;
cin>>n;
cin.get();
string s;
vector<int> nums;
vector<vector<int>> ans;
for(int i=1; i<=n; i++){ //注意一定要用for 不然用while跳不出循环,每次在while里面操作函数了
getline(cin,s);
nums=helper(s);
ans.push_back(nums);
cout<<accumulate(nums.begin(),nums.end(),0)<<endl;
}
return 0;
}
vector<int> helper(string s){
string temp;
vector<int>res;
for(int i=0; i<s.size();i++){
if(s[i]!=' ')
{
temp=temp+s[i];
}else{
res.push_back(stoi(temp));
temp.clear();
}
}
res.push_back(stoi(temp));
return res;
}
当我们知道输入的几行几列的情况又该如何处理呢?针对有逗号的情况。这个暂时不知道先做到题目再说把
在这里插入代码片
接下来就是看看树、链表的题目对应的情况了。