【剑指offer】java版题解(持续更新)

本文为刷【剑指】备战校招的过程,持续更新
备战虽晚但卷,共勉!

斐波那契数列

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

一刷 2021.7.13

  • 无脑平推法(渣渣能快速想到的就是这一种)

    public class Solution {
         
        public int Fibonacci(int n) {
         
            int x = 0;
            int y = 1;
            if(n<1 || n>39){
         
                return 0;
            }
            for(int i = 1;i<n;i++){
         
                y = x+y;
                x = y-x;
            }
            return y;
        }
    }   
    
  • 递归实现

    这个解法是百度发到了斐波那契数列的公式得出的,下面que出斐波那契数列的公式
    在这里插入图片描述
    通过以上公式,就能得出以下的算法啦

    public class Solution {
         
        public int Fibonacci(int n) {
         
            if(n==0)
                return 0;
            if(n==1)
                return 1;
            return Fibonacci(n-1) +Fibonacci(n-2);
        }
    }
    
  • 数组实现
    用一个数组将每个值存起来,需要的时候直接取,不用重复计算

	//第一种
    public static int Fibonacci2(int n) {
   
        ArrayList<Integer> list = new ArrayList<>();
        list.add(0);
        list.add(1);
        if(n <= 1){
   
            return list.get(n);
        }else{
   
            for(int i = 2; i <= n; i++){
   
                list.add(list.get(i-1)+list.get(i-2));
            }
            return list.get(n);
        }
    }
	//第二种
	class Solution {
   
    public int fib(int n) {
   
        if (n<2) return n;
        long[] result = new long[n+1];
        result[0] = 0;
        result[1] = 1;
        for(int i = 2; i<=n;i++){
   
            result[i] = result[i-1]+result[i-2];
            result[i] %= (Math.pow(10,9) + 7);
        }
        return (int)result[n];
    }
}

用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

一刷 2021.8.2
ps:渣渣第一眼看完题目,这是什么
过一会联想到上午看《大话数据结构》时书上说到的可以用两个栈怼一起,方便入栈和出栈,但好像跟这道题没关系,不过我联想到的,我觉得至少算学习了,普通且自信
但是还是没有任何解题思路,所以我看了题解视频,网址如下
题解链接

二刷 2021.8.10
游客前一次的经验,这次上手就熟悉了很多,比较顺利

  • 思路1
    要实现队头删除和队尾插入,首先我们需要知道元素入栈是放在栈底的,且在此思路中,栈1和栈2不会同时存在元素,即若队列不为空,则元素要么全在栈1中,要么全在栈2中

    队尾插入
    若元素都在栈2,栈2的栈顶元素为队列的队头,要实现队尾插入,就要栈2的元素全部入栈1,此时栈1的栈顶元素为队尾,插入即可
    若元素都在栈1,此时栈顶元素即为队尾,直接在栈顶插入即可

    队头删除
    若元素起初都入了栈1,要删除栈1的栈底元素,就把栈1的元素全部入栈2.此时栈1的栈底元素就变为了栈2的栈顶元素,只需要将其pop出即可
    若元素都在栈2,直接pop出栈2的栈顶元素即可
    但要注意校验队列是否为空

    代码实现

    class CQueue {
         
    
        //初始化两个栈
        private Stack<Integer> stack1;
        private Stack<Integer> stack2;
        //队列
        public CQueue() {
         
            this.stack1 = new Stack<>();
            this.stack2 = new Stack<>();
        }
        
        //队尾插入
        public void appendTail(int value) {
         
        	//若栈1
            while(!stack2.isEmpty()){
         
                stack1.push(stack2.pop());
            }
            stack1.push(value);
        }
        
        //删除头部
        public int deleteHead() {
         
            while(!stack1.isEmpty()){
         
                stack2.push(stack1.pop());
            }
            if(stack2.isEmpty()){
         
                return -1;
            }
            return stack2.pop();
    
        }
    }
    
  • 思路2
    要实现队头删除和队尾插入,首先我们需要知道元素入栈是放在栈底的,在此思路中,栈1和栈2可能同时存在元素

    队尾插入
    在思路1的基础上,不论栈2是否为空,我们将元素直接插入到栈1都是正确的,所以我们在插入时,直接将元素入栈1,此时插入的时间复杂度为O(1)

    队头删除
    由思路1,栈2的栈顶元素永远是队列的头部,所以队头删除只需要将栈2中的栈顶元素pop出来即可
    但是删除元素需要对栈2做非空校验
    若栈2为空,将栈1中的元素pop出来,放到栈2中,此时栈2的栈顶元素还是是队列的头部,栈2中的栈顶元素pop出来即可
    若此时仍为空,即队列为空,return -1即可

    代码实现

    class CQueue {
         
    
        //初始化两个栈
        private Stack<Integer> stack1;
        private Stack<Integer> stack2;
        //队列
        public CQueue() {
         
            this.stack1 = new Stack<>();
            this.stack2 = new Stack<>();
        }
        
        //队尾插入
        public void appendTail(int value) {
         
            stack1.push(value);
        }
        
        //删除头部
        public int deleteHead() {
         
            if(stack2.isEmpty()){
         
                while(!stack1.isEmpty()){
         
                    stack2.push(stack1.pop());
                }
            }
            if(stack2.isEmpty()){
         
                return -1;
            }else{
         
                return stack2.pop();
            }
        }
    }
    ``
    
    

二维数组中的查找

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

一刷2021.8.4

  • 思路一 暴力破解
    无脑但好使
class Solution {
   
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
   
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
   
            return false;
        }
        int rows = matrix.length;
        int columns = matrix[0].length;

        for(int i = 0;i<rows;i ++){
   
            for(int j = 0; j < columns; j++ ){
   
                if(matrix[i][j] == target){
   
                    return true;
                }
            }
        }
        return false;
    }
}
  • 思路二 线性查找
    由题可知:每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序
    从右上角开始找
    如果当前元素大于目标值,说明当前元素的下边的所有元素都一定大于目标值,因此往下查找不可能找到目标值,往左查找可能找到目标值。如果当前元素小于目标值,说明当前元素的左边的所有元素都一定小于目标值,因此往左查找不可能找到目标值,往下查找可能找到目标值。
class Solution {
   
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
   
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
   
            return false;
        }
        int rows = matrix.length;
        int columns = matrix[0].length;
        int row = 0;
        int column = columns -1;

        while(row < rows && column >= 0){
   

            int num = matrix[row][column];
            if(num == target){
   
                return true;
            }else if(num > target){
   
                column --;
            }else{
   
                row ++;
            }  
        }
        return false;
    }
}

包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

一刷 2021.8.10
看到的时候是比较蒙的,所以只能看题解

  • new 两个栈,数据栈和辅助栈
  • 数据栈用来存储入栈的元素,辅助栈用来动态存储栈中的最小元素,且栈中的最小元素恒为辅助栈的栈顶元素
  • 当往栈中添加元素的时候,在入数据栈之前先与辅助栈的栈顶元素比较,
    • 若要添加元素小于辅助栈的栈顶元素,即此时栈中的最小元素为添加元素,将该元素分别入辅助栈和数据栈即可
    • 若要添加元素大于或等于辅助栈的栈顶元素,即此时栈中的最小元素仍为辅助栈的栈顶元素,故将辅助栈的栈顶元素再次入栈,然后将元素入数据栈
  • 删除栈顶元素的时候,由于栈中的最小元素恒为辅助栈的栈顶元素,只需将数据栈和辅助栈的栈顶元素分别出栈即可
  • 返回栈顶元素即返回数据栈的栈顶元素
  • 返回栈中的最小元素即返回辅助栈的栈顶元素
class MinStack {
   

    //数据栈
    private Stack<Integer> dataStack;
    //辅助栈,每当有元素进出数据栈,更新辅助栈的最小值
    private Stack<Integer> minStack;

    public MinStack() {
   
        //初始化数据栈和辅助栈
        dataStack = new Stack<>();
        minStack = new Stack<>();
    } 
    public void push(int x) {
   
        //如果辅助栈为空或者x小于辅助栈的栈顶元素
        //即此时栈的最小元素应为x,则将x入辅助栈
        if(minStack.isEmpty() || x<minStack.peek()){
   
            minStack.push(x);
        }else{
   //如果x大于等于辅助栈的栈顶元素,则将栈顶元素再次入栈
            minStack.push(minStack.peek());
        }
        //将x入数据栈
        dataStack.push(x);
    }   
    //删除元素只需将数据栈和辅助栈的栈顶元素分别出栈即可
    public void pop() {
   
        dataStack.pop();
        minStack.pop();
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值