LeetCode 剑指 Offer 刷题代码 (5)

面试题68 - I. 二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

    //非递归
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while(root!=null){
            if(p.val<root.val && q.val<root.val)
                root = root.left;
            else if(p.val>root.val && q.val>root.val)
                root = root.right;
            else
                break;
        }
        return root;
    }
	//递归
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(p.val<root.val && q.val<root.val)
            return lowestCommonAncestor(root.left,p,q);
        if(p.val>root.val && q.val>root.val)
            return lowestCommonAncestor(root.right,p,q);
        return root;
    }

面试题66. 构建乘积数组

给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B 中的元素 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。

	public int[] constructArr(int[] a) {
        int [] res = new int[a.length];
        int left = 1;
        for(int i=0; i<a.length; i++){
            res[i] = left;
            left *= a[i];
        }
        int right = 1;
        for(int j=a.length-1; j>=0; j--){
            res[j] *= right;
            right *= a[j];
        }
        return res;
    }

面试题64. 求1+2+…+n

求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

    public int sumNums(int n) {
        //(1+n)*n/2    最简单的了 
        //但是我用递归 哈哈
        if(n==0) return 0;
        return n+sumNums(n-1);
    }

面试题63. 股票的最大利润

假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?

    public int maxProfit(int[] prices) {

        int left=0,right=1,res=-1;
        while (right<prices.length){
            res = res>prices[right]-prices[left]?res:prices[right]-prices[left];
            if(prices[right]<prices[left])
                left = right;
            right++;
        }
        return res>0?res:0;
    }

面试题62. 圆圈中最后剩下的数字

0,1,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

    public int lastRemaining(int n, int m) {
        int p=0;
		for(int i=2;i<=n;i++)
		{
			p=(p+m)%i;
		}	
		return p;
    }

面试题61. 扑克牌中的顺子

从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。

    public boolean isStraight(int[] nums) {
        Arrays.sort(nums);
        int zero = 0, i=0;
        for(; nums[i]==0 ;i++) if(nums[i]==0) zero++;
        while(i<4 && nums[i]+1==nums[i+1]) {
            i++;
        }
        if(i<4 && nums[i]==nums[i+1])
            return false;
        int j=4;
        while(j>i && nums[j]-1==nums[j-1])
            j--;
        return nums[j]-nums[i]-1<=zero;
    }

面试题60. n个骰子的点数

把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。

    private int [] arr = new int[6*11+1];
    public double[] twoSum(int n) {
        dfs(0,0,n);
        int num=0,sum=0, index=0;
        for(int i=1; i<=66; i++)
            if(arr[i]!=0){
                num++;
                sum += arr[i];
            }

        double []res = new double[num];
        for(int i=1; i<=66; i++)
            if(arr[i]!=0){
                res[index++] = arr[i]*1.0/sum;
            }
        return res;
    }

    private void dfs(int k, int sum, int n) {
        if(k==n){
            arr[sum]++;
            return;
        }
        for(int i=1; i<=6; i++)
            dfs(k+1,sum+i,n);
    }

面试题59 - II. 队列的最大值

请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。
若队列为空,pop_front 和 max_value 需要返回 -1

        private Queue<Integer> queue;
        private Deque<Integer> maxQueue;

        public MaxQueue() {
            queue = new LinkedList<Integer>();
            maxQueue = new LinkedList<Integer>();
        }

        public int max_value() {
            if(maxQueue.isEmpty())
                return -1;
            return maxQueue.peek();
        }

        public void push_back(int value) {
            queue.add(value);
            while(!maxQueue.isEmpty() && maxQueue.peekLast()<=value)
                maxQueue.pollLast();
            maxQueue.add(value);
        }

        public int pop_front() {
            if(queue.isEmpty())
                return -1;
            int res = queue.poll();
            if(maxQueue.peekFirst()==res)
                maxQueue.poll();
            return res;
        }

面试题59 - I. 滑动窗口的最大值

给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。

    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums==null || nums.length==0) return new int[0];
        int[] res = new int[nums.length - k + 1];
        int max=nums[0],maxIndex=0,index = 0;//加上maxIndex能提高性能
        int i=0,j=k-1;
        for(int q=0; q<k; q++) {
            if (nums[q] >= max){  //  >= -> 加上maxIndex能提高性能
                max = nums[q];
                maxIndex = q;
            }
        }
        while (j<nums.length-1){
            res[index++] = max;
            if(i==maxIndex){//最大值是左边界,从新寻找最大值
                max=nums[i+1];maxIndex = i+1;
                for(int q=i+2; q<=j+1; q++){
                    if (nums[q] >= max){
                        max = nums[q];
                        maxIndex = q;
                    }
                }
            }else{
                if(nums[j+1]>=max){
                    max = nums[j+1];
                    maxIndex = j+1;
                }
            }
            i++;j++;
        }
        res[index++] = max;
        return res;
    }
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums==null || nums.length==0) return new int[0];
        int[] res = new int[nums.length - k + 1];
        //大顶堆
        PriorityQueue<Integer> queue = new PriorityQueue<>((a, b) -> b - a);
        int i=0, j=k-1, index=0;
        for(int q=0; q<k; q++) queue.add(nums[q]);
        while(j<nums.length-1){
            res[index++] = queue.peek();
            queue.remove(nums[i++]);
            queue.add(nums[++j]);
        }
        res[index++] = queue.peek();

        return res;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值