【笔试面试】2015华为软件开发实习生

时间: 2015.06.16
地点:厦门大学

  1. 简单题: 10个数字位取3个组成一个三位数(不能重复),使得这三位数的值最大。
    方法:这个是送分题,我比较懒,直接用set 来存放,然后输出后面三个位置的值来搞定

  2. 奇偶数排序问题
    问题描述: 一串无序的数字,先根据所以奇数的逆序排序,再输出所有偶数的顺序排序数值。
    方法: 很简单,基本两个排序就可以搞定。

  3. 最大的边长问题:
    问题描述:大致是这样子,有一个n*m的0 ,1 组成的矩阵,求该矩阵的最大的正方形子区域,使得正方形区域内的所有元素都为1,并输出改正方形的边长。其中n,m<=400;

解法1:暴力解法:穷尽所有的正方形子区域(O(N^2))+判断该正方形子区域内的元素是否都为1(O(N^2)),所以该方法的时间复杂度是(O(N^4)),鉴于n,m<=400,改方法肯定不可取的。

解法N:
这种问题,一定要想方设法的避免重复计算问题,可以考虑以空间换时间的方式去实现。

想法1: 积分图的方法://跟图像上的积分图一个概念。
伪代码

1. 计算改n*m矩阵的积分图,时间复杂度为O(n*m);
2. 再穷举所有的正方形子区域(O(n^2))
3. 计算该正方形区域的所有的元素和O(1)
4. 纵上改方法的时间复杂度为O(n*n),鉴于n,m<=400,所以该方法的效率不算太低。

源代码:

#include<iostream>
using namespace std;
int data[400][400];//原始数据
int ig[401][401];//积分图

bool evaluate(int a,int b,int edge)
{
   int sum=(ig[a+edge][b+edge]-ig[a+edge][b]-ig[a][b+edge]+ig[a][b]);
   if(sum==(edge*edge))
 return true;
   else
 return false;
}
int main()
{
 int n,m;
 cin>>n>>m;
 for(int i=0;i<n;i++)
 for(int j=0;j<m;j++)
 {
 cin>>data[i][j];
 }
 //计算积分图
 for(int i=0;i<=n;i++)
 {
 ig[i][0]=0;
 }
 for(int j=0;j<=m;j++)
 {
 ig[0][j]=0;
 }
 for(int i=1;i<=n;i++)
 {
 for(int j=1;j<=m;j++)
 {
 ig[i][j]=ig[i-1][j]+ig[i][j-1]-ig[i-1][j-1]+data[i-1][j-1];
 }
 }
 //计算所有可能的子正方形区域
 //子正方形区域内的元素如果都为1,则其积分图为边长的平方.
 int max_edge=m>n?n:m;
 for(int edge=max_edge;edge>=1;edge--)
 {
 for(int i=0;i<=n-edge;i++)
 for(int j=0;j<=m-edge;j++)
 {
 if(evaluate(i,j,edge))
 {
 cout<<edge<<endl;
 return 0;
 }
 }
 }
 //
 cout<<0<<endl;
 return 0;
}

可惜当时做的时候,没有想到这个,只是在考完回来的路上才想到的。

你可能感兴趣的:(【笔试面试】2015华为软件开发实习生)