通读了剑指offer这本书,决定把上面涉及到的算法进行整理,加深对算法的理解,并通过Java代码进行实践。待更新。。。
package com.xpn.offer;
import java.util.Stack;
/**
* 2、实现singleton模式
* 3、二维数组的查找,从左到右、从上到下有序 findSortedMatrix
* 4、替换字符串的空格为“%20”,从后往前替换,提高效率replaceBlack
* 5、从尾到头打印链表printReverseList printReverseListRec
* 6、重建二叉树(根据前序和中序遍历的结果)
* 7、用两个栈实现一个队列
* 8、旋转数组的最小数字:递增排序的一个旋转数组,找出最小的元素 findMinRotatedArray
* 9、斐波那契数列:递归实现、迭代实现(效率)DP
* 10、二进制中1的个数 n&(n-1)将最右边一位的1置0
* 11、数值的整数次方
* 12、打印1到最大的n位数(大数问题,字符串模拟)、数字排列问题?
* 13、O(1)时间删除链表结点。思路:复制数据,然后删除。尾结点单独处理(需要遍历)
* 14、调整数组顺序,使得奇数位于偶数前面 reorderOddEven
* 15、链表中倒数第k个结点。要点:两个指针,异常处理,鲁棒性考察
* 16、反转链表,异常处理
* 17、合并两个排序的链表,额外申请头结点,为空情况考虑
* 18、判断树B是否为树A的子结构
* 19、二叉树的镜像
* 20、顺时针打印矩阵,从外向里顺序打印每一个数字printMatrix,找到规律和边界条件
* 22、包含min函数的栈
* 23、栈的压入弹出序列,序列A:压栈序列,序列B:出栈序列,判断B是否正确?isPopOrder
* 24、从上打印二叉树:层次遍历,队列实现
* 25、二叉搜索树树的后序遍历,判断输入的数组是否为后续二叉搜索树的遍历结果,找规律,递归实现。
* @author xpn
*
*/
public class Main {
private static class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
}
}
static class Node{
int value;
public Node(int value) {
this.value=value;
}
Node next;
}
/**
* @param args
*/
public static void main(String[] args) {
Node n1 = new Node(1);
Node n2 = new Node(2);
Node n3 = new Node(3);
Node n4 = new Node(4);
Node n5 = new Node(5);
n1.next = n2;
n2.next = n3;
n3.next = n4;
n4.next = n5;
// printReverseListRec(n1);
int mat[][]={
{1,2,3,4},
{5,6,7,8},
{10,11,12,13}
};
printMatrix(mat,mat[0].length,mat.length);
int[] A={1,2,3,4,5};
int[] B={4,3,5,1,2};
System.out.println(isPopOrder(A,B));
}
//2.实现singleton模式
//构造函数私有,返回实例静态
static class Singleton{
private Singleton() {
}
private static Singleton instance=null;
private static Object flag=1;//必须是个对象
public static Singleton getInstance () {
if(instance==null){
synchronized (flag) {
if(instance==null)
instance=new Singleton();
}
}
return instance;
}
}
//3、二维数组的查找,从左到右、从上到下有序 findSortedMatrix
//思路:从右上角到左下角进行二分查找
private static boolean findSortedMatrix(int[][] A,int num){
if(A==null)
return false;
int m=A.length;//行
int n=A[0].length;//列
int i=0;
int j=n-1;
while(i<m&&j>=0){
if(num==A[i][j]){
return true;
}else if(num<A[i][j]){
j--;
}else {
i++;
}
}
return false;
}
//4、替换字符串的空格为“%20”,从后往前替换,提高效率replaceBlack
//思路:从后往前进行,此思路还适应于合并2个数组,减少移动次数。
//5、从尾到头打印链表printReverseList printReverseListRec
//思路:通过栈来迭代,或者使用递归
private static void printReverseListRec(Node head){
if(head==null)
return;
printReverseListRec(head.next);
System.out.print(head.value+" ");
}
//6、重建二叉树(前序+中序) constructTree 递归思想解决
/**
*
* @param A 前序遍历
* @param s1 前序遍历开始下标
* @param e1 前序遍历开始下标
* @param B 中序遍历
* @param s2 中序遍历开始下标
* @param e2 中序遍历开始下标
* @return
*/
private static TreeNode constructTree(int[] A,int s1,int e1,
int[] B,int s2,int e2){
if(s1>e1||s2>e2)
return null;
int rootValue=A[s1];
TreeNode root=new TreeNode(rootValue);
if(s1==e1){
if(s2==e2){
if(A[s1]==B[s2])
return root;
else {
return null;
}
}
}
int rootInorder=s2;
while(rootInorder<=e2&&B[rootInorder]!=rootValue){
rootInorder++;
}
int leftLength=rootInorder-s2;
int rightLength=e2-rootInorder;
int preOrderEnd=s1+leftLength;
if(leftLength>0){//构建左子树
root.left=constructTree(A, s1+1, preOrderEnd, B, s2, rootInorder-1);
}
if(rightLength>0){
root.right=constructTree(A, preOrderEnd+1, e1, B, rootInorder+1, e2);
}
return root;
}
//7、用两个栈实现一个队列、两个队列实现一个栈
//8、旋转数组的最小数字:递增排序的一个旋转数组,找出最小的元素 findMinRotatedArray
//思路:左边指针最后指向最大的数,右边指针最后指向最小的数(无重复的情况)
private static int findMinRotatedArray(int A[]){
if(A==null||A.length<=0)
return 0;
int p1=0;
int p2=A.length-1;
int mid=0;
while(A[p1]>=A[p2]){
if(p2-p1==1){
mid=p2;
break;
}
mid=(p1+p2)/2;
if(A[mid]>A[p1]){
p1=mid;
}else {
p2=mid;
}
}
return A[mid];
}
//14、调整数组顺序,使得奇数位于偶数前面 reorderOddEven
private static void reorderOddEven(int A[]) {
if(A==null||A.length<=1)
return;
int i=0;
int j=A.length-1;
while(i<j){
while((A[i]&1)!=0){//找偶数
i++;
}
while((A[j]&1)==0){
j--;
}
if(i<j)
swap(A,i,j);
}
}
private static void swap(int[] A,int i,int j) {
A[i]=A[i]^A[j];
A[j]=A[i]^A[j];
A[i]=A[i]^A[j];
}
//18、判断树B是否为树A的子结构
private static boolean hasSubTree(TreeNode A,TreeNode B){
boolean result=false;
if(A!=null&&B!=null){
if(A.val==B.val){
result=isSubTree(A,B);
}
if(!result){
hasSubTree(A.left, B);
}
if(!result){
hasSubTree(A.right, B);
}
}
return result;
}
private static boolean isSubTree(TreeNode a, TreeNode b) {
if(a==null)
return false;
if(b==null)
return true;
if(a.val!=b.val)
return false;
return isSubTree(a.left, b.left)&&isSubTree(a.right, b.right);
}
//20、顺时针打印矩阵,从外向里顺序打印每一个数字printMatrix
private static void printMatrix(int[][] mat,int columns,int rows){
if(mat==null||columns<=0||rows<=0)
return;
int start=0;
while(columns>start*2&&rows>start*2){
printMatrixCircle(mat,columns,rows,start);
++start;
}
}
private static void printMatrixCircle(int[][] mat, int columns, int rows,
int start) {
int xEnd=columns-start-1;
int yEnd=rows-start-1;
for(int i=start;i<=xEnd;i++){//从左到右打印up行
System.out.print(mat[start][i]+" ");
}
for(int j=start+1;j<=yEnd;j++){//从上到下打印right行
System.out.print(mat[j][xEnd]+" ");
}
if(start<yEnd){
for(int i=xEnd-1;i>=start;i--){//从右到到左打印down行
System.out.print(mat[yEnd][i]+" ");
}
}
if(start<yEnd-1){
for(int j=yEnd-1;j>start;j--){//从下到上打印left行
System.out.print(mat[j][start]+" ");
}
}
}
//23、栈的压入弹出序列,序列A:压栈序列,序列B:出栈序列,判断B是否正确?isPopOrder
private static boolean isPopOrder(int[] A,int[] B){
if(A==null||B==null)
return false;
if(A.length!=B.length){
return false;
}
Stack<Integer> stacks=new Stack<Integer>();
int i=0;//A index
int j=0;//B index
int len=B.length;
while(j<len){
if(stacks.empty()||stacks.peek()!=B[j]){
if(i>=len){
break;
}
stacks.push(A[i++]);
}
if(stacks.peek()!=B[j])
break;
stacks.pop();
j++;
}
if(stacks.empty()&&j==len)
return true;
return false;
}
}