有道难题"题

第一道算法题(250分)

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

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

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->


/**
*
@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;
}
Stringtmp
= 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;
}
Stringtmp
= 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 " };

longbegin=System.currentTimeMillis();
height
=data.length;
width
=data[0].length();
flag
=newboolean[height][width];
inti,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);
}
longend=System.currentTimeMillis();
longtime=end-begin;
System.out.println(
"耗时"+time);

}
}

第二道算法题(500分)

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

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 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、付费专栏及课程。

余额充值