剑指offer:分治算法

剑指offer(四):分治算法

我是菜逼!!!!!!

题目一:重建二叉树

public class p7 {
    int [] preorder;
    //使用哈希表来标记索引,得到根节点在中序遍历列表中的位置
    HashMap<Integer,Integer> dic = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;
        for (int i = 0; i < inorder.length; i++) {
            dic.put(inorder[i],i);//将中序遍历列表及其索引存入哈希表
        }
        return recur(0,0,inorder.length-1);
    }
    //1、递归的功能就是建立对应的二叉树
    TreeNode recur(int root, int left, int right){
        //2、递归的终止条件是当左边界大于右边界则结束
        if (left>right)return null;
        //3、递推工作
        TreeNode node = new TreeNode(preorder[root]);//建立当前节点
        int i = dic.get(preorder[root]);//得到当前根节点中序遍历中的索引
        node.left = recur(root + 1, left, i - 1);//分开构造其左节点
        node.right = recur(root+i-left+1,i+1,right);//分开构造其右节点
        return node;//回溯返回根节点
    }
}

题目二: 数值的整数次方

class Solution {
    public double myPow(double x, int n) {
        //当x为0时返回0;
        if(x == 0.0f) return 0.0d;
        //执行时会因越界而赋值出错,解决方案是先将n
        long b = n;
        double res = 1.0;
        if(b < 0) {
            //b小于0的话x取倒数,b取
            x = 1 / x;
            b = -b;
        }
        while(b > 0) {
            if((b & 1) == 1) res *= x;
            x *= x;
            b >>= 1;
        }
        return res;
    }
}
tips:
  • 幂结果获取:

    • 根据推导,可通过循环 x = x^2操作,每次把幂从 n降至 n//2 ,直至将幂降为 0;
    • 设 res=1,初始状态 x^n = x^n*res。在循环二分时,每当 n 为奇数时,将多的一项 x 乘入 res ,则最终可化至 x^n = x^0 * res = res,返回 res 即可。
  • n&1**(与操作)**:判断n二进制最右一位是否为1;

  • n>>1**(移位操作)**:n右移一位(可理解为删除最后一位)。

题目三: 打印从 1 到最大的 n 位数

class Solution {
    int[] res;
    int nine = 0, count = 0, start, n;
    char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    public int[] printNumbers(int n) {
        this.n = n;
        res = new int[(int)Math.pow(10, n) - 1];
        num = new char[n];
        start = n - 1;
        dfs(0);
        return res;
    }
    //1、递归功能,生成n位数的数字序列
    void dfs(int x) {
        //2、递归的终止条件,当添加到最后一位数字时加入表示结果的字符串队列
        if(x == n) {
            //2.1、分离出高位的0
            String s = String.valueOf(num).substring(start);
            //2.1、添加到结果序列中
            if(!s.equals("0")) res[count++] = Integer.parseInt(s);
            if(n - start == nine) start--;
            return;
        }
        for(char i : loop) {
            if(i == '9') nine++;
            num[x] = i;
            dfs(x + 1);
        }
        nine--;
    }
}

题目四:二叉搜索树的后序遍历序列

关键点:找到序列中第一个大于根节点的数,然后以此为界限分为左右两个区间

//方法一:递归分治
   public boolean verifyPostorder(int[] postorder) {
        return recur(postorder, 0, postorder.length-1);
    }
    //1、判断当前序列是否为后序遍历序列
    boolean recur(int[] list, int i, int j){
        //2、终止条件是左边界大于等于右边界,此时返回true
        if (i>=j)return true;
        //2.1、递归工作是首先判断左树中的元素是否都小于最后的值
        int p = i;
        while (list[p]<list[j])p++;
        //2.2、接着判断右树中的元素是否都大于最后的值
        int m = p;
        while (list[p]>list[j])p++;
        //3、返回值,遍历到头且左右树都是后序遍历的结果
        return p==j&&recur(list,0,m-1)&&recur(list,m,j-1);
    }
}

//方法二:辅助单调栈
class Solution {
    public boolean verifyPostorder(int[] postorder) {
        Stack<Integer> stack = new Stack<>();
        int root = Integer.MAX_VALUE;
        for(int i = postorder.length - 1; i >= 0; i--) {
            if(postorder[i] > root) return false;
            while(!stack.isEmpty() && stack.peek() > postorder[i])
                root = stack.pop();
            stack.add(postorder[i]);
        }
        return true;
    }
}

题目五:数组中的逆序对

class Solution {
    //和归并排序一个思想
    int[] nums,tem;
    public int reversePairs(int[] nums) {
        this.nums = nums;
        tem = new int[nums.length];
        return recur(nums, 0, nums.length-1) ;
    }
    int res;
    //1、递归功能,实现对逆序对的统计
    int recur(int[] nums, int l, int r){
        //2、终止条件是左边界大于右比边界的索引值
        if (l>=r)return 0;
        //将原区间分开
        int m = (l+r)/2;
        res = recur(nums, l, m)+recur(nums, m+1, r);
        for (int i = l; i <= r; i++) {
            tem[i] = nums[i];
        }
        int x =l, y=m+1;
        //合并区间
        for (int k = l; k <= r; k++) {
            if (x==m+1)nums[k]=tem[y++];
            else if (y==r+1||tem[x]<=tem[y])nums[k]= tem[x++];
            else {
                nums[k]=tem[y++];
                res+=m-x+1;
            }
        }
        return res;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值