1. 打靶问题的递归解法

Technorati 标记: 递归算法,字典法,二分法,打靶问题,日期问题,求幂,多项式求值

伦敦奥运会火热进行中,让我们来看个打靶的问题:一个射击运动员打靶,靶一共有10环,求连开10枪打中90环的可能行有多少种?
分析:这是一个典型递归求解问题。假设第10枪打x环,则将问题转换为剩下9枪打90-x环的可能有多少种,x的取值范围为[0, 10],根据加法原理,则:10枪打90环的可能 = 第10枪打0环,剩下9枪打90环的可能 + 第10枪打1环,剩下9枪打89环的可能 + 第10枪打2环,剩下9枪打88环的可能
+ 第10枪打3环,剩下9枪打87环的可能 + 第10枪打4环,剩下9枪打86环的可能 + 第10枪打5环,剩下9枪打85环的可能
+ 第10枪打6环,剩下9枪打84环的可能 + 第10枪打7环,剩下9枪打83环的可能 + 第10枪打8环,剩下9枪打82环的可能
+ 第10枪打9环,剩下9枪打81环的可能 + 第10枪打10环,剩下9枪打80环的可能。

递归的停止条件为:
1. 若环数小于0 或者 剩下的环数大于剩下的枪数乘以10(即剩下每枪打10环用不玩所剩环数),则该递归路径不记入可能情况。
2. 若不满足条件1,且所剩枪数为1,则该递归路径记为1中可能情况。

 1:  #include <stdio.h>
 2:  
 3:  int recursion(int count, int score)
 4:  {
 5:      if (score < 0 || score > count * 10) {
 6:          return 0;
 7:      }
 8:   
 9:      if (1 ==  count) {
10:          return 1;
11:      }    
12:   
13:      int i = 0;
14:      int sum = 0;
15:   
16:      for (; i <= 10; ++i) {
17:          sum += recursion(count - 1, score - i);
18:      }
19:   
20:      return sum;
21:  }
22:   
23:  int main()
24:  {
25:      printf("result: %d\n", recursion(10, 90));        
26:      return 0;
27:  }

2. 求多项式的值与求幂的快速算法

2.1 求多项式的值

已知多项式中的系数a0,a1,a2……an及x的值,求f(x)。

多项式求值问题可以利用辗转相乘的方式进行计算,根据上面的式子分析,可以将上式转换为: f(x) = ((((an * x) + an-1) * x + an-2) * x  ……. + a1) * x + a0
有了这个变形,代码自然而然就能写出来了:

 1:  #include <stdio.h>
 2:  
 3:  int polynomial(const int *coefficient, int n, int x)
 4:  {
 5:      int sum = 0;
 6:   
 7:      int i = n - 1;
 8:      for (; i != 0; --i) {
 9:          sum = sum * x + coefficient[i];
10:      }
11:   
12:      return sum * x + coefficient[0];
13:  }
14:   
15:  int main()
16:  {
17:      int coeff[5] = {1, 2, 3, 4, 5};
18:      printf("result: %d\n", polynomial(coeff, sizeof(coeff) / sizeof(coeff[0]), 10));
19:      return 0;
20:  }

2.2 求幂的快速算法

求x的p次幂本是简单的问题,可以将x次乘p次就可以了,这里我们当然不是要讨论这种计算方法,这里讨论的是怎样高效计算。
有没有可能减少做乘法的次数呢?让我们来做一个分析,考虑x的6次幂的情况:x * x * x * x * x * x = (x * x * x) * (x * x * x)
等式前面部分需进行6次乘法,后半部分需计算(x * x * x) ,然后乘以上次计算的值即可,共4次乘法。
通过上述分析可知,求x的p次幂可以通过递归折半的方法来减少乘法的次数,循着这个思考,实现就不太困难了。

 1:  #include <stdio.h>
 2:  
 3:  /* 统计乘法的次数 */
 4:  static int multiply_count = 0;
 5:   
 6:  /* 求x的p次幂 */
 7:  int power(int x, int p)
 8:  {
 9:      int ret =  0;
10:   
11:      if (1 == p) {
12:          return x;
13:      }
14:   
15:      /* 先计算x的p/2次幂 */
16:  ret = power(x, p >> 1);
17:      ret *= ret;
18:      ++multiply_count;
19:   
20:      /* 若p是奇数,则再乘一次x */
21:  if (0 != p % 2 /* 求模本身是一个耗性能的运算,这里可优化为 p – ((p >> 1) << 1) */) { 
22:          ret *= x;
23:          ++multiply_count;
24:      }    
25:   
26:      return ret;
27:  }
28:   
29:  int main()
30:  {
31:      printf("resulut: %d\n", power(2, 20));    
32:      printf("multiply count: %d\n", multiply_count);
33:      return 0;
34:  }

计算2的20次幂总共进行5次乘法就足够了,而原始的算法需要20次,那么这种算法究竟需要多少次乘法呢?
由于该算法根本思想是折半递归,类似于2分查找,所以乘法的次数为lgp取天花板值这个数量级的(lgp表示以2为底p的对数)。
整型int最多表示2的32次幂,因此最多节省24次乘法,对于现代的计算机,这似乎不是特别重要,但是在以下情况下该算法具有重要价值:
1. 对于需要高频率计算幂的情况;
2. 对于大数高精度计算的情况,如需计算2的10000次幂。
当然了,这也是对递归算法和2分法的巧妙应用,学习其思想吧。

3. 一年中的第n天是几月几号?

和这个问题类似的问题还有:
1. 给定某年某月某日,问这是这年的第多少天?
2. 已知某年的1月1号是星期几,求给定的某年某月某日是星期几?

其实这类问题的共同点在于它们都需要考虑闰年问题,大月小月问题;
首先我们解决闰年问题,根据闰年的定义定义如下宏来判断某年是否是闰年:
#define IS_LEAP(X) (((X) % 400 == 0 || (X) % 100 != 0 && (X) % 4 == 0) ? 1 : 0)

在来看大月小月问题,可以定义如下二维数组,用day_count_of_month[0][12]表示润年情况下每月的天数,用day_count_of_month[1][12]表示非润年情况下每月的天数(这就是传说中的字典法了,就是根据提供的信息查表,类似于查字典,所以叫做字典法):
int day_count_of_month[2][12] = {

{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                                                {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

};

 1:  #include <stdio.h> 
 2:  
 3:  #define IS_LEAP(X) (((X) % 400 == 0 || (X) % 100 != 0 && (X) % 4 == 0) ? 1 : 0)
 4:  int day_count_of_month[2][12] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
 5:                                   {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; 
 6:  /* 计算year年的第n天是几月几号 */
 7:  void convert_to_date(int year, int n) 
 8:  { 
 9:      int leap = IS_LEAP(year); 
10:      if(year < 1970 || year > 5000 || n <= 0 || n > 365 + leap) { 
11:          printf("bad year\n"); 
12:      }
13:   
14:      int i = 0; 
15:      for(; n > day_count_of_month[leap][i]; ++i) { 
16:          n -= day_count_of_month[leap][i]; 
17:      } 
18:   
19:      printf("year : %d, month : %d, day : %d\n", year, i + 1, n); 
20:  } 
21:   
22:  int main() 
23:  { 
24:      convert_to_date(2012, 230); 
25:  } 

上面这段代码解决了第一个问题,第二个问题可以转换为类似第一个问题的问题:
先计算给定的某年某月某日到给定已知这天的总天数s=>s%7=>利用模运算结果来推算所求日期的星期情况即可。

点击这里获取本文相关源码。

本文许可自由转载,转载请注明出处!

转载于:https://www.cnblogs.com/dskit/archive/2012/08/11/2633736.html

经典基础算法之面试题(系列一)相关推荐

  1. 经典基础算法之面试题(系列一)(转)

    1. 打靶问题的递归解法 Technorati 标记: 递归算法,字典法,二分法,打靶问题,日期问题,求幂,多项式求值 伦敦奥运会火热进行中,让我们来看个打靶的问题:一个射击运动员打靶,靶一共有10环 ...

  2. 计算机及网络应用基础思维导图_计算机基础/算法/面试题 PDF+思维导图下载

    之前为了面试,整理了九大应付面试的思维导图 + 一份 630 页的程序员内功修炼手册 + 一份计算机基础/算法/Java技术栈/Linux C++技术栈的资料.当时我就是靠着这份思维导图以及整理的 P ...

  3. 两万多字诠释python最经典基础算法之100题【内含思路、程序和答案】【python初学者必备】

    前言: 本文为最最基础的python基础算法题目.思路和答案,适合python初学者使用,可以当作python入门算法工具书,虽然不具有高深的算法,但是都是企业级算法用的频率最多的,这也是学好高级算法 ...

  4. mysql用大白话解释_Java基础--2021Java面试题系列教程--大白话解读

    前言 序言 再高大上的框架,也需要扎实的基础才能玩转,高频面试问题更是基础中的高频实战要点. 适合阅读人群 Java 学习者和爱好者,有一定工作经验的技术人,准面试官等. 阅读建议 本教程是系列教程, ...

  5. 经典基础算法的一些精髓和注意点总结

    一.搜索遍历算法 0.搜索概论 搜索,某个维度(角度)上分为两种,分别是遍历逻辑结构和遍历状态空间结构,二者都是一张图,而一个是题目给定的,一个是由题目给定所确定的 所谓状态空间,就是这个问题的询问, ...

  6. Hive经典最全笔试题系列

    现在的大数据开发,越来越趋向于编写SQL代替程序开发,比如MapReduce的Hive客户端,Kafka,Spark,Flink等都是支持SQL操作的.所以学好SQL是重中之重.是每个大数据程序开发工 ...

  7. 经典基础算法:蜜蜂路线

    引入: 有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房m爬到蜂房n的可能路线数. 其中,蜂房的结构如下所示. 输入格式: 输入 m,n 的值, 0<m<n& ...

  8. java基础知识之面试题(一)

    目录 前言 1. JDK/JRE/JVM区别 2. 构造方法 3. 重载 4. 面向对象 4.1 封装 4.2 继承 4.3 多态 5. 关键字 5.1 static 5.2 final 6. 抽象类 ...

  9. 图像处理深度学习经典基础算法

    目录 前言 一.算法实现效果 二.相关算法的一个个人理解 1.LeNet-5体系结构构: 2.AlexNet网络结构: 3.GoogLeNet网络结构: 4.VGG网络结构(VGG16.VGG19) ...

最新文章

  1. Windows进程与线程学习笔记(八)—— 线程切换与TSS/FS
  2. NFS网络文件共享系统-综合架构NO.2
  3. python中坐标怎么表示_如何在Python中以像素表示(有限)平面上的坐标
  4. 64岁Python之父加入微软 | 谁说大龄程序员无出路
  5. Hadoop学习笔记
  6. java原生怎么发请求,java原生http请求post
  7. asp.net core mvc 管道之中间件
  8. 自学python能干些什么副业-学完Python的我,月薪6千,副业2万
  9. Linux搭建arm的qemu模拟器
  10. 平稳过程的各态历经性
  11. SQL Server使用
  12. 施乐s2110进入维修模式_施乐S2110维修手册(无密码)
  13. 无需易语言模块实现任何组件透明加自汇皮肤效果
  14. 蔡学镛谈Java学习
  15. WebStorm之如何清除缓存
  16. Ubuntu20.04 安装搜狗拼音
  17. 屏蔽不讲robots规则的国外垃圾蜘蛛
  18. Auto.js脚本开发入门
  19. google黑客常用搜索语句
  20. APP - IOS_Application 常用推荐

热门文章

  1. zzuli 2527: THE END IS COMING!!!!!(最小费用最大流)
  2. BZOJ 2154 Crash的数字表格 (莫比乌斯反演)
  3. Codeforces Round #529 (Div. 3) E. Almost Regular Bracket Sequence (括号配对,前缀和)
  4. python 查看 .npy文件 和 .pkl 文件的方法
  5. Leetcode题库 5.最长回文子串(C++实现)
  6. win7未启用计算机远程访问,Win7系统下连接远程提示未启用对服务器的远程访问如何解决...
  7. 5G NR 定时提前 Timing advance
  8. java 同步中的线程出现异常会放弃锁吗
  9. 【常用】数学符号及读法大全
  10. vue 生命周期详解