面试题目——《CC150》递归与动态规划
面试题9.1:有个小孩正在上楼梯,楼梯有n个台阶,小孩一次可以上1阶、2阶或者3阶。实现一个方法,计算小孩有多少种上楼梯的方式。
思路:第4个数是前三个数之和
注意:能不能使用递归,能不能建立一个很大的数组来存储传递的参数(因为可能有空间的限制),要%1000000007防止超出范围
package cc150.recursion_dp; public class GoUpstairs { public static void main(String[] args) {
// TODO 自动生成的方法存根
GoUpstairs gu = new GoUpstairs();
System.out.println(gu.countWays(4)); } public int countWays(int n) {
int index1 = 1;
int index2 = 2;
int index3 = 4;
int sum = 0;
if(n == 1)
return index1;
else if(n == 2)
return index2;
else if(n == 3)
return index3;
else{
while(n-- >= 4){ //规律是第4个数是前三个数之和
sum = ((index1 + index2)%1000000007 + index3)%1000000007;
index1 = index2;
index2 = index3;
index3 = sum;
}
return sum;
}
} // public int countWays(int n) {
// // write code here
// if(n < 0)
// return 0;
// else if(n == 0)
// return 1;
// else
// return countWays(n-3) + countWays(n-2) + countWays(n-1);
// } // public int countWays(int n,int[] map) { //使用动态规划
// // write code here
// if(n < 0)
// return 0;
// else if(n == 0)
// return 1;
// else if(map[n] > 0)
// return map[n] % 1000000007;
// else{
// map[n] = countWays(n-1,map) + countWays(n-2,map) + countWays(n-3,map);
// return map[n] % 1000000007;
// }
// } // public int[] map = new int[100000];//使用动态规划,有空间限制32768K,不能到100000
// public int countWays(int n) {
// // write code here
// if(n < 0)
// return 0;
// else if(n == 0)
// return 1;
// else if(map[n] > 0)
// return map[n] % 1000000007;
// else{
// map[n] = countWays(n-1) + countWays(n-2) + countWays(n-3);
// return map[n] % 1000000007;
// }
// } }
面试题9.2:设想有个机器人坐在X×Y网格的左上角,只能向右、向下移动。机器人从(0,0)到(X,Y)有多少种走法?
package cc150.recursion_dp; public class Robot1 { public static void main(String[] args) {
// TODO 自动生成的方法存根
Robot1 rb = new Robot1();
System.out.println(rb.countWays(3, 3));
} public int countWays(int x, int y)
{
if(x==0||y==0)return 0;
if(x==1||y==1)return 1;
return countWays(x-1,y)+countWays(x,y-1); //递归,把最后一步分解成两步
} // public int countWays(int x, int y) {
// // write code here
// if(x == 1 || y ==1)
// return 1;
// if(x > 1&& y > 1){
// int sum = x + y -2;
// int sum_jiecheng = sum;
// while(--sum >= 1){
// sum_jiecheng *= sum;
// }
// x--;
// int x_jiecheng = x;
// while(--x >= 1){
// x_jiecheng *= x;
// }
// y--;
// int y_jiecheng = y;
// while(--y >= 1){
// y_jiecheng *= y;
// }
// return (sum_jiecheng/x_jiecheng)/y_jiecheng;
// }
// return 0;
// } }
有障碍的机器人寻路
package cc150.recursion_dp; public class Robot2 { public static void main(String[] args) {
// TODO 自动生成的方法存根
Robot2 rb = new Robot2();
int[][] a = {{0,1}};
System.out.println(rb.countWays(a,2,2));
} public int countWays(int[][] map, int x, int y) {
// write code here
int[][] f = new int[x][y]; //f记录的是到达这个f[x][y]的路径数量
for(int i=0;i<x;i++){
for(int j=0;j<y;j++){
if(map[i][j] != 1)
f[i][j] = 0; // 不能走,就是方法数==0
else if(i==0 && j==0)
f[i][j] = 1; // 起点,1种走法
else if(i==0 && j!=0)
f[i][j] = f[i][j-1]; // 上边沿:只能从左边来
else if(i!=0 && j==0)
f[i][j] = f[i-1][j]; // 左边沿:只能从上边来
else
f[i][j] = (f[i-1][j]+f[i][j-1]) % 1000000007; // 其他点:左边+上边
}
}
return f[x-1][y-1];
} }
面试题9.3:在数组A[0...n-1]中,有所谓的魔术索引,满足条件A[i]=i。给定一个有序整数数组,元素值各不相同,编写一个方法,在数组A中找出一个魔术索引,若存在的话。
package cc150.recursion_dp; public class MagicIndex { public static void main(String[] args) {
// TODO 自动生成的方法存根 } //二分查询法
public boolean findMagicIndex(int[] A, int n) { //n为数组的大小
// write code here
if(findMagic(A,0,n-1) == -1) //是n-1
return false;
else
return true;
} public int findMagic(int[] A, int start,int end) { //n为数组的大小
// write code here
if(start < 0 || end < start || end >= A.length)
return -1;
int mid = (start+end) >> 1;
if(A[mid] == mid)
return mid;
else if(A[mid] > mid) //大于说明在只能左边
return findMagic(A,start,mid-1);
else
return findMagic(A,mid+1,end);
} //暴力查询法
public boolean findMagicIndex(int[] A, int n) { //n为数组的大小
// write code here
for(int i=0;i<n;i++){
if(A[i] == i)
return true;
}
return false;
} }
如果数组中有重复的元素的情况
package cc150.recursion_dp; public class MagicIndex { public static void main(String[] args) {
// TODO 自动生成的方法存根 } //如果数组中有重复的元素的情况
//二分查询法
public boolean findMagicIndex(int[] A, int n) { //n为数组的大小
// write code here
if(findMagic(A,0,n-1) == -1) //是n-1
return false;
else
return true;
} //数组中有重复元素的情况
public int findMagic(int[] A, int start,int end) { //n为数组的大小
// write code here
if(start < 0 || end < start || end >= A.length)
return -1;
int midIndex = (start+end) >> 1;
int midValue = A[midIndex];
if(midValue == midIndex)
return midIndex;
//有可能在左边,也有可能在右边
//搜索左半部分
int leftIndex = Math.min(midIndex-1,midValue); //比较下标减1和值的大小,较小的作为end,因为值和下标要相等
int left = findMagic(A,start,leftIndex);
if(left >= 0)
return left;
//搜索右半部分
int rightIndex = Math.max(midIndex+1,midValue); //较大的作为start,因为值和下标要相等
int right = findMagic(A,rightIndex,end);
return right;
} }
面试题9.4:编写一个方法,返回某集合的所有子集。
面试题9.5:编写一个方法,确定某字符串的所有排列组合。
package cc150.recursion_dp; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator; public class Subset { public static void main(String[] args) {
// TODO 自动生成的方法存根
Subset ss = new Subset();
int[] a = {1,2,3};
ArrayList<ArrayList<Integer>> arr = ss.getSubsets(a, 0);
arr.remove(0);
Iterator ire = arr.iterator();
while(ire.hasNext())
System.out.println(ire.next());
} //输出的结果非字典逆序
public ArrayList<ArrayList<Integer>> getSubsets(int[] A, int index) { //若n表示集合的大小,有2^n个子集
// write code here
ArrayList<ArrayList<Integer>> allsubsets;
if(A.length == index){ //如果index是达到length,就加上空集
allsubsets = new ArrayList<ArrayList<Integer>>(); //空集子集
allsubsets.add(new ArrayList<Integer>());
}else{
allsubsets = getSubsets(A,index + 1); //直到等于length,加上空集后继续执行
int item = A[index];
ArrayList<ArrayList<Integer>> moresubsets = new ArrayList<ArrayList<Integer>>();
for(ArrayList<Integer> subset : allsubsets){ //遍历原来的子集,一个一个加上item后放入新的子集
ArrayList<Integer> newsubset = new ArrayList<Integer>();
newsubset.addAll(subset); //新的子集先放入原来的子集
newsubset.add(item); //新的子集放入新加入的A[index],只有一个
moresubsets.add(newsubset); //把新的子集放入moresubsets中,比如空集加上3后是3,空集和3加上2后是2和3,2
}
allsubsets.addAll(moresubsets); //moresubsets用于在循环中存放加上新元素的子集,allsubsets用与存放每一次的moresubsets
}
return allsubsets;
} }
面试题9.6:实现一种算法,打印n对括号的全部有效组合(即左右括号正确匹配)。(牛客网里面是判断是否正确匹配)
import java.util.*; public class Parenthesis {
public boolean chkParenthesis(String s, int n) {
// write code here
int stackSize = s.length();
int count = 0;
Stack<Character> theStack = new Stack<Character>();
for(int i=0;i<s.length();i++){
char ch = s.charAt(i); //遍历每一个字符
switch(ch){
case '{':
case '[':
case '(':
theStack.push(ch); //遇到'{[('就入栈
count++;
break; case '}':
case ']':
case ')':
count++;
if( !theStack.isEmpty()){
char chx = theStack.pop(); //遇到'}])'弹出堆栈
if( (chx=='{' && ch!='}') || (chx=='[' && ch!=']') || (chx=='(' && ch!=')')){
return false;
}
}
else{
return false;
}
break;
default:break;
}
}
if(count != stackSize)
return false;
if( !theStack.isEmpty()){ //如果栈不为空的话,证明缺少右括号
return false;
}
return true;
}
}
面试题9.7:编写函数,实现许多图片编辑软件都支持的“填充颜色”功能。给定一个屏幕(以二维数组表示,元素为颜色值)、一个点和一个新的颜色值,将新颜色值填入这个点的周围区域,直到原来的颜色值全都改变。
package cc150.recursion_dp; public class PaintFill { public static void main(String[] args) {
// TODO 自动生成的方法存根
PaintFill pf = new PaintFill();
Color[][] cl = {{Color.Black,Color.Black,Color.Black},{Color.Black,Color.White,Color.Black},{Color.Black,Color.Black,Color.Black}};
pf.paintFill(cl,1,1,Color.White,Color.Green);
for(int i=0;i<cl.length;i++){
for(int j=0;j<cl[0].length;j++){
System.out.print(cl[i][j]);
}
System.out.println();
}
} //枚举
enum Color{
Black,White,Red,Yellow,Green;
} //x,y表示填充的坐标,ocolor表示原来的颜色,ncolor表示现在的颜色
public boolean paintFill(Color[][] screen,int x,int y,Color ocolor,Color ncolor){//x是横坐标,screen[0].length
if(x < 0 || x >= screen[0].length || y < 0 || y > screen.length)
return false;
if(screen[y][x] == ocolor){ //只有颜色等于原来的颜色的点才填充
screen[y][x] = ncolor;
paintFill(screen,x-1,y,ocolor,ncolor);
paintFill(screen,x+1,y,ocolor,ncolor);
paintFill(screen,x,y-1,ocolor,ncolor);
paintFill(screen,x,y+1,ocolor,ncolor);
}
return true;
} public boolean paintFill(Color[][] screen,int x,int y,Color ncolor){
if(screen[y][x] == ncolor)
return false;
return paintFill(screen,x,y,screen[y][x],ncolor);
} }
面试题9.8:给定数量不限的硬币,币值为25分,10分,5分和1分,编写代码计算n分有几种表示法。
package cc150.recursion_dp; public class MakeChange { public static void main(String[] args) {
// TODO 自动生成的方法存根
MakeChange mc = new MakeChange();
System.out.println(mc.countWays(100000));
} //二维dp
// public int countWays(int n) {
// int A[] = {1, 5, 10, 25}, dp[][] = new int[A.length][n + 1];
// for (int j = 0; j <= n; j++) {
// dp[0][j] = 1;
// }
// for (int i = 1; i < A.length; i++) {
// for (int j = 0; j <= n; j++) {
// int t = j - A[i];
// if (t >= 0) {
// dp[i][j] = (dp[i - 1][j] + dp[i][t]) % 1000000007;
// } else {
// dp[i][j] = dp[i - 1][j];
// }
// }
// }
// return dp[A.length - 1][n];
// } //一维dp,递归求每次减去1,5,10,25后剩下的次数
public int countWays(int n) {
int dp[] = new int[n + 1], i, A[] = {1, 5, 10, 25}; //dp数组中存储的是组合的总数
for (i = 0, dp[0] = 1; i < A.length; i++) { //在{1,5,10,25}中遍历;当j=A[1]=5的时候会计算两次,1增加到5的时候一次,5到5的时候一次
for (int j = A[i]; j <= n; j++) { //在j小于n的条件下,求1,5,10,25到n中每一个的可能性
dp[j] = (dp[j] + dp[j - A[i]]) % 1000000007; //j-A[i]是在已经选择了A[i]的情况下,求剩下的可能性
}
}
return dp[n];
} //很慢,会超时
public int makeChange(int n,int denom){
int next_denom = 0;
switch(denom){
case 25:
next_denom = 10;
break;
case 10:
next_denom = 5;
break;
case 5:
next_denom = 1;
break;
case 1: //如果到最后返回1,表示有1种方法
return 1;
}
int ways = 0;
for(int i=0;i*denom <= n;i++){
ways += makeChange(n-i*denom,next_denom)%1000000007; //返回的方法的总数的和
}
return ways%1000000007;
} }
面试题9.9:设计一种算法,打印八皇后在8×8棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。
package cc150.recursion_dp; import java.util.ArrayList; public class Queens { public static void main(String[] args) {
// TODO 自动生成的方法存根
Queens q = new Queens();
System.out.println(q.nQueens(8));
} public int nQueens(int row){
int[] arr = new int[row];
ArrayList<int[]> list = new ArrayList<int[]>();
return placeQueens(0,arr,list,row);
} int count=0; //计数 public int placeQueens(int row,int[] columns,ArrayList<int[]> results,int size){//理解的时候画一个3×3的矩阵理解
if(row == size){
count++;
//results.add(columns.clone());
}
else{
for(int col=0;col<size;col++){ //递归后行数递增,这里for循环检查每一列,然后再返回上一层递归中行数继续增加
if(checkValid(columns,row,col)){ //从左向右检查每一列,检查同一列,对角线有没有其他皇后
columns[row] = col; //columns的下标表示行,值表示列
placeQueens(row+1,columns,results,size);
}
}
}
return count;
} public boolean checkValid(int[] columns,int row1,int column1){ //columns表示一列,检查有无其他皇后在同一列,columns有可能包含column1
for(int row2 = 0;row2<row1;row2++){
int column2 = columns[row2]; //row2,column2的元素
//检查row2,column2是否会让row1,column1变成无效
if(column1 == column2)
return false;
//检查对角线
int columnDistance = Math.abs(column2-column1);
int rowDistance = row1-row2; //row1只可能大于row2
if(columnDistance == rowDistance)
return false;
}
return true;
} }
面试题目——《CC150》递归与动态规划的更多相关文章
- C++程序员面试题目总结(涉及C++基础、多线程多进程、网络编程、数据结构与算法)
说明:C++程序员面试题目总结(涉及C++基础知识.多线程多进程.TCP/IP网络编程.Linux操作.数据结构与算法) 内容来自作者看过的帖子或者看过的文章,个人整理自互联网,如有侵权,请联系作者 ...
- Android面试题目及其答案
转自:http://blog.csdn.net/wwj_748/article/details/8868640 Android面试题目及其答案 1.Android dvm的进程和Linux的进程, 应 ...
- 70. Climbing Stairs【leetcode】递归,动态规划,java,算法
You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb ...
- C语言经典面试题目(转的,不过写的的确好!)
第一部分:基本概念及其它问答题 1.关键字static的作用是什么? 这个简单的问题很少有人能回答完全.在C语言中,关键字static有三个明显的作用: 1). 在函数体,一个被声明为静态的变量在这一 ...
- C/C++面试题目一
C/C++开发工程师面试题目(一)(附答案分析) 推荐:自己根据在面试中碰到做过的一些题目以及总结的题目,希望对面试的同学有所帮助. 一. 选择题 1. 下列类中( )不是输入输出流类iostrea ...
- linux面试题目--1
Linux面试题目 填空题1. 在Linux系统中,以 (文件)方式访问设备 .2. Linux内核引导时,从文件/etc/fstab 中读取要加载的文件系统.3. Linux文件系统中每个文件用i节 ...
- 2020阿里Java面试题目大汇总,看看你离阿里还有多远,附答案!
前言 首先说一下情况,我大概我是从去年12月份开始看书学习,到今年的6月份,一直学到看大家的面经基本上百分之90以上都会,我就在5月份开始投简历,边面试边补充基础知识等.也是有些辛苦.终于是在前不久拿 ...
- HTML/CS3相关面试题目
一.HTML/CS3基本面试题目. 1. 常用那几种浏览器测试? 1.1浏览器:IE,Chrome(谷歌),FireFox(火狐),Safari(苹果计算机的最新操作系统Mac OS X中的浏览器,使 ...
- PHP面试题目搜集
搜集这些题目是想在学习PHP方面知识有更感性的认识,单纯看书的话会很容易看后就忘记. 曾经看过数据结构.设计模式.HTTP等方面的书籍,但是基本看完后就是看完了,没有然后了,随着时间的推移,也就渐渐忘 ...
- 总结CSS面试题目的考察点及常见布局问题整理
整理网上流传的若干份面试题目,突发奇想,总结关于CSS面试题目的考察点,发现问题大多围绕几个属性和几种题目,水平有限,仅供参考. 写这个博文内心有种莫名奇妙的自我谴责感,实在不应该把面试层叠样式“应试 ...
随机推荐
- windows下OpenSSL加密证书安装步骤与使用方法
OpenSSL加密证书一般用于签名认证,含私钥和公钥.在Linux系统中,OpenSSL一般是已经安装好了,可以直接使用.而在Windows系统中,是需要安装使用的. 最近在使用支付平台时,用到了Op ...
- RabbitMQ服务安装配置
RabbitMQ是流行的开源消息队列系统,是AMQP(Advanced Message Queuing Protocol高级消息队列协议)的标准实现,用erlang语言开发.RabbitMQ据说具有良 ...
- 【php+mysql】博客分页制作思路
1.首先需要初始化设置每页显示的文章数$page_size,mysql数据库中总的文章数$arc_size,页面数$page 2.利用分页公式 (当前页数 - 1 )X 每页条数 , 每页条数Sele ...
- Label控件如何根据字符串自定义大小
一.. this.label_Msg.AutoSize = false; //设置label空件不能自动大小 二.. 用代码控制label控件的大小 1.根据字符串.label的宽度 计算字符串的面 ...
- java设计模式之原型模式
原型模式概念 该模式的思想就是将一个对象作为原型,对其进行复制.克隆,产生一个和原对象类似的新对象.java中复制通过clone()实现的.clone中涉及深.浅复制.深.浅复制的概念如下: ⑴浅复制 ...
- 你不知道的Javascript(上卷)读书笔记之一 ---- 作用域
你不知道的Javascript(上卷)这本书在我看来是一本还不错的书籍,这本书用比较简洁的语言来描述Js的那些"坑",在这里写一些博客记录一下笔记以便消化吸收. 1 编译原理 在此 ...
- aop
做aop做一些事情::: package cn.happy.spring04aop; public interface ISomeService { public void doSomeThing() ...
- python基础之编码问题
python基础之编码问题 本节内容 字符串编码问题由来 字符串编码解决方案 1.字符串编码问题由来 由于字符串编码是从ascii--->unicode--->utf-8(utf-16和u ...
- nodejs express 静态文件的路径
当express 设置为静态文件服务器的时候.可以通过2种方式进行方位: 1,通过设置app.use('路径1','../a/b/image') express 路径的形式,如 src="路 ...
- BIOS设置和CMOS设置的区别与联系
BIOS是主板上的一块EPROM或EEPROM芯片,里面装有系统的重要信息和设置系统参数的设置程序(BIOS Setup程序): CMOS是主板上的一块可读写的RAM 芯片,里面装的是关于系统配置的具 ...