第n个月后共有多少对兔子
/*
* 题目描述:每对兔子每个月不多不少恰好能生一对(一雌一雄)新兔子,而且每对新生兔出生两个月后就成熟并具备生殖能力;
* 另外,假定所有的兔子都不会死亡。假如养了初生的小兔一对,试问第n个月后共有多少对兔子?
* 思路:
* 现在兔子的数量=前一个月兔子的数量+新生兔子的数量
* 前一个月兔子的数量:f(i-1)
* 新生兔子的数量:f(n-2) (前两个月的兔子都具备生殖能力)
* */
public int NumberOfRabit(int i){
if(i==0) return 1;
if(i==1) return 1;
return NumberOfRabit(i-1)+NumberOfRabit(i-2);
}
集合划分
/*
* 题目描述:给定正整数n 和 m,计算出n个元素的集合{1,2,…,n }可以划分为多少个不同的由 m 个非空子集构成的集合。
* 思路:
* n个元素的划分为m个子集的数量=n-1个元素划分为m-1个子集的数量+n-1个元素划分为m个子集的数量*m
* 当n-1个元素划分为m-1个子集时,把第n个元素单独当成一个子集加入就好。
* 当n-1个元素划分为m个子集时,把第n个元素往m个子集中任意一个插入,每个划分有m种插入方式。
* 终止条件:
* n<m或m==0时,0种插入方式
* m==n或m==1时,1种插入方式
* */
public int numOfDivide(int n,int m){
if(m==0||m>n) return 0;
if(m==n||m==1) return 1;
return numOfDivide(n-1,m-1)+numOfDivide(n-1,m)*m;
}
给表达式加括号
/*
* 题目:给表达式加括号
* 题目描述:Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are +, - and *.
* 思路:从头开始遍历字符串,遇到'+','-','*',就把字符串分割为两部分递归处理, 将两部分的计算结果用列表保存返回。
* 再把leftList和rightList的所有组合进行运算,将最终结果们保存到List中。
* 递归过程中,当字符串中没有运算符号时说明整个字符串是一个数字,这种情况下,直接将字符串转为数字保存到list中即可
* */
public List<Integer> diffWaysToCompute(String input) {
List<Integer> list = new LinkedList<>();
boolean isNumber = true;
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c == '+' || c == '-' || c == '*') {
isNumber = false;
List<Integer> leftList = diffWaysToCompute(input.substring(0, i));
List<Integer> rightList = diffWaysToCompute(input.substring(i + 1, input.length()));
for (int leftElem : leftList) {
for (int rightElem : rightList) {
switch (c) {
case '+':
list.add(leftElem + rightElem);
break;
case '-':
list.add(leftElem - rightElem);
break;
case '*':
list.add(leftElem * rightElem);
break;
default:
break;
}
}
}
}
}
if (isNumber) {
list.add(Integer.valueOf(input));
}
return list;
}
不同的二叉搜索树
/*
* 不同的二叉搜索树
* 题目描述:给定一个数字 n,要求生成所有值为 1...n 的二叉搜索树。
* 思路:每遍历到一个元素,就把该元素作为根节点,将数组以当前元素分割,分别将左列表和右列表构建为它的左右子树。
* 注意,当左右子树没有值时,要把相应列表add一个null,返回给根节点
* */
public LinkedList<TreeNode> buldTree(int start, int end) {
LinkedList<TreeNode> list = new LinkedList<>();
if (start > end) list.add(null);
for (int i = start; i <= end; i++) {
LinkedList<TreeNode> left = buldTree(start, i - 1);
LinkedList<TreeNode> right = buldTree(i + 1, end);
for (TreeNode leftRoot : left) {
for (TreeNode rightRoot : right) {
TreeNode root = new TreeNode(i);//注意这里每次都要重新new
root.left = leftRoot;
root.right = rightRoot;
list.add(root);
}
}
}
return list;
}
最接近点对(减治)
题目描述:在二维空间内找到两个距离最近的点
思路:
- 选取一垂直线l: x = m来作为分割直线,其中m为S中各点x坐标的中位数。将S分割为S1和S2。
- 递归地在S1和S2上找出其最小距离d1和d2,并设d = min{d1, d2},S中的最接近点对是d,或者是某个{p, q},其中p∈S1且q∈S2。
- 候选点 p 和 q 到直线l 的距离不能超过d,则只需考虑区间P1和P2的范围;
- 考虑P1中任意一点p,它若与P2中的点q构成最接近点对的候选者,则必有distance(p,q)<d。满足这个条件的P2中的点一定落在一个d×2d的矩形R中;
- 由d的意义可知,P2中任何2个S中的点的距离都不小于d。由此可以推出矩形R中最多只有6个S中的点
证明: 将矩形R的长为2d的边3等分,将它的长为d的边2等分,由此导出6个(d/2)×(2d/3)的矩形。若矩形R中有多于6个S中的点,则由鸽舍原理易知至少有一个(d/2)×(2d/3)的小矩形中有2个以上S中的点。设u,v是位于同一小矩形中的2个点,则(?/2)2+(2?/3)2=25/36 ?^2。distance(u,v)=5d/6<d。这与d的意义相矛盾。
算法描述:
预处理1: 对点集S按x轴从小到大排序;
预处理2: 对点集S按y轴从小到大排序放Y中,并记录各点对应S中的下标;
时间复杂度:T(n)=O(n)+O(n)+T(n/2)+T(n/2)+O(n)
T(n)=O(nlog(n))