【笔试面试】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;
}

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值