1 汉诺达问题
汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。 问应该如何操作?
(1)递归
public class Hanoilmol {
//hanoi(n,A,B,C)表示将n个圆盘从A柱子,通过B柱子挪到C柱子
public void hanoi(int n,char A,char B,char C){
if(n==1){
System.out.println("move: "+A+"----->"+C);//最大的圆盘从A移动到C
}
else{
hanoi(n-1, A, C, B);
System.out.println("move: "+A+"----->"+C);
hanoi(n-1, B, A, C);
}
}
public static void main(String[] args) {
Hanoilmol hano=new Hanoilmol();
hano.hanoi(10, 'A', 'B', 'C');
}
}
2 斐波那契数列
一只青蛙一次可以跳一级台阶,也可以一次跳两级台阶,现在有 n 级台阶,问青蛙一共有多少种跳法?
我们先令 f(n) 为 n 级台阶的总跳法数,那么第一次如果选择跳一级的话,那么剩下的 n-1 级台阶的跳法数就为 f(n-1),如果第一次跳两级的话,那么剩下的 n-2 级台阶的跳法就是 f(n-2),然后再回到题目中要求来看,青蛙一次只能挑一级或两级,也就是说刚刚列举的这两种情况的和 就是青蛙一共有多少种跳法,所以 f(n) = f(n-1) + f(n-2)。到了这一步,我们不难看出,这其实就是数学中的斐波拉契数列,
求第n个斐波那契数?
0、1、1、2、3、5、8、13、21、34 . . .
(1)递归
public static int fib(int n){
if (n<0){return -1;}
else if (n==1||n==2) {return 1;}
else{
return fib(n-1)+fib(n-2);
}
}
(2) 数组保存结果,动态规划思想
public class Fib {
public static void main(String[] args) {
int n = 9;
int res = fib(n);
System.out.println(res);
}
public static int fib(int n){
if (n<1) {return -1;}
int[] f = new int[n+1];
f[0]=1;
f[1]=1;
for (int i =2;i<n;i++){
f[i] = f[i-1]+f[i-2];
}
return f[n-1];
}
}
3 二分查找
public static int binarySearch(int[] arr, int tar) {
int low = 0;
int high = arr.length - 1;
int mid = 0;
//检查
if (tar < arr[low] || tar > arr[high] || low > high) {
return -1;
}
while (low <= high) {
mid = (low + high) / 2;
//中间值小于目标值,说明目标值在mid右边
if (arr[mid] < tar) {
low = mid + 1;
//中间值大于目标值,说明目标值在mid左边
} else if (arr[mid] > tar) {
high = mid - 1;
} else {
return mid;
}
}
return -1;
}
4 快速排序
```java
import java.lang.reflect.Array;
import java.util.Arrays;
public class QuickSort {
public static void main(String[] args) {
int[] a = {1,8,7,81,7,7,9,3,54,41};
qckSort(a, 0, a.length - 1);
System.out.println(Arrays.toString(a));
}
// 对数组a中从low到high的元素进行排序
private static void qckSort(int[] a, int low, int high) {
//安全性校验
if (high <= low) {
return;
}
//确定分界值
int key = a[low];
//定义两个指针,分别指向切分元素的最小索引值和最大索引值的下一个位置
int left = low;
int right = high + 1;
//初分
while (true) {
//先从右往左扫描,移动right指针,找到一个比分界值小的元素,停止
while (a[--right] > key) {// --表示右指针向左移
if (right == low) {
break;
}
}
//再从左往右扫描,移动left指针,找到一个比分界值大的元素,停止
while (a[++left] < key) {// ++表示左指针向右移动
if (left == high) {
break;
}
}
//判断left>=right,如果是,则证明元素扫描完毕,结束循环,如果不是,则交换元素
if (left >= right) {
break;
} else {
int temp1 = a[left];
a[left] = a[right];
a[right] = temp1;
}
}
//交换分解值索引的值和low的索引的值
int temp2 = a[low];
a[low] = a[right];
a[right] = temp2;
//对lo到hi之间的数据分成两组,(左子组和右子组)
int partition = right;//分组的分界值,位置变化后的索引
//分别对每一个数组进行排序
qckSort(a, low, partition - 1);
qckSort(a, partition + 1, high);
}
}
5 链表反转
//结点类
public class Node{
private int val;//数据域
private Node next;//指针域,指向下一个指针
public Node(int val){
this.val=val;
}
}
//反转链表
public Node ReverseLinkList(Node node){
if (node==null||node.next==null){
return node;
}
//定义三个指针,1 当前指针,2 当前指针的前一个指针,3 当前指针的后一个指针
Node pre = null;
Node cur = node;
Node temp = null;
while (cur !=null){
temp = cur.next;
cur.next = pre;
pre= cur;
cur = temp ;
}
return pre;
}
6 单链表是否有环
(1)快慢指针
//结点类
public class Node{
private int val;//数据域
private Node next;//指针域,指向下一个指针
public Node(int val){
this.val=val;
}
}
public boolean isLoop(Node head){
//定义两个指针
Node fast = head;
Node slow = head;
while (fast !=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if (fast.equals(slow)){
return true;
}
}
return false;
}
7 输入两个链表,找出它们的第一个公共节点。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//定义两个指针,在相遇点两个指针走的步数是一样多的
ListNode n1 = headA;
ListNode n2 = headB;
while (n1 != n2) {
if (n1 == null) {
n1 = headB;
}else {
n1 = n1.next;
}
if (n2 == null) {
n2 = headA;
}else {
n2 = n2.next;
}
}
return n1;
}
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}