剑指offer(1-20)题

第一题:

/**
 * 在一个二维数组中,
 * 每一行都按照从左到右递增的顺序排序
 * 每一列都按照从上到下递增的顺序排序。
 * 请完成一个函数
 * 输入这样的一个二维数组和一个整数
 * 判断数组中是否含有该整数
 *
 */
public class Demo01 {

	public static void main(String[] args) {
		//int  std[][] = {{1,2,8,9},{2,4,9,12},{4,7,10,13,},{6,8,11,15}};
		int std[][] ={{}};
		System.out.println(new Demo01().Find(7, std));


	}

	public boolean Find(int target, int [][] array) {


		boolean found = false;
		int lie = array[0].length;

		int hang = array.length;  

		int column = lie -1;
		int row =0;
		while(row<hang &&column>=0){
			int value = array[row][column];
			if(target>value){
				row++;
			}else if(value>target){
				column--;
			}else{
				found = true;
				break;
			}

		}
		return found;

	}




第二题:
/**
 * 请实现一个函数,
 * 将一个字符串中的空格替换成“%20”。
 * 例如,当字符串为We Are Happy.
 * 则经过替换之后的字符串为We%20Are%20Happy
 * @author 大护法
 *
 */
public class Demo02 {
	
	public static void main(String[] args) {
		StringBuffer str = new StringBuffer("We Are Happy");
		new Demo02().replaceSpace(str);
		
		System.out.println(new Demo02().replaceSpace(str));
		
	}
	public String replaceSpace(StringBuffer str) {
		if(str == null){
			return null;
		}
		
		StringBuffer newStr = new StringBuffer();
		
		for(int i=0; i<str.length(); i++){
			if(str.charAt(i) == ' '){
				newStr.append('%');
                newStr.append('2');
                newStr.append('0');
			}else{
				newStr.append(str.charAt(i));
			}
			
			
		}
		
		return newStr.toString();


	}
}

第三题
/**
 *    输入一个链表,从尾到头打印链表每个节点的值。
 *    
 *    public class ListNode {
 *        int val;
 *        ListNode next = null;
 *
 *        ListNode(int val) {
 *            this.val = val;
 *        }
 *    }
 *
 *    思路 :可以将链表中的元素放入一个栈中 
 *         然后在根据栈先进先出的特点将其压入一个 list的集合中
 */




public class Demo03 {
	public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
		Stack<Integer> stack = new Stack<Integer>();
		
		while(listNode!=null){
			stack.push(listNode.val);
			listNode = listNode.next;
		}
		
		ArrayList<Integer> list = new ArrayList<Integer>();
		
		
		//stack.isEmpty() 判断栈是否初始化
		while(!stack.isEmpty()){
			list.add(stack.pop());
		}
		return list;


	}
	
	public static void main(String[] args) {
		Stack<Integer> stack = new Stack<Integer>();
		stack.push(2);
		stack.push(3);
		
		System.out.println(stack.isEmpty());
	}
}

第四题
/**
 * 输入某二叉树的前序遍历和中序遍历的结果,
 * 请重建出该二叉树。
 * 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
 * 例如输入前序遍历序列
 * {1,2,4,7,3,5,6,8}
 * 和中序遍历序列{4,7,2,1,5,3,8,6},
 * 则重建二叉树并返回。
 * 
 * 
 * 注 :
 * Arrays.copyOfRange(T[ ] original,int from,int to)将一个原始的数组original,
 * 从小标from开始复制,复制到小标to,生成一个新的数组。
 * 注意这里包括下标from,不包括下标to。
 * 
 * 
 * 思路: 根据前序遍历确定二叉树的根结点  然后根据根节点递归,每次都将二叉树分成左右两边
 * 
 * @author 大护法
 *
 *
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */


public class Demo04 {
	
	public static void main(String[] args) {
		int[] pre = {1,2,4,7,3,5,6,8};
		int[] in  = {4,7,2,1,5,3,8,6};
		
		System.out.println(new Demo04().reConstructBinaryTree(pre, in));
	}
	public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
		if(pre.length == 0 || in.length==0){
			return null;
		}
		
		//创建树输入根节点
		TreeNode node = new TreeNode(pre[0]);
		
		for(int i = 0; i < in.length; i++){
            if(pre[0] == in[i]){
                node.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i+1), Arrays.copyOfRange(in, 0, i));
                node.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i+1, pre.length), Arrays.copyOfRange(in, i+1,in.length));
            }
        }
		
		return node;
	}


}

第五题
/**
 * 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
 * 
 * 思路 :  定义了两个栈 
 *       可以利用栈的定义根据出栈和进栈来实现队列的基本操作
 *       
 * @author 大护法
 *
 */
public class Demo05 {
	Stack<Integer> stack1 = new Stack<Integer>();
	Stack<Integer> stack2 = new Stack<Integer>();


	public void push(int node) {
        stack1.push(node);
	}


	public int pop() {
		while(!stack1.isEmpty()){
			stack2.push(stack1.pop());
		}
		
		int temp = stack2.pop();
		
		while(!stack2.isEmpty()){
			stack1.push(stack2.pop());
		}
		
		return temp;


	}
}

第六题
/**
 * 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 
 * 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 
 * 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
 * NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
 * @author 大护法
 *
 *
 *
 * 注:采用2分法进行查找
 */
public class Demo06 {


	public int minNumberInRotateArray(int [] array) {
		
		
		if(array == null || array.length == 0) return 0;
		
		
		int start = 0;                   //头元素
		int end = array.length - 1;      //尾元素
		int mid = (start + end) / 2;     //中间元素
		
		//只有一个元素
		if(array[end] == array[start] || array[mid] == array[end] || array[mid] == array[start]){
			return findMin(array);
		}
		
		//
		if(array[mid] > array[start] && array[mid] < array[end]){
			return array[0];
		}
		
		while(true){
			mid = (start + end) / 2;
			if(array[mid] > array[start]){
				start = mid;
			}else if(array[mid] < array[end]){
				end = mid;
			}
			if((start+1) == end) break;
		}
		return array[end];
	}


	public int findMin(int[] array){
		int result = Integer.MAX_VALUE;
		for(int i = 0; i <= array.length - 1; i++){
			result = Math.min(result, array[i]);
		}
		return result;
	}


	public static void main(String[] args) {
		int a[] = {6501,6828,6963,7036,7422,7674,8146,8468,8704,8717,9170,
				9359,9719,9895,9896,9913,9962,154,293,334,492,1323,1479,1539,1727,
				1870,1943,2383,2392,2996,3282,3812,3903,4465,4605,4665,4772,
				4828,5142,5437,5448,5668,5706,5725,6300,6335};


		int m = new Demo06().minNumberInRotateArray(a);
		System.out.println(m);
	}
}

第七题
/**
 * 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项
 * 
 * 斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
 * 如果设F(n)为该数列的第n项(n∈N*),那么这句话可以写成如下形式::F(n)=F(n-1)+F(n-2)
 * 显然这是一个线性递推数列。
 * 
 * 
 * 用迭代进行计算
 * @author 大护法
 *
 */
public class Demo07 {
	public int Fibonacci(int n) {




		if(n == 0)return 0;
		if(n == 1 || n ==2){
			return 1;
		}
		
		int fn1 = 1;
	    int fn2 = 1;
	    int fnsum = 0;
	    
	    for(int i = 3; i<=n; i++){ 	
	    	fnsum = fn1 + fn2;
	    	fn2 = fn1;
	    	fn1 = fnsum;
	    	
	    }
		return fnsum;
	
	}
	
	public static void main(String[] args) {
		int m = new Demo07().Fibonacci(39);
		System.out.println(m);
	}
}

第八题
/**
 * 
 *  **   递归循环
 *  一只青蛙一次可以跳上1级台阶,也可以跳上2级。
 *  求该青蛙跳上一个n级的台阶总共有多少种跳法。
 *  
 *  注 :
 *       台阶         方法
 *       f(1)     1
 *       f(2)     2
 *       f(3)     3
 *       f(4)     5
 *       f(5)     8
 *       
 *       推出规律 f(n) = f(n-1)+f(n-2)    n>2;
 * @author 大护法
 *
 */
public class Demo08 {
	public int JumpFloor(int target) {
		
		if(target <= 0) return 0;
		if(target == 1) return 1;
		if(target == 2) return 2;
		
		int fn1 = 2; 
		int fn2 = 1; 
		int result = 0;
		for(int i=3; i<=target; i++){
			result = fn1+fn2;
			fn2 = fn1;
			fn1 = result;
		}
		return result;


    }
}

第九题
/**
 * 变态跳台阶
 * 
 * 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。
 * 求该青蛙跳上一个n级的台阶总共有多少种跳法。
 * 
 * 
 * 注:
 * 
 * f(1) = 1
 * f(2) = f(2-1) + f(2-2)         //f(2-2) 表示2阶一次跳2阶的次数。
 * f(3) = f(3-1) + f(3-2) + f(3-3) 
 * ...
 * f(n) = f(n-1) + f(n-2) + f(n-3) + ... + f(n-(n-1)) + f(n-n) 
 * 
 * 所以得出递推公式 采用递归实现
 *          | 1         (n=0 ) 
 *  f(n) =  | 1         (n=1 )
 *          | 2*f(n-1)  (n>=2)
 *          
 *          
 * @author 大护法
 *
 */
public class Demo09 {
	public int JumpFloorII(int target) {
		
		if(target <= 0){
			return 0;
		} else if(target == 1){
			return 1;
		}else{
		    return 2 * JumpFloorII(target - 1);
		}
		


	}
}

第十题
/**
 * 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形
 * 请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
 * 
 * 注:
 * 根据推到得出递推公式:
 *       1 (n=1)
 * f(n)  2 (n=2)
 *       f(n-1)+f(n-2)  (n>2)
 * @author 大护法
 *
 */
public class Demo10 {
	
	public int RectCover(int target) {
		
         if(target <= 0){
        	 return 0;
         }else if(target == 1 || target == 2){
        	 return target;
         }else {
			return RectCover(target-1) + RectCover(target-2);
		}
         
    }




}

第十一题(不会)
/**
 * 位运算:
 * 
 * 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
 * @author 大护法
 *
 */
public class Demo11 {


}

第十二题
/**
 * 数值的整数次方:
 * 
 * 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
 * 
 * @author 大护法
 *
 */
public class Demo12 {
	public double Power(double base, int exponent) {


		double std=1.0;
		
		if(base == 0){
			return 0.0000;
		}else if(exponent<0){
			exponent = Math.abs(exponent);
			
			for(int i =0; i<exponent; i++){
				std = std*base;
			}
			
			return 1/std;
			
		}else{
			for(int i=0; i<exponent; i++){
				std = std*base;
			}
			
			return std;
		}
		
	}
	
	
	public static void main(String[] args) {
		System.out.println(new Demo12().Power(-1.25, -3));
	}
}

第十三题
/**
 * 
 * 
 * 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,
 * 所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变
 * 
 * 
 * 注:
 * 定义一个新数组,然后统计新数组中的奇数和偶数的个数
 * 然后对原数组进行遍历根据条件压入新的数组
 * @author 大护法
 *
 */
public class Demo13 {
	public void reOrderArray(int [] array) {
        int[] result = new int[array.length];
        
        int numofOdd = 0;   //奇数个数
        
        
        
        for(int i =0; i<array.length; i++){
        	if(array[i]%2 == 1){
        		numofOdd ++;
        	}
        }
        
        
        int indexofOdd = 0;
        int indexOfEven = numofOdd;
        
        for(int i =0; i<array.length; i++){
        	if(array[i]%2 == 1){
        		result[indexofOdd++] = array[i];
        	}else{
        		result[indexOfEven++] = array[i];
        	}
        }
        
        for(int i=0;i<array.length;i++){
            array[i] = result[i];
        }
	}
}

第十四题
/**
 * 输入一个链表,输出该链表中倒数第k个结点。
 * 
 * 
 * 
 * @author 大护法
 *
 */




public class Demo14 {
	public ListNode FindKthToTail(ListNode head,int k) {
		if(head == null){
			return head;
		}
		
		ListNode node = head;
		int count = 0;
		
		while(node != null){
			count++;
			node = node.next;
		}
		
		if(count<k) return null;
		
		ListNode  p = head;
		for(int i =0; i<count-k; i++){
			p = p.next;
		}
		return p;
	}
}

第十五题
/**
 * 输入一个链表,反转链表后,输出链表的所有元素
 * @author 大护法
 *
 */
public class Demo15 {
	public ListNode ReverseList(ListNode head) {
		if(head == null){
			return null;
		}
		
		ListNode newHead = null;
		ListNode pNode = head;
		ListNode pPrev = null;
		
		while(pNode != null){
			pPrev = newHead;
			newHead = pNode;
			pNode = pNode.next;
			newHead.next = pPrev;
		}
		
		return newHead;
		
	


	}
}

第十六题
/**
 * 
 * 输入两个单调递增的链表,输出两个链表合成后的链表,
 * 当然我们需要合成后的链表满足单调不减规则。
 * @author 大护法
 *
 */
public class Demo16 {
	public ListNode Merge(ListNode list1,ListNode list2) {
		if(list1==null){
			return list2;
		}else if(list2==null){
			return list1;
		}
		ListNode pMergeHead = null;
		if(list1.val<list2.val){
			pMergeHead = list1;
			pMergeHead.next = Merge(list1.next,list2);
		}else{
			pMergeHead = list2;
			pMergeHead.next = Merge(list1,list2.next);
		}
		return pMergeHead;
	}


}

第十七题
/**
 * 输入两棵二叉树A,B,判断B是不是A的子结构。
 * (ps:我们约定空树不是任意一个树的子结构)
 * 
 * 注:
 *   首先遍历 A 树 查找和B树根结点相同的节点 然后 A树以次为根节点  和 B树进行比较
 *   
 *   
 *   特别注意root2 为空时候的比较
 * @author 大护法
 *
 */
public class Demo17 {
	public boolean HasSubtree(TreeNode root1,TreeNode root2) {


		if(root2 == null) return false;
		if(root1 == null && root2 != null) return false;


		boolean flag = false;


		if(root1.val == root2.val){
			flag = isSubTree(root1,root2);
		}if(flag == false){
			flag = HasSubtree(root1.left, root2);
			if(flag == false){
				flag = HasSubtree(root1.right, root2);
			}
		}
		return flag;	


	}


	private Boolean isSubTree(TreeNode root1,TreeNode root2) {
		if(root2 == null) return true;
		if(root1 == null && root2 != null) return false;


		if(root1.val == root2.val){
			return isSubTree(root1.left, root2.left)  && isSubTree(root1.right, root2.right);
		}


		return false;
	}
}

第十八题
/**
 * 操作给定的二叉树,将其变换为源二叉树的镜像。
 * 
 * 注:
 * 
 *   利用递归 从根节点之后依次递归交换左右子树 便可以得到所谓镜像二叉树
 * @author 大护法
 *
 */
public class Demo18 {
	public void Mirror(TreeNode root) {
        if(root == null)
        	return;
        if(root.left == null && root.right == null)
        	return;
        
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
        
        if(root.left != null)
        	Mirror(root.left);
        if(root.right != null)
        	Mirror(root.right);
	}


}

第十九题
/**
 * 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字
 * 例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
 * 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
 * 
 * @author 大护法
 *
 */
public class Demo19 {
	public ArrayList<Integer> printMatrix(int [][] matrix) {
		
		
		ArrayList<Integer> list = new ArrayList<Integer>();
		int rows = matrix.length;       //行
		int cols = matrix[0].length;    //列
		
		System.out.println("rows ="+rows+"; cols"+cols);
		if(rows==0 && cols==0) return list;
		
		
		
		
		int left = 0, top = 0, right = cols - 1, bottom = rows - 1;
		while(rows>0 && cols>0){
			for(int i=left; i<=right; i++){
				list.add(matrix[top][i]);
			}
			for(int i=top+1; i<=bottom; i++)
			{
				list.add(matrix[i][right]);
			}
			
			if (top != bottom)
			for(int i=right-1; i>=left; i--){
				list.add(matrix[bottom][i]);
			}
			
			if (left != right)
			for(int i=bottom-1; i>=top+1; i--){
				list.add(matrix[i][left]);
			}
			
			left++;  top++;
			right--; bottom--;
			rows =rows-2;
			cols =cols-2;
		}
		
		
		
		return list;
	       
    }
	
	
	public static void main(String[] args) {
		int[][] matrix={{1},{2},{3},{4},{5}};
		System.out.println(new Demo19().printMatrix(matrix));
	}
}

第二十题
/**
 * 定义栈的数据结构,
 * 请在该类型中实现一个能够得到栈最小元素的min函数
 * @author 大护法


 *
 */
public class Demo20 {
	
	Stack<Integer> stack = new Stack<Integer>();
	//入栈
	public void push(int node) {
        stack.push(node);
	}


	
	//出栈
	public void pop() {
        stack.pop();
	}


	//返回栈顶的元素
	public int top() {
        return stack.peek();
	}


	//返回栈中最小的元素
	public int min() {
        int min = top();
        int temp;
        Iterator<Integer> it = stack.iterator();
        
        while(it.hasNext()){
            temp=it.next();
            if(temp<min)
                min=temp;
        }
        return min;
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值