剑指offer 1-10


package com.overridere.onetoten;

import java.util.ArrayList;

public class Solution {

    /**
     * 第一题
     * 在一个二维数组中,每一行都按照从左到右递增的顺序排序,
     * 每一列都按照从上到下递增的顺序排序。
     * 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
     */
    public boolean Find(int target, int [][] array) {
        int row = 0;
        int col = array[0].length - 1;
        while(row < array.length && col >= 0){
            if(array[row][col] < target){
                row ++;
            }else if(array[row][col] > target){
                col --;
            }else{
                return true;
            }
        }
        return false;
    }

    /**
     * 第二题
     * 请实现一个函数,将一个字符串中的空格替换成“%20”。
     * 例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
     */
    public String replaceSpace(StringBuffer str) {
        //方式一:自带替换行数
        //return str.toString().replaceAll("\\s", "%20");
        //方式二:自己编写替换
        //想法:就跟数组替换一样,因为字符串类型的容量和字符串时间内容的长度一样,所以如果自己进行替换的话需要扩容
        //需要扩容就要考虑要扩容多少,因为替换的字符串和被替换的字符串长度差为2,所以每次遇到需要替换的字符串的时候就可以将长度+2
        int len = str.length();
        int num = 0;
        for(int i = 0; i < len; i ++){
            if(str.charAt(i) == ' '){           //如果是空格的话
                str.setLength(str.length()+2);  //将长度加长2个,因为插入的字符串比替换的字符串长2,所以没遇到一个空格就要多两个长度
                num +=2;                        //记录一下新增位置的数量
            }
        }
        //带到这里新的被扩容的字符串容器弄好了,接下来就是遍历替换了
        //因为扩容的位置是在后面加上的,如果从前面遍历的话,遇到一个空格将要将后面所有元素往后推,这样效率低
        //从后遍历的话可以这样做,因为位置是在后面添加的,所以从后面遍历的时候就可以带着新增的位置往前遍历,遇到空格就把位置方向来进行替换
        //假设数组为' who are you ',扩容之后为' who are you         'num为8,len为以前的长度13
        //第一次遇到空格的时候j为len-1,num为8,变化为' who are you      %20'
        //第一次遇到不少空格的时候(u),变化为' who are yo      u%20'
        //然后继续:' who are y      ou%20'--》' who are       you%20'--》' who are    %20you%20'
        for(int j = len-1;j >= 0;j --){
            if(str.charAt(j) == ' '){       
                num-=2;
                str.setCharAt(j+num,'%');   
                str.setCharAt(j+num+1,'2'); 
                str.setCharAt(j+num+2,'0');
            }else
                str.setCharAt(j+num, str.charAt(j));
        }
        return str.toString();

    }

    public String replaceSpace2(StringBuffer str) {
        //方式三:在扩容的时候顺便插入了
        for(int i = 0; i < str.length(); i ++){
            if(str.charAt(i) == ' '){           
                str.setLength(str.length()+2);  
                for(int j = str.length()-1;j > i+2;j --){
                    str.setCharAt(j, str.charAt(j-2));
                }
                str.setCharAt(i,'%');   
                str.setCharAt(i+1,'2'); 
                str.setCharAt(i+2,'0');
            }
        }
        return str.toString();

    }

    /**
     * 第三题
     * 输入一个链表,从尾到头打印链表每个节点的值。{67,0,24,58}
     */
    public class ListNode {
        int val;
        ListNode next = null;

        ListNode(int val) {
            this.val = val;
        }
    }
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> list = new ArrayList<>();
        if(listNode != null){
            list = printListFromTailToHead(listNode.next);
            list.add(listNode.val);
        }
        return list;
    }

    /**
     * 第四题
     * 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
     * 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
     */
    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode(int x) {
            val = x;
        }
    }

    public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
        TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
        return root;
    }
    //前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
    public TreeNode reConstructBinaryTree(int [] p,int sp,int ep,int [] in,int si,int ei) {
        if(sp>ep||si>ei)
            return null;
        TreeNode root=new TreeNode(p[sp]);
        //中序遍历得出的数组特点为:根左边的数据-根节点-根右边的数据
        //前序遍历得出的数组特点为:根-根左边的数据-根右边的数据
        //所以左儿子就可以在根左边的数据中找,右儿子在根右边的数据中找
        //          根左边的数据  (-根节点)  -根右边的数据
        //(根节点-)    根左边的数据              -根右边的数据
        //递归的时候就可以把根节点去掉了,找左儿子就传递两个根左边的数据,找右儿子就传递两个根右边的数据
        for(int i=si;i<=ei;i++){
            if(in[i]==p[sp]){//意味着遍历到了根
                //前序遍历切割为:2,4,7,中序遍历切割为:4,7,2,两个数组都是根节点左边的数据
                root.left=reConstructBinaryTree(p,sp+1,sp+i-si,in,si,i-1);
                //前序遍历切割为:3,5,6,8,中序遍历切割为:5,3,8,6,两个数组都是根节点右边的数据
                root.right=reConstructBinaryTree(p,i-si+sp+1,ep,in,i+1,ei);
            }
        }
        return root;
    }

    /**
     * 第五题 QueueFromTwoStack
     */

    /**
     *  第六题
     *  把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
     *  输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
     *  例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
     *  NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
     */
    public int minNumberInRotateArray(int [] array) {
        for(int i = 0; i < array.length-1; i ++){
            if(array[i]>array[i+1]){
                return array[i+1];
            }
        }
        return 0;
    }

    /**
     * 第七题
     * 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。n<=39
     */
    public int Fibonacci(int n) {

        //方式一:

//      if(n <= 0)
//          return 0;
//      else if(n == 1)
//          return 1;
//      else
//          return Fibonacci(n-1) + Fibonacci(n-2);

        //方式二:递归2   
//      return tailRecursion(n, 0, 1);

//      方式三
//      int [] nums = new int[n];
//      if(n <= 0){
//          return 0;
//      }
//      for(int i = 0; i < n; i ++){
//          if(i <= 1)
//              nums[i] = 1;
//          else
//              nums[i] = nums[i-1] + nums[i-2];
//      }
//      return nums[nums.length - 1];

        //方式四
        int n1 = 0; int n2 = 1;
        if(n <= 0)
            return n1;
        else if(n == 1)
            return n2;
        else{
            while(n-->1){
                n2 = n1 + n2;
                n1 = n2 - n1;
            }
        }
        return n2;
    }

    public int tailRecursion(int n, int n1, int n2){
        if(n <= 0)
            return 0;
        else if(n == 1)
            return n2;
        else
            return tailRecursion(--n, n2, n1+n2);
    }

    /**
     * 第八题
     * 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
     * 
     * 其它方法可以参考上面的题目
     */
    public int JumpFloor(int target) {
        //也是斐波那契数列
        int n1 = 0; int n2 = 1;
        if(target <= 0)
            return n1;
        else if(target <= 2)
            return target;
        else{
            while(target-->1){
                n2 = n1 + n2;
                n1 = n2 - n1;
            }
        }
        return n1+n2;
    }

    /**
     * 第九题
     * 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
     * 
     * 思路:当你还没跳到时候,你有n种跳法,跳1阶或者2阶。。。或者n阶,
     * 当你在1阶的时候有n-1中跳法,当你在2阶的时候有n-2种跳法,当你在n-1阶时只有1中跳法
     * 逆向思路:当你在n阶的时候你有可能从n-1阶跳过来的,也有可能是从n-2阶。。。。或者从1阶跳过来的,或者从0跳过来的
     * 总共有n种台阶让你到达n阶,当你在n-1阶的时候总共有n-1种台阶让你到达n-1阶
     * 设函数f(n)为你到达n阶所可能使用的跳法总数,如果是从n-1阶跳过来的那么就要知道到达n-1阶所可能使用的跳法总数。。。
     * 所以f(n) = f(n-1)+f(n-2)+...+f(1)+f(0),f(n-1) = f(n-2)+f(n-3)...+f(1)+f(0)...
     * 所以f(n) = f(n-1)+[f(n-2)+...+f(1)+f(0)] = f(n-1)+f(n-1) = 2f(n-1);
     */
    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的大矩形,总共有多少种方法?
     * 
     * 思路:如果最后一个小矩形是横向放置的,那么第n-1个小矩形肯定也是横向放置的,前n-2个矩形放置方法总数需要求
     * 如果最后一个小矩形是纵向放置的,则前n-1个矩形放置方法总数需要求
     * 所以f(n) = f(n-1)+f(n-2) 斐波那契递归,这种递归又有好多种其它方法实现
     * 
     */
    public int RectCover(int target) {
        int n1 = 1,n2 = 2;
        if(target <= 0)
            return 0;
        else if(target == 1)
            return 1;
        else if(target == 2)
            return 2;
        while(target-- > 2){
            n2 = n1 + n2;
            n1 = n2 - n1;
        }
        return n2;
    }
}

第五题

package com.overridere.onetoten;

import java.util.Stack;

/**
 * 第五题
 * 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
 * @author OverrideRe
 *
 */
public class QueueFromTwoStack {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();

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

    public int pop() {
        if(stack2.isEmpty()){
            while(stack1.size() > 0){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值