【题解】2015编程之美资格赛 CodeHunt C#满分参考与总结

去年(2014)编程之美我是靠着不熟练的C#,边做CodeHunt边查资料,跌跌撞撞进了复赛(当然进复赛以后没别人有技巧,没进线下,不然就醉了),当然没收藏好总结,有点遗憾——这个模式挺好玩的啊~于是今年就下定决心,做完以后整理一下所有题目的测试数据、我的代码和做题思路了~


先说明:我C#用的比Java熟,只愿意用C#写(虽然其实都不算太熟)


首先当然是资格赛的了


0.2


x和y做的运算?一般就是a*x+b*y+c的形式吧,套进去就行了


using System;


public class Program {
  public static int Puzzle(int x, int y) {
    return 2*x+y;
  }
}



0.3

只能说,不难,这只是直觉,所写即所想……

using System;


public class Program {
  public static bool Puzzle(int x, int y) {
    return x>=y;
  }
}




0.4

我下面的代码,只是为了强行用foreach而这么写的,其实完全没必要……for循环修改a[]里的,负数就绝对值运算一下就行了。

using System;
using System.Collections.Generic;
public class Program {
    public static int[] Puzzle( int[] a ) {
        List<int> t = new List<int>();
        foreach (var i in a) {
            t.Add(i < 0 ? -i : i);
        }
        return t.ToArray();
    }
}



0.5


找一下规律,发现要求第一次出现的下标,否则返回-1——string的IndexOf方法正好就是这种行为!

using System;

public class Program {
  public static int Puzzle(string s1, string s2) {
    return s1.IndexOf(s2);
  }
}




0.6


如果出现重复的数,返回true,否则返回false

一开始写了个,把数组排序,然后检查每个相邻两项是否相同——代码质量1灯

不得不说,C#的Linq太方便了!

对数组调用Distinct方法,返回一个IEnumerable<T>接口,然后ToArray()就变成去重的数组了,判断前后两者长度是否一样就行

using System;
using System.Linq;

public class Program {
    public static bool Puzzle( int[] a ) {
		return a.Distinct().ToArray().Length!=a.Length;
    }
}




0.7


这个题是有点逗你玩的意思

我本来以为是判断奇数的个数,奇数个返回1,偶数个返回0-_-||

后来多搞了一点数据出来发现,好像直接输出最后一个值就好了!

using System;

public class Program {
    public static int Puzzle(int[] a) {
      return a[a.Length-1];
    }
}



1.1

任务,比较明显的,就是把5位二进制字符串变成2位16进制字符串(不足的补上前导0)

我第一时间想到Java,因为的确用Java做过这件事情……可是,我可以吐槽一下,CodeHunt的Java简直是残次品吗?java.math.*没有是什么心态……

然后google查啊,然后就发现了我在代码里用到的下面这两个方法:

Convert.ToInt32

Int32.ToString()

他们可以做2、8、10、16进制之间的相互转换,没Java的凶悍(Java可以做2到36进制的),但这题上,够用了。

using System;
public class Program {
    public static string Puzzle(string x) {
        int ans=Convert.ToInt32(x,2);
        return ans.ToString("X2");
    }
}




1.2


通过骗数据大法(函数里把给出的输入和对应输出都正确处理,提交,他会给你更多数据),发现结果就是4的倍数……

0,1,2,3-->0

4,5,6,7-->4

——这明显是整除4后乘4的行为

using System;

public class Program {
    public static int Puzzle(int n) {
      return n/4*4;
    }
}



1.3


(有一种数字电路课程设计的既视感)

看到数据的第一反应是,3个中2个以上为true的就是true(3选2投票器)

然后提交,返回错误,多提供一组:

true , false, false -->true

于是问题变成了,如果把x,y,z看做二进制每一位,拼起来表达的数>=3为true,否则为false

于是可以写成x||(y&&z)了

using System;

public class Program {
  public static bool Puzzle(bool x, bool y, bool z) {
    return x||y&&z;
  }
}



1.4


灵感来源是," ! ! "-->{"",“!”,“!”,""}

这好像就是按空格分割的行为吧~

string的Split()大法好

using System;

public class Program {
  public static string[] Puzzle(string s) {
    return s.Split(' ');
  }
}


1.5


简单的眼力和C#数组的考察

显然,生成一个m行n列的矩阵,每个元素[i][j]=(i+1)*(j+1)就行了

using System;

public class Program {
    public static int[][] Puzzle(int m, int n) {
        int [][]ans=new int[m][];
        for(int i=0;i<m;i++){
            ans[i]=new int[n];
            for(int j=0;j<n;j++)
                ans[i][j]=(i+1)*(j+1);
        }
        return ans;
    }
}




1.6


观察最后一组数据,从第一个字母开始,间隔1个字母取出来组成新串,且不取最后一个字母

这个题粗暴的表达就行了

using System;

public class Program {
    public static string Puzzle(string s) {
        string ans="";
        for(int i=0;i<s.Length-1;i+=2)
            ans+=s[i];
        return ans;
    }
}




2.1


又是找x和y关系的?

再试试看放到a*x+b*y+c的关系式里看看,又好像有一组符合的解啊

using System;

public class Program {
    public static int Puzzle(int x, int y) {
        return x+2*y+3;
    }
}



2.2


任务比较显然,在s串每两个字母中间插入一个p串

至于怎么写最短,就要看你是不是熟悉C#里String类的操作了

先用ToCharArray()方法变成字符数组,然后用Join()方法,轻松又愉快

——不熟悉的同学请拿起你的google,再不济,百度,搜一搜,看看msdn里的说明就行

using System;

public class Program {
    public static string Puzzle(string s, string p) {
        return String.Join(p,s.ToCharArray());
    }
}



2.3


又靠猜了……

先观察下面小的一组{15,0},{1,11}-->{15,165}

165=11*15

然后放到第二组里看看

472-13*10=342=19*18

于是第二维就是p[0]*q[1]+p[1]*q[0]

第一维,真的就靠神奇的瞎猜了,反正p、q的4个数都用上看看,就找到规律了

using System;

public static class Program {
    public static int[] Puzzle(int[] p, int[] q) {
        return new int[2]{p[0]*q[0]-p[1]*q[1] , p[0]*q[1]+p[1]*q[0]};
    }
}


2.4


这题略神,构造了很多组数据,还是没找到什么好规律……

直到突然想看看,a尽量减去b,看看为true的都余下多少……

为true的都余下2!

就是说,判断a%b==2就行了!

using System;
public class Program {
    public static bool Puzzle(int a, int b) {
        return a%b==2;
    }
}




2.5

把字母变成相应的2位十进制数,拼接起来,返回一个int

为什么要一开始ans="0"?防止产生的ans串是空串,直接去Parse()会出Exception

using System;

public class Program {
    public static int Puzzle(string s) {
        string ans="0";
        for(int i=0;i<s.Length;i++) ans+=((int)s[i]-96).ToString("D2");
        return int.Parse(ans);
    }
}



2.6


产生的结果好大啊……

我们除除看吧……

319935/462=692.5

692.5/462=1.49......... ==>这个方向仿佛不科学,换一个

692.5-462=230.5

而230.5=462/2-0.5


再来一组数据看看?

365807/494=740.5

740.5-494=246.5

而246.5=494/2-0.5

——恭喜,我们应该是找到规律了!

别忘了直接写表达式算出来double,强制类型转换就行了

using System;

public class Program {
    public static int Puzzle(int x) {
        return (int)(x*(x+x/2.0-0.5));
    }
}


======================难度提升分割线======================

上面的代码都还是很短的吧?用户写的内容不超过10行,规律比较好找,也好写一点

下面的难度是比上面的大一些的,拿来当复赛最后一题估计不过分的~

(不过还是比hihocoder水啊哈哈哈~)


3.1


任务:给你一个可能带有其他字符的括号串,不合法串返回0,否则返回最大括号嵌套深度
一开始感觉很虚啊,因为直觉告诉我,写完也得来个十多行,估计满灯不了~可是当我写完提交后发现,代码怎么长随便……

下面的方法太丑了——手工维护一个栈,里面存放左括号的位置,碰到左括号压栈,碰到右括号试图出栈,并且在左括号到右括号之间找最大括号深度,这对括号的最大深度就+1,最后判断整个过程中是否出现非法行为,如果有就返回0,否则返回最大括号深度。

——发誓,去年做编程之美的CodeHunt,我真的没碰到过代码要这么长的……

using System;
using System.Linq;
public class Program {
    public static int Puzzle(string s) {
        int []dp=new int[s.Length];
        int []stack=new int[s.Length];
        int sp=0,mark=0;
        for(int i=0;i<s.Length;i++){
            if(s[i]=='('){
                stack[sp++]=i;
            }else if(s[i]==')'){
                if(sp>0){
                  int m=0;
                  for(int j=stack[sp-1]+1;j<i;j++)
                      if(m<dp[j])m=dp[j];
                  dp[i]=m+1;
                  sp--;
                }else mark=1;
            }
        }
        return mark==1||sp!=0?0:dp.Max();
    }
}




3.2


一开始看到这个题,我是拒绝的——这是什么鬼……,到底要做什么运算?于是跳过

可是回来一看,发现规律了:

b是你存的数据,a是需要的数据的下标,你返回a中请求的数据的查询结果值,组成个数组就行了……

不过有点小坑的是,a[]和b[]居然会传入同一个对象!你直接修改a再返回会得到错误答案(不过本来就不应该这样做的……)

using System;

public static class Program {
    public static int[] Puzzle(int[] a, int[] b) {
        int []ans=new int[a.Length];
        for(int i=0;i<a.Length;i++)
            ans[i]=b[a[i]];
        return ans;
    }
}






3.3


这个任务挺诡异的——

要求找到在s中出现的所有p串,删除,其中最后一次出现p串的位置之后的字符也要删除

比如

"acba","acb"==>""

"bababjccccccccaba","ab"==>"bjcccccccc"

"bbb","bb"==>""

一种想法就是,先找LastIndexOf(),删掉之后的字符,然后再在剩下的s串中找p串,用Replace全部替换掉

——然后"bbb","bb"你想怎么办啊?

于是我采用了一种比较不科学的折衷方法:

先把所有p串换成###,然后删除最后一次###后面的字符,最后把所有###换成空,然后,好像就通过了?

(希望有大神给个更科学的正解,不胜感激~)

using System;

public class Program {
    public static string Puzzle(string s, string p) {
        if(p.Length==0)return s;
        s=s.Replace(p,"###");
        if(s.LastIndexOf("###")>=0)s=s.Remove(s.LastIndexOf("###"));
        s=s.Replace("###","");
        return s;
    }
}




3.4


任务,找到x中出现的最大的质因子……

这个题就八仙过海,各显神通了,我这个写法应该不是最优的,请无视……

using System;

public class Program {
    public static int Puzzle(int x) {
        if(x<4)return x;
        int maxp=1;
        for(int i=2;i<=Math.Sqrt(x);i++)
            while(x%i==0){
                maxp=i;
                x/=i;
            }
        return maxp>x?maxp:x; 
    }
}



3.5


感觉好像做了什么很飘逸的运算产生的结果……

提示也很有意思,How is the array transformed?数组做了变换?

于是猜猜看,感觉是每项取了个平均值?

{0,18,30,40}-->{9,16,29,35}

9==(0+18)/2

16!=(0+30)/2;但16==(0+18+30)/3!!!

29=(18+30+40)/3

35=(30+40)/2

……怎么感觉像是图像处理里的均值滤波器啊(不过是一维的)

然后写一发啊,提交,过了

using System;
public class Program {
    public static int[] Puzzle(int[] a) {
        int []b=new int[a.Length];
        b[0]=(a[0]+a[1])/2;
        for(int i=1;i<a.Length-1;i++)
            b[i]=(a[i-1]+a[i]+a[i+1])/3;
        b[a.Length-1]=(a[a.Length-2]+a[a.Length-1])/2;
        return b;
    }
}




3.6


我发誓,没左上角的提示,还真的想不出来!

What happens to the bit pattern?

bit?感觉是二进制啊,于是:

Sample的二进制表示:
00000001
10000000


10000100
00100001


01100101
10100110

规律:二进制串做了个reverse操作

于是又来,把int变成8位2进制字符串,然后反转,再Convert.ToInt32转成整数形式。


不过,不知道为什么,CodeHunt上以下代码运行报错,不能用下面的办法反转原串(下面的办法网上找的,看着好科学)
char[] ret = data.ToCharArray();
return string.Concat<char>(ret.Reverse<char>());


那就折衷一下吧,变成字符数组,然后反转数组,你总没意见了吧?


using System;

public static class Program {
    public static int Puzzle(int n) {
        char []arr=Convert.ToString(n,2).PadLeft(8, '0').ToCharArray();
        Array.Reverse(arr);
        return Convert.ToInt32(new string(arr),2);
    }
}

===================================================

总结:

打完资格赛的CodeHunt,感觉是方方面面都要考啊!

C#要重点关注:

1、字符串的操作(字符串与数的转换,字符串的查找、替换、分割等)

2、数组的属性、方法

3、Linq带来的一些超省力的方法(比如Sum\Distinct\Min\Max\Zip等,有些地方不用Linq代码质量分拿不到3灯的)

然后还有就是自己平时的算法能力和实现能力的积累了


就是这样,End at 2015.04.20

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值