第一道算法题(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);}} 所属话题: “有道难题”编程挑战赛