1. 斐波那契数列的递归和迭代方法
public static int f ( int n) {
if ( n == 0 ) {
return 0 ;
}
if ( n == 1 ) {
return 1 ;
}
return f ( n- 1 ) + f ( n- 2 ) ;
}
public static int f ( int n) {
int f0 = 0 ;
if ( n == 0 ) {
return f0;
}
int f1 = 1 ;
if ( n == 1 ) {
return f1;
}
int f2 = 0 ;
for ( int i= 2 ; i<= n; i++ ) {
f2 = f0 + f1;
f0 = f1;
f1 = f2;
}
return f2;
}
2. 归并排序
归并排序算法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
public static int [ ] sort ( int [ ] a, int low, int high) {
int mid = ( low+ high) / 2 ;
if ( low< high) {
sort ( a, low, mid) ;
sort ( a, mid+ 1 , high) ;
merge ( a, low, mid, high) ;
}
return a;
}
public static void merge ( int [ ] a, int low, int mid, int high) {
int [ ] temp = new int [ high- low+ 1 ] ;
int i= low;
int j = mid+ 1 ;
int k= 0 ;
while ( i<= mid && j<= high) {
if ( a[ i] < a[ j] ) {
temp[ k++ ] = a[ i++ ] ;
} else {
temp[ k++ ] = a[ j++ ] ;
}
}
while ( i<= mid) {
temp[ k++ ] = a[ i++ ] ;
}
while ( j<= high) {
temp[ k++ ] = a[ j++ ] ;
}
for ( int x= 0 ; x< temp. length; x++ ) {
a[ x+ low] = temp[ x] ;
}
}
3. 最大公约数和最小公倍数
辗转相除法:用较大数除以较小数,再用出现的余数(第一余数)去除除数,再用出现的余数(第二余数)去除第一余数,如此反复,直到最后余数是0为止。
public class Test {
public static void main ( String[ ] args) {
Scanner sc = new Scanner ( System. in) ;
int m = sc. nextInt ( ) ;
int n = sc. nextInt ( ) ;
if ( m< n) {
int temp = m;
m = n;
n = temp;
}
int t = gy ( m, n) ;
System. out. println ( "它们最大公约数为:" + t) ;
System. out. println ( "它们最小公倍数为:" + m * n / t) ;
}
private static int gy ( int m, int n) {
if ( m% n == 0 ) return n;
return gy ( n, m% n) ;
}
}
4. 图形打印
矩形,矩形打印需要用一个嵌套for循环来实现图形的长宽打印。外层for循环控制行数,内层for循环控制列数。其中小技巧是,打印时在内层不进行换行,外层进行换行。
public class test {
public static void main ( String[ ] args) {
for ( int j = 0 ; j < 5 ; j++ ) {
for ( int i = 0 ; i < 5 ; i++ ) {
System. out. print ( "*" ) ;
}
System. out. println ( ) ;
}
}
}
三角形,打印同样需要嵌套for循环,这里需要由空格来替换掉部分“”号,因此在内层需要两个for循环来实现替换。这里若要实现正三角形,则可以用一个小技巧“ ”占两个字节。
public class triangle {
public static void main ( String[ ] args) {
for ( int i = 0 ; i < 5 ; i++ ) {
for ( int j = 0 ; j < 5 - i; j++ ) {
System. out. print ( " " ) ;
}
for ( int k = 0 ; k < i; k++ ) {
System. out. print ( "* " ) ;
}
System. out. println ( ) ;
}
}
}
圆形,打印圆形必须要用到Java中的Math方法,其中Math.sqrt()计算平方根,Math.round()四舍五入取整。首先定义一个变量为圆形的半径r并赋值,可知圆心坐标为(r,r),勾股定理可知圆y = r -√(2r x-x*x)。
public class circle {
int r= 10 ;
for ( int y = 0 ; y <= 2 * r; y += 2 ) {
int x = ( int ) Math. round ( r - Math. sqrt ( 2 * r * y - y * y) ) ;
int len = 2 * ( r - x) ;
for ( int i = 0 ; i <= x; i++ ) {
System. out. print ( ' ' ) ;
}
System. out. print ( '*' ) ;
for ( int j = 0 ; j <= len; j++ ) {
System. out. print ( '*' ) ;
}
System. out. println ( '*' ) ;
}
}
}
5. 打印数组全排列
当存在n个数据 array[n]时,第一个元素可以是n中的任意一个元素,采用一个函数swap 将第一个数与后面数交换位置,就可以得到第一个位置不同的情况。 递归调用 printArragne(int [ ] array , int k , int n )方法array为需要全排列的数组,k为当前需要打印的起始地址,n为元素个数。 递归的出口就是n==k的时候,当需要打印的地址等于元素个数时候就结束 k<n时,则循环交换k与后面所有的数,循环里面则递归调用printArrange以便从数组下标0到n-1全部递归输出,交换完后记得还要交换回去
public class Arrange {
public static void main ( String[ ] args) {
int array [ ] = { 1 , 2 , 3 } ;
printArrange ( array, 0 , array. length- 1 ) ;
}
static void printArrange ( int [ ] array , int k , int n ) {
if ( k == n) {
for ( int i = 0 ; i < array. length ; i++ ) {
System. out. print ( array[ i] ) ;
}
System. out. print ( " " ) ;
return ;
} else {
for ( int i = k; i < n+ 1 ; i++ ) {
swap ( array, k, i) ;
printArrange ( array, k + 1 , n) ;
swap ( array, k, i) ;
}
}
}
static void swap ( int [ ] array , int a, int b) {
int c = array[ a] ;
array[ a] = array[ b] ;
array[ b] = c ;
}
}
6. LRU缓存机制实现
原作者:labuladong 链接:https://leetcode-cn.com/problems/lru-cache/solution/lru-ce-lue-xiang-jie-he-shi-xian-by-labuladong/ LRU 算法实际上是让你设计数据结构:首先要接收一个 capacity 参数作为缓存的最大容量,然后实现两个 API,一个是 put(key, val) 方法存入键值对,另一个是 get(key) 方法获取 key 对应的 val,如果 key 不存在则返回 -1,get 和 put 方法必须都是 O(1) 的时间复杂度。 要实现put 和 get 方法的时间复杂度为 O(1),数据结构必要的条件:查找快,插入快,删除快,有顺序之分。 哈希表查找快,但是数据无固定顺序;链表有顺序之分,插入删除快,但是查找慢,结合一下,形成一种新的数据结构:哈希链表。 LRU 缓存算法的核心数据结构就是哈希链表,双向链表和哈希表的结合体。这个数据结构长这样: 双链表的节点类,key 和 val 都认为是 int 类型
class Node {
public int key, val;
public Node next, prev;
public Node ( int k, int v) {
this . key = k;
this . val = v;
}
}
根据 Node 类型构建一个双链表,实现几个需要的 API(这些操作的时间复杂度均为 O(1)):
class DoubleList {
private Node head, tail;
private int size;
public DoubleList ( ) {
head = new Node ( 0 , 0 ) ;
tail = new Node ( 0 , 0 ) ;
head. next = tail;
tail. prev = head;
size = 0 ;
}
public void addFirst ( Node x) {
x. next = head. next;
x. prev = head;
head. next. prev = x;
head. next = x;
size++ ;
}
public void remove ( Node x) {
x. prev. next = x. next;
x. next. prev = x. prev;
size-- ;
}
public Node removeLast ( ) {
if ( tail. prev == head)
return null;
Node last = tail. prev;
remove ( last) ;
return last;
}
public int size ( ) {
return size;
}
}
实现双向链表后,只需要在 LRU 算法中把它和哈希表结合起来即可
class LRUCache {
private HashMap< Integer, Node> map;
private DoubleList cache;
private int cap;
public LRUCache ( int capacity) {
this . cap = capacity;
map = new HashMap < > ( ) ;
cache = new DoubleList ( ) ;
}
public int get ( int key) {
if ( ! map. containsKey ( key) )
return - 1 ;
int val = map. get ( key) . val;
put ( key, val) ;
return val;
}
public void put ( int key, int val) {
Node x = new Node ( key, val) ;
if ( map. containsKey ( key) ) {
cache. remove ( map. get ( key) ) ;
cache. addFirst ( x) ;
map. put ( key, x) ;
} else {
if ( cap == cache. size ( ) ) {
Node last = cache. removeLast ( ) ;
map. remove ( last. key) ;
}
cache. addFirst ( x) ;
map. put ( key, x) ;
}
}
}