华为软件岗0408笔试-C++实现

总体感受

第一次参加笔试不太清楚考试不能进行调试,再加上记错考试时间,弱鸡的我表示三道题都有思路,可惜都未能AC,考完用自己的IDE写了三道题的答案,欢迎讨论与指正~

第一题:编码数目

题目:输入N,M,求N+N^2+N^3+...+N^M的结果(取余1000000007),1<N<=65536,1<M<=100000

输入格式:每行输入N M,直到N M均等于0时跳出
输出格式:每行输出对应的结果
思路:考试时采用累乘+累加方法,每步进行求余运算确保不越界,case通过80%,可能是超时吧。后来了解到快速幂的方法,可以将朴素求幂的O(N)时间复杂度降低到O(logN),思路是幂次拆分成2^n的形式,举例:6^13=6^(2^0+2^2+2^3),这样原本需要13次运算可降低到3次。


C++实现:
#include <iostream>
#define MAXVAL 1000000007;
using namespace std;

long long quickPower(int N, int i);

int main(int argc, char const *argv[])
{
	int N,M;
	cin>>N>>M;
	while(N!=0 || M!=0){
		long long sum=0;
		for(int i=1;i<=M;i++){
			sum+=quickPower(N,i);
			sum%=MAXVAL;
		}
		cout<<sum<<endl;
		cin>>N>>M;
	}
	return 0;
}

// 快速幂
long long quickPower(int N, int i){
	long long res=1;
	long long nn=N, ii=i;
	for(;ii!=0;ii/=2){
		if(ii%2==1) res=(res*nn)%MAXVAL;
		nn=(nn*nn)%MAXVAL;
	}
	return res;
}


第二题:二进制

题目:允许对二进制数进行两种操作:00->10,10->01,求可能的最大数(两种操作可以进行任意次)
输入格式:先一行输出样例数,然后每两行输入二进制长度与二进制数本体,1<=长度<=10000
例如:
2
4
0001
10
1010111000
输出格式:每行输出每个样例的答案
例如:
1101
1111101111
思路:第一种操作是产生新的1,使数变大,第二种操作是右移1、左移0,虽然会暂时使数变小,但是会在高位产生连续0,为第一种操作提供可能。总的来说,第二种操作为第一种操作服务。找规律发现,从左往右遍历长度为n的二进制数,记录第一个0后1的个数为m,那么这些1一定会被第二种操作移动到末尾,然后采用第一种操作对二进制数中的连续0产生最可能多的1,最终答案是(n-m-1)个1 + 1个0 + m个1。
举例:101010011->100001111(第二种操作结果)->111101111(第一种操作结果)
注意:需要考虑二进制数全为1的情况,这时直接输出原二进制数即可(可能是考试时未考虑,case通过0 我太难了o(╥﹏╥)o)
#include <iostream>
using namespace std;

int main(){
	int sampleNum, len;
	string str;
	cin>>sampleNum;
	for(int i=0;i<sampleNum;i++){
		cin>>len;
		cin>>str;
		int idx;
		// 统计第一次0后的1的个数m
		for(idx=0;idx<len;idx++){
			if(str[idx]=='0') break;
		}
		if(idx==len){ // error:全为1的情况,直接输出
			cout<<str<<endl;
		}
		else{ // 不全为1,最大数则由(len-m-1)个1,1个0,m个1组成
			int cnt1=0;
			for(;idx<len;idx++){
				if(str[idx]=='1') cnt1++;
			}
			for(idx=0;idx<len-cnt1-1;idx++) str[idx]='1';
			str[idx]='0';
			for(idx++;idx<len;idx++) str[idx]='1';
			cout<<str<<endl;
		}
	}

	return 0;
}

第三题:解数独

题目:和leetcode 37题一致,链接:https://leetcode-cn.com/problems/sudoku-solver/
输入格式:
{5,3,0,0,7,0,0,0,0}
{6,0,0,1,9,5,0,0,0}
{0,9,8,0,0,0,0,6,0}
{8,0,0,0,6,0,0,0,3}
{4,0,0,8,0,3,0,0,1}
{7,0,0,0,2,0,0,0,6}
{0,6,0,0,0,0,2,8,0}
{0,0,0,4,1,9,0,0,5}
{0,0,0,0,8,0,0,7,9}
输出格式:
{5,3,4,6,7,8,9,1,2}
{6,7,2,1,9,5,3,4,8}
{1,9,8,3,4,2,5,6,7}
{8,5,9,7,6,1,4,2,3}
{4,2,6,8,5,3,7,9,1}
{7,1,3,9,2,4,8,5,6}
{9,6,1,5,3,7,2,8,4}
{2,8,7,4,1,9,6,3,5}
{3,4,5,2,8,6,1,7,9}
思路:也和力扣的官方题解二——回溯法相似,维护三个数组来记录各行、各列以及各大格的填数情况,同时维护一个储存填数坐标的栈用于回溯。大致思路是遍历扫描数独矩阵,尝试填入空格,成功填入后将该格压入栈;当遭遇无法填入的情况时,则从栈中取出上一次填写的格的坐标,并修改它的值并继续扫描。
明明是刷过的题,可惜前面纠结太久,后面没时间写完了,下次一定要先看一遍所有题的题目然后选熟悉的题先做o(╥﹏╥)o
C++实现:
#include <iostream>
#include <vector>
#include <stack>
using namespace std;

int main(){
	// 读取矩阵和初始化
	vector<vector<int> > matrix(9,vector<int>(9,0)); // 数独矩阵
	vector<int> row(9,0); // 行内元素
	vector<int> col(9,0); // 列内元素
	vector<int> block(9,0); // 箱内元素

	for(int i=0;i<9;i++){
		scanf("{%d,%d,%d,%d,%d,%d,%d,%d,%d}",&matrix[i][0],&matrix[i][1],&matrix[i][2],&matrix[i][3],&matrix[i][4],&matrix[i][5],&matrix[i][6],&matrix[i][7],&matrix[i][8]);
		getchar(); // 将缓冲区里的回车键取出,使缓冲区为空,下次scanf进入阻塞状态
		// 清空缓冲区的几种方法:
		// 1、fflush(stdin)
		// 2、while (ch=getchar() != '\n' && ch != 'EOF')
	}

	for(int i=0;i<9;i++){
		for(int j=0;j<9;j++){
			if(matrix[i][j]!=0){
				int k=(i/3)*3+j/3;
				int tmp=1<<matrix[i][j];
				row[i]|=tmp;
				col[j]|=tmp;
				block[k]|=tmp;
			}
		}
	}

	// 开始尝试
	bool step;
	int r=0,c=0,preV=0,k,tmp;
	stack<vector<int> > s; // 维护填入值的坐标点
	while(r<9 && c<9){
		step=true;
		if(matrix[r][c]==0){
			int i;
			for(i=preV+1;i<=9;i++){
				tmp=1<<i;
				k=(r/3)*3+c/3;
				if((row[r]&tmp)==0 && (col[c]&tmp)==0 && (block[k]&tmp)==0){ // 可以填入
					matrix[r][c]=i;
					row[r]|=tmp;
					col[c]|=tmp;
					block[k]|=tmp;
					s.push({r,c});
					preV=0;
					break; // 填入数字后跳出
				}
			}
			if(i==10){ // 找不到合适的数,回溯
				// 包括:取出上一个填入点坐标,还原填入点坐标为0,还原三个元素数组,标记不步进
				if(s.empty()){
					cout<<"无解"<<endl;
					return 0;
				}
				vector<int> pre=s.top();
				s.pop();
				r=pre[0];
				c=pre[1];
				k=(r/3)*3+c/3;
				preV=matrix[r][c];
				matrix[r][c]=0;
				tmp=1<<preV;
				// 标记数组复原
				row[r]&=(~tmp);
				col[c]&=(~tmp);
				block[k]&=(~tmp);
				// 不步进
				step=false;
			}
		}

		if(step){
			c++;
			if(c==9){
				c%=9;
				r++;
			}
		}
		cout<<"row="<<r<<", col="<<c<<endl;
		// 输出结果
		for(int i=0;i<9;i++){
			printf("{%d,%d,%d,%d,%d,%d,%d,%d,%d}\n",matrix[i][0],matrix[i][1],matrix[i][2],matrix[i][3],matrix[i][4],matrix[i][5],matrix[i][6],matrix[i][7],matrix[i][8]);
		}
		cout<<endl;
	}

	// 输出结果
	for(int i=0;i<9;i++){
		printf("{%d,%d,%d,%d,%d,%d,%d,%d,%d}\n",matrix[i][0],matrix[i][1],matrix[i][2],matrix[i][3],matrix[i][4],matrix[i][5],matrix[i][6],matrix[i][7],matrix[i][8]);
	}

	return 0;
}







#华为笔试##华为##笔试题目#
全部评论
55555我是第一题ac卡40卡到自闭,耗太久了!!
1 回复 分享
发布于 2020-04-09 19:54
加起来够一百就行
点赞 回复 分享
发布于 2020-04-09 16:38
第一题直接动态规划,时间复杂度不是o(n)了吗?
点赞 回复 分享
发布于 2020-04-11 03:03
不能调试是什么意思,有什么小方法吗,比如本地调试可以吗?
点赞 回复 分享
发布于 2020-04-11 10:38
请问楼主,华为机试能不能用#include<algorithm>算法库,还有<cmath>之类
点赞 回复 分享
发布于 2020-04-12 22:26
请问楼主收到面试了吗?
点赞 回复 分享
发布于 2020-04-13 14:14
楼主你好,请问收到是否参加机试的短信回复y以后还有什么要操作的吗,等着笔试链接就行了吗,谢谢您的解答
点赞 回复 分享
发布于 2020-04-13 17:01
这个是等比数列求和吗?N*(1-N**M)/(1-N),然后N的M次方可以用快速幂
点赞 回复 分享
发布于 2020-04-14 11:38
代码很清晰,点个赞
点赞 回复 分享
发布于 2020-04-14 15:51
唉。。我最后也是第一题40,第二题10,第三题0,直接凉凉
点赞 回复 分享
发布于 2020-05-01 22:03

相关推荐

6 38 评论
分享
牛客网
牛客企业服务