zoukankan      html  css  js  c++  java
  • [剑指offer] JZ 5-7 做题笔记

    JZ5 用两个栈实现队列

    题目描述

    题目描述
    用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

    思路:一个栈进,一个栈出,即实现了队列

    代码

    import java.util.Stack;
    
    public class Solution {
        Stack<Integer> stack1 = new Stack<Integer>();
        Stack<Integer> stack2 = new Stack<Integer>();
        
        public void push(int node) {
            stack1.push(node);
        }
        
        public int pop() {
            if(stack1.empty()&&stack2.empty()){
                throw new RuntimeException("Queue is empty!");
            }
            if(stack2.empty()){
                while(!stack1.empty()){
                    stack2.push(stack1.pop());
                }
            }
            return stack2.pop();
        }
    }
    

    JZ6 旋转数组的最小

    题目描述

    把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
    输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
    NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
    示例1
    输入
    [3,4,5,1,2]
    返回值
    1

    思路1:直接遍历,效率很低,但是代码能过

    运行时间:198ms
    超过79.15%用Java提交的代码
    占用内存:29076KB
    超过6.92%用Java提交的代码

    代码

    import java.util.ArrayList;
    public class Solution {
        public int minNumberInRotateArray(int [] array) {
            int min = array[0];
            for(int i=1; i < array.length; i++){
                if(min > array[i]){
                    min = array[i];
                }
            }
            return min;
        }
    }
    

    思路2:二分的思想

    将右端点标识为target,中端点标示mid,array[mid]和target比较共三种情况:
    array[mid] < target: 因为是非递增数组,下一个查找区间应该是在[first,mid]找
    array[mid] > target:下一个查找区间为[mid+1, last]
    array[mid] = target:不能判断,将last=last-1后继续查找。
    但是,不能将左端点制定为target,如

    • 12345,mid=3,target=1,mid>target,但最小在mid左侧
    • 34512,mid=5,target=3,mid>target,但最小在mid右侧

    代码

    import java.util.ArrayList;
    import java.util.Arrays;
    public class Solution {   
        public int minNumberInRotateArray(int [] array) {
            if(array.length == 0) return 0;
            int first = 0, last = array.length - 1;
            while(first < last){//first = last的时候只有一个元素,停止
                if(array[first] < array[last]){//退出,说明没有旋转,就是按照递增的顺序
                    return array[first];
                }
                int mid = first + ((last - first) >> 1);
                if(array[mid] > array[last])
                    first = mid + 1;
                else if(array[mid] < array[last])
                    last = mid;
                else
                    --last;
            }
            return array[first];
        }
    };
    

    JZ 7 斐波那契数列

    题目描述

    大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。
    n≤39n≤39
    示例1
    输入
    4
    返回值
    3

    思路1:直接递归,但是有大量重复计算,时间和空间复杂度都比较高

    public class Solution {
        public int Fibonacci(int n) {
            if(n == 0 || n == 1) return n;
            return Fibonacci(n-1) + Fibonacci(n-2);
        }
    }
    时间复杂度:O(2^n)
    空间复杂度:递归栈的空间
    

    思路2:将计算过的斐波那契的值存在另外一个数组中,不再二次计算,减少时间复杂度

    import java.util.Arrays;
    //解决第一次提交中递归中重复计算的问题,节约时间
    public class Solution {
        public int Fib(int n, int[] dp){
            if(n == 0 || n == 1) return n;
            if(dp[n] != -1) return dp[n];//dp用来存放FIbonacci(n),只要不为-1.说明计算过了,直接返回。
            return dp[n] = Fib(n-1, dp) + Fib(n-2, dp);//如果没算过,先计算,再返回
        }
        public int Fibonacci(int n) {
            int[] dp = new int[45];//测试用例长度小于45
            Arrays.fill(dp, -1);//将为计算的地方填充为-1,因为答案均大于0,方便计算
            return Fib(n, dp);
        }
    }
    

    时间复杂度:O(n), 没有重复的计算
    空间复杂度:O(n)和递归栈的空间

    思路3:动态规划

    虽然方法二可以解决此题了,但是如果想让空间继续优化,那就用动态规划,优化掉递归栈空间。
    方法二是从上往下递归的然后再从下往上回溯的,最后回溯的时候来合并子树从而求得答案。
    那么动态规划不同的是,不用递归的过程,直接从子树求得答案。过程是从下往上。

    public class Solution {
        public int Fibonacci(int n) {//直接 从子树开始
            int [] dp = new int[n+1];
            dp[1] = 1;
            for(int i = 2; i <= n; ++i){
                dp[i] = dp[i-1] + dp[i-2];
            }
            return dp[n];
        }
    }
    

    这段代码我本地试了下没问题,牛客网上显示数组越界,暂时不纠结了。
    时间复杂度:O(n)
    空间复杂度:O(n)

    再进一步,计算n的时候,只会用到n-1和 n-2,所以这里只用保存2个元素

    public class Solution {
        public int Fibonacci(int n) {//直接 从子树开始
            if(n == 0 || n == 1) return n;
            int a = 0 , b = 1, c = 0;
            for(int i = 2; i <= n; ++i){
                c = a + b;
                a = b;
                b = c;
            }
            return c;
        }
    }
    

    时间复杂度:O(n)
    空间复杂度:O(1)

    日积月累,水滴石穿
  • 相关阅读:
    如何设置backBarButtonItem的title和action
    让navigationItem.leftBarButtonItem具有backBarButtonItem的外观样式
    在Xcode中添加空模板
    reason:'CALayer position contains NaN: [160 nan]'
    git的注册与使用:代码的版本控制器
    iOS开发零基础教程之Git的一些常用命令
    iOS开发零基础教程之生成git所需的SSH keys
    iOS开发零基础教程之在终端(Terminal)里安装oh my zsh
    iOS开发零基础教程之Homebrew的安装
    [原]ibatis 数据库时间 插入数据
  • 原文地址:https://www.cnblogs.com/lonelyisland/p/14395723.html
Copyright © 2011-2022 走看看