您的位置:首页 > 编程语言 > C#

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

2015-04-19 22:15 405 查看
去年(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
;
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: