转老赵点滴 - 追求编程之美

2009-05-27 19:45 by Jeffrey Zhao, 25031 阅读, 156 评论, 收藏, 编辑

CSDN学生中心是个好地方,如果善于利用,应该能够对大众产生正面影响。老赵也去那里安了家,并给出了一个编程问题。题目如下:

请将方法补充完整:

static void Reverse(int[] array, int begin, int end)
{...
}

Reverse方法的作用是将array数组中,从begin下标到end下标之间的元素反序一下,如一个数组初始值是[1, 2, 3, 4, 5, 6],begin为1,end为4,那么当调用了Reverse之后,array数组中的元素便依次成为[1, 5, 4, 3, 2, 6],其中从array[1]到array[4]之前的元素被反序了。此外补充一点……其实本不用补充:这个方法需要对传入参数的正确性进行校验,如果用户调用该方法时传入了非法的参数,那么则需要抛出异常,并写清原因。您可以使用您喜欢的语言来实现:C#,VB,Java,Ruby,Python……但是请不要使用内置库中已经有的功能。:)

很简单,不是吗?只可惜截止到目前,也只有1人给出了正确答案。如果您没有做过这道题目,那么在查看下面的分析之前,不妨拿张纸拿支笔,写下您的答案,然后再听老赵慢慢讲来……(点此展开)

主体逻辑

这道题目的主题逻辑其实非常简单。不就是把数组中的一部分反序吗?不过从这一点上面来说,代码的清晰程度也有较大差距。好的做法和普通的做法,从编程难度和理解上都有一定差距。例如:

  1. 许多朋友的做法是:既然是反转数组的一部分元素,那么只要找到中间的位置,然后计算出和begin的偏移量,然后……怎么怎么一搞,就完成了——嗯,似乎还需要根据进行begin和end中间的元素个数是奇数还是偶数分别处理。
  2. 另一些朋友的做法是:开一个新数组(长度为end - begin + 1),将begin到end之间的元素放到新数组中去,然后反序,然后再复制回来。
  3. 还有一个朋友认为用栈:把begin到end之间的元素给push到栈中,再一个一个pop出来依次赋值给begin到end,这样就反序了……唔!数据结构学的不错!

只可惜,这样的做法都复杂了一些。3种做法的时间复杂度均为O(end – begin),但是只有第一种做法的空间复杂度是O(1),而后两者也都是线性的空间复杂度。那么老赵眼里最好的做法是什么呢?

public static void Reverse(int[] array, int begin, int end)
{while (end > begin){int temp = array[begin];array[begin] = array[end];array[end] = temp;begin++;end--;}
}

end和begin两个下标从初始值开始依次向中间逼近,每次都交换一下数组中的元素。最终,while在判断的时候会发现end == begin(begin和end之间总共奇数个元素),或end < begin(begin和end之间总共偶数个元素)。无论哪种情况,都表示反序已经完成。

是不是很简单?

参数校验

上面的做法应该说是最简单的一种,不过实际在评判答案的时候,直接结果正确,老赵都认为是正确的。只可惜,几乎没有朋友在“参数校验”这方面作对。

顺便提一下的是,有位朋友给我留言很有意思:“老师只给了一个测试数据,如果要用其它测试数据的话比如比较特殊的,那请老师下次把测试数据列好。”这句话让我木然:测试数据是无穷无尽的,难道需要都列出来?平时写程序,用户会指出他的所有操作步骤吗?给测试数据的目的是为了帮助理解题意,题目的要求都写清楚了,做题才有意义。如果一道题目只要求把给出的测试数据运行,那么又有谁不会做呢?老赵这里就可以立即给出一个万能模板:

if (...)
{return ...
}
else if (...)
{return ...
}...

按理来说,即使题目中没有写明需要参数校验,一个优秀的实现也应该自带这一点。

其实只要仔细一些,把参数所有的错误情况列举出来并不是难事:

  • array == null
  • begin < 0;
  • end < begin
  • end >= array.Length

那么,其他一些情况是否应该一并判断呢?例如end < 0,array.Length == 0或者begin >= length。老赵认为“不判断也没有关系”,因为以上的判断已经确保不会出现额外的错误情况了。那么begin == end是否算是问题呢?老赵认为,这个判断也可以省略。不过……如果begin > end,那么是否应该把两者的数值进行交换?我不知道为什么有些朋友这么做了,不过老赵认为,一般来说一个方法不应该为参数进行额外“调整”——其实各大类库都不会如此画蛇添足。如果哪位朋友有不同看法,我们可以继续讨论。

常见错误

在各种答案,以及平时面试过程中,这道题总归会有一些非常典型的错误发生。其中给老赵的感觉也非常有意思,不知其中的“思路”是否如老赵猜测那样。

在方法中进行输入和输出

有不少朋友在代码里放置了这样的代码:

static void Reverse(int[] array, int begin, int end)
{Console.WriteLine("请输入xxx");array[0] = Int32.Parse(Console.ReadLine());...for (int i = 0; i < array.Length; i++){Console.WriteLine(i);}
}

为什么会出现这种情况?老赵估计是受到了某些培训机构的影响(观察出现这个问题的朋友们的分布便知)。这些培训一再强调输入、输出,而没有让学员有任何“模块”,“类库”,“辅助方法”的概念。学员的观念中,任何程序都要向用户去索要“输入”,并且要“输出”,否则就不算是程序。

为什么会这样?

打印错误,而不是抛出异常

代码如下:

static void Reverse(int[] array, int begin, int end)
{if (array == null){Console.WriteLine("数组为空");return;}...
}

除了和上面类似的“思维”以外,这说明有些朋友还没有形成“抛出异常”的观念。这意味着在过往的编程经验中,可以说完全没有“参数校验”的概念在头脑里面。培训机构只是一味地CRUD,展示,写入,却没有“抛出异常”的想法。同理,即使在题目中已经明确写清了是“抛出”异常,有些朋友的写法是这样的:

static void Reverse(int[] array, int begin, int end)
{try{// 交换数据}catch (Exception e){Console.WriteLine(e.Message);}
}

很明显,他们只有“捕获”异常的概念——自然是框架本身抛出的异常——而不知“抛出”异常。

参考答案

以下是老赵给出的参考答案:

static void Reverse(int[] array, int begin, int end)
{if (array == null){throw new ArgumentNullException("array", "array不能为空");}if (begin < 0){throw new ArgumentOutOfRangeException("begin", "begin不能小于0");}if (end < begin){throw new ArgumentOutOfRangeException("end不能小于begin", (Exception)null);}if (end >= array.Length){throw new ArgumentOutOfRangeException("end", "end超过array最大下标");}while (end > begin){int temp = array[begin];array[begin] = array[end];array[end] = temp;begin++;end--;}
}

这道简单的题目,您做对了吗?

转载于:https://www.cnblogs.com/syw429326339/archive/2012/12/05/2803990.html

一道简单的编程题,不过您做对了吗?相关推荐

  1. 一道简单的编程题考核你的编程功底

    上周有位工作了3年多的程序员(一直在企业做应用开发)来面试,本来打算不安排上机编程的,但是他开出了6K的薪资要求,我还是决定考核下他的编程功底. 刚好最近企业在做生产流程信息流对接这块的开发,我就提取 ...

  2. A. 这是一道简单的水题~

    A. 这是一道简单的水题~ pbz最近沉浸在数学中无法自拔,他发现了一种非常有趣的数,这个数的十进制表示形式中只含有8和9,这个数有着很好的寓意,代表了pbz的梦想和期望,他想知道对于任意的给定的正整 ...

  3. 一道小学奥数题,没做出来。求解答

    一道小学奥数题,没做出来.求解答. 将图形平均分成大小相等,形状相同的四份. 下面是某位高人给出的答案.四种不同颜色分别代表4个不同的部分.怎么说呢,这确实是个答案... 虽然和我们通常认为的答案有些 ...

  4. CTF easy_maze 一道简单的迷宫题。

    CTF easy_maze 一道简单的迷宫题. 打开IDA进行分析. 定位到main函数 查看程序 在main函数中查看子方法 这里发现如是遇字母"o"则退出,查看unk_400A ...

  5. qduoj 一道简单的数据结构题(水题)

    题目链接:https://qduoj.com/problem/147/点击打开链接 一道简单的数据结构题 发布时间: 2017年6月3日 18:46   最后更新: 2017年6月3日 18:51   ...

  6. 给准备做测试的亲友出了一道简单的求和题

    撸了今年阿里.头条和美团的面试,我有一个重要发现.......>>> 在1-99,小于或等于10的(譬如:1+2+...+10),全部相加:大于10的,十位数如果是奇数的,就算他们之 ...

  7. 剑指Offer_编程题 不用加减乘除做加法

    不用加减乘除做加法 时间限制:1秒 空间限制:32768K 热度指数:81997 算法知识视频讲解 题目描述 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. 首先,十进 ...

  8. 一道简单的逻辑运算题

    操作目录 逻辑或运算的简单例题"||" 题目 解析 总结 逻辑或运算的简单例题"||" 题目 若有变量声明如下: int x =5,y = 7,z = 8; 执 ...

  9. 八道简单入门编程题详解+拓展(水花仙,二进制序列……)

    目录 1.求二进制1的个数 2.计算分数的值 3. 水花仙数 4. 打印X图形 5.输出乘法口诀表 6.输出一个整数的每一位 7.模拟登陆 8.二进制序列 1.求二进制1的个数 求一个整数,在内存当中 ...

最新文章

  1. hadoop学习之旅1
  2. Docker 数据卷之进阶篇
  3. 大班体育游戏电子计算机教案,幼儿园大班体育游戏教案《夹球走走走》
  4. C++ GUI Qt4编程(12)-6.1FindFileDialog
  5. 游戏行业的人工智能设计(二):路径搜寻和感知
  6. bzoj1128 Lam-lights
  7. 洛谷4951 地震 bzoj1816扑克牌 洛谷3199最小圈 / 01分数规划
  8. Docker原理之Namespaces
  9. linux在线扩展文件系统空间ext2online
  10. 【第一部分】04Leetcode刷题
  11. Day 177/200 React 颜色选择器
  12. 系统架构设计——OpenHarmony 鸿蒙分布式操作系统
  13. 【2020年】Android开发学习思考及规划
  14. 原生开发跟混合开发?两者有什么区别?
  15. 51nod 1521 一维战舰
  16. 小米笔记本U盘win10换win7系统操作教程
  17. 柱坐标系与直角坐标系的转换
  18. python给图片加半透明水印_图片添加半透明文字水印 Python
  19. 专业技术职务代码-GBT8561-2001
  20. 【数据挖掘】公寓住房月租金预测

热门文章

  1. Python精通-Python字典操作
  2. ubuntu下使用qemu模拟ARM-----uboot从sd卡启动内核
  3. Go 模块--开始使用 Go Modules
  4. 算法面试中单链表专题
  5. 关于Feign的几个问题
  6. zxing 如何识别反转二维码
  7. Java把科学计数法转换为字符串
  8. ASP.NET MVC中的统一化自定义异常处理
  9. Redis在项目中的地位及使用场景剖析
  10. pytorch学习笔记(1):开始一个简单的分类器