"有道难题"题解

第一道算法题(250分)

      话说你在走路上班时,经过一片种植萝卜的农田。这块田地的形状是一个矩形的网格。field的第i个元素的第j个字符,表示田地的第i 行第j列的格子里包含的萝卜的数目。我们定义一个格子的特殊程度为它周围所有格子的萝卜个数的和; 它周围的格子包含它上下左右以及对角相邻的格子,最多有8个,在田地的边界上的格子会少一些。如果一个格子周围没有别的格子,则它的特殊程度为0
请返回田地中特殊程度在AB之间的所有格子的数目(包含A,B)。

下面是我的解法,由于不懂C#,所以就使用与其相近的Java来编写,简单说明下,就是引入一个辅助标记二维数组,若数组中某一个数其值大于范围的最大值,则说明其本身和周围位置(最多八个)都是不再需要进行统计的,所以这里进行一个剪枝操作,设置标记值表示此处不需要进行判断,减少搜索的范围,从而提高算法速度,最后测试运算10万次,用时为937毫秒,具体的测试用例见原帖中。


/**
 * 
@author  phinecos
 * 
@since  2009-6-1
 
*/
public   class  NumberField 
{
    
private   static   int  min;
    
private   static   int  max;
    
private   static   int  height;
    
private   static   int  width;
    
private   static   boolean  flag[][]; // 辅助标志
    
    
private   static   void  markNoSpecial(String[] field,  int  i,  int  j)
    {
// 设置false标记,无需再对其周围进行检测
         int  k,m;
        
int  num;
        
for  (k  =  i - 1 ; k  <=  i + 1   &&  k  <  height;  ++ k)
        {
            
if  (k  <   0 )
            {
// 越过边界
                k  =  i;
            }
            String tmp 
=  field[k];
            
for  (m  =  j - 1 ; m  <=  j + 1   &&  m  <  width;  ++ m)
            {
                
if  (m  <   0 )
                {
// 越过边界
                    m  =  j;
                }
                
if  (k  !=  i  ||  m  !=  j)
                {
                    num 
=  tmp.charAt(m)  -   ' 0 '
                    
if  (num  >  max  &&  flag[k][m]  !=   false )
                    {
                        flag[k][m] 
=   false ;
                    }
                }
            }
        }
    }
    
private   static   int  getSpecialNumber(String[] field,  int  i, int  j)
    {
// 计算field[i][j]的特殊程度
         int  count  =   0 ;
        
int  height  =  field.length; // 高度
         int  width   =  field[ 0 ].length(); // 宽度
         int  num  =   0 ;
        
int  k,m;
        
for  (k  =  i - 1 ; k  <=  i + 1   &&  k  <  height;  ++ k)
        {
            
if  (k  <   0 )
            {
// 越过边界
                k  =  i;
            }
            String tmp 
=  field[k];
            
for  (m  =  j - 1 ; m  <=  j + 1   &&  m  <  width;  ++ m)
            {
                
if  (m  <   0 )
                {
// 越过边界
                    m  =  j;
                }
                
if  (k  !=  i  ||  m  !=  j)
                {
                    num 
=  tmp.charAt(m)  -   ' 0 '
                    
if  (num  >= max)
                    {
// 比最大值要大,肯定不行的,置为false标记
                        flag[k][m]  =   false ;
                    }
                    count 
+=  num;
                }
            }
        }
        
return  count;
    }
    
public   static   int  countSpecialNumbers(String[] field, int  A, int  B)
    {
        
int  count  =   0 ;
        
int  i,j,num  =   0 ;
        
for  (i  =   0 ; i  <  field.length;  ++ i)
        {
            
for  (j  =   0 ; j  <  field[i].length();  ++ j)
            {
                
if  (flag[i][j]  !=   false )
                {
// 不是false标记
                    num  =  getSpecialNumber(field,i,j);
                    
if  (num  >=  A  &&  num  <=  B)
                        
++ count;
                }
                
else  
                {
// 本身是false标记,则将其周围都置为false标记
                    markNoSpecial(field,i,j);
                }
            }
        }
        
return  count;
    }

    
/**
     * 
@param  args
     
*/
    
public   static   void  main(String[] args) 
    {
        String[] data 
=  { " 1234567890 " ,
                 
" 1234567890 " ,
                 
" 1234567890 " ,
                 
" 1234567890 " ,
                 
" 1234567890 " ,
                 
" 1234567890 " ,
                 
" 1234567890 " ,
                 
" 1234567890 " ,
                 
" 1234567890 " ,
                 
" 1234567890 " ,
                 
" 1234567890 " };

       long begin = System.currentTimeMillis();
        height 
= data.length;
        width 
= data[0].length();
        flag 
= new boolean[height][width];
       
        int i,j;
        
for (i = 0; i < height; ++i)
        {
            
for (j = 0; j < width; ++j)
            {
                flag[i][j] 
= true;
            }
        }
        min 
= 3;
        max 
= 18;
        System.out.println(countSpecialNumbers(data,min,max));

    
        
for (i = 0; i < 100000; i++)
        {
            countSpecialNumbers(data, min, max);
        }
        
long end = System.currentTimeMillis();
        
long time = end - begin;
        System.out.println(
"耗时"+time);

    }
}

第二道算法题(500分)

题目要求:双倍超立方数是指一个正整数可以正好被拆分为两种不同的a^3+b^3的方式,其中a,b均为整数且0<a<=b。对于任何一个指定的 int n, 返回所有的小于等于n的双倍超立方数的个数。

import  java.util.ArrayList;
import  java.util.Hashtable;
import  java.util.List;
import  java.util.Map;
import  java.util.Set;
import  java.util.Map.Entry;


public   class  TwiceSuperCubic 
{
    
private   static  Map < Integer,Integer >  cache  =   new  Hashtable < Integer, Integer > (); // 键为立方和,值为次数
 
     
public   static   int  count( int  n)
     {
            
if  (n < 1   ||  n > 1000000000
                
return   0 ;
            
int  count  =   0 ;
            
int  max  =  ( int ) java.lang.Math.pow(n,  1.0f / 3.0f );
            
for  ( int  a  =   1 ; a  <=  max; a ++ )
            {
                
for  ( int  b  =  a; b  <=  max; b ++ )
                {
                    
int  tmp  =  a  *  a  *  a  +  b  *  b  *  b;
                    
if  (cache.get(tmp)  ==   null )
                    {
                        cache.put(tmp, 
1 );
                    }
                    
else
                    {
                        
int  num  =  cache.get(tmp);
                        cache.put(tmp, num
+ 1 );
                    }
                }
            }
          
            Set
< Entry < Integer,Integer >>  entrys  =  cache.entrySet();
       
            
for  (Entry < Integer,Integer >  entry : entrys)
            {
                
int  key  =  entry.getKey();
                
int  value  =  entry.getValue();
                
if  (key  <=  n  &&  value == 2 )
                   
++ count;
            }
            
return  count;
        }


    
/**
     * 
@param  args
     
*/
    
public   static   void  main(String[] args) 
    {
        
long  t1  =  System.currentTimeMillis();
        
int  n  =   1000000000 ;
        System.out.println(count(n));
        
long  t2  =  System.currentTimeMillis();
        System.out.println(t2
- t1);
        
    }

}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值