剑指Offer系列之题6~题10

目录

  • 6.用两个栈实现队列
  • 7.旋转数组的最小数字
  • 8.斐波那契数列
  • 9. 跳台阶
  • 10.变态跳台阶 ??

6.用两个栈实现队列

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

考虑栈1用于存储元素,出队时,将栈1的元素压入栈2,此时栈2中元素从栈顶到底即其入队的顺序,然后出栈。若出队时栈2非空,则直接从栈2弹出元素。



1、根据栈2是否空将栈1元素全部压入:

import java.util.Stack;

public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();

    //栈1存储元素,然后压入栈2,栈2的元素即进入队列的顺序
    public void push(int node) {
        stack1.push(node);
    }

    public int pop() {//每次出队时,判断栈2是否空,空则将栈1元素出栈后压入栈2,然后弹出栈2的栈顶元素
        if(stack2.empty()){
            while(!stack1.empty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
}

2、根据栈1是否只剩1个元素将栈1除栈底外元素压入:

该思路相比上一步增加了复杂度,不推荐。

//判断栈1是否为空,空则从栈2弹出栈顶元素(考虑两栈都空的异常)
//栈1非空则判断栈1是否只有一个元素。是则pop,不是则将除栈底外元素全部push到栈2

7.旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。

例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

考虑数组旋转后分为左边的递增数组和右边的递增数组,通过三个指针去判断,左、中、右。

当中间的元素大于等于左边元素时,说明其在左边的递增数组,此时最小值在右边。左指针移到中间位置。

当中间的元素小于等于右边元素时,说明其在右边的递增数组,此时最小值在左边。右指针移到中间位置。

当左=中=右时无法判断,顺序查找。退出条件为左右指针相邻,此时右指针的元素为最小值。



1、暴力解:

//遍历,输出最小值
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array.length==0){//异常
            return 0;
        }
        int min=array[0];
        for(int i=0;i<array.length-1;i++){
            if(array[i]>array[i+1]){
                min=array[i+1];
                break;
            }
        }
        return min;
    }
}

2、二分查找:

public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array.length==0){//异常
            return 0;
        }
        int len=array.length;
        int left=0;//左指针
        int right=len-1;//右指针
        int mid=(left+right)/2;
        if(array[left]<array[right]){//若小于则证明该数组是升序
            return array[left];
        }
        //特殊情况,左、右、中三值相等,此时下面的方法无法判断。需要单独处理这种情况
        if(array[left]==array[mid] && array[right]==array[mid]){
            int min=array[0];
            for(int i=0;i<len-1;i++){
                if(array[i]>array[i+1]){
                    min=array[i+1];
                    break;
                }
            }
            return min;
        }

        while(right!=left+1){
            if(array[mid]<=array[right]){
                //说明在右边的递增数组,最小值在该元素前面
                right=mid;
                mid=(left+right)/2;
            }
            if(array[mid]>=array[left]){
                //说明在左边的递增数组,最小值在该元素后面
                left=mid;
                mid=(left+right)/2;
            }
        }
        return array[right];
    }
}

8.斐波那契数列

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项为1)。n<=39

了解斐波那契数列的特性 f(n)=f(n-1)+f(n-2){n>=2};



1、递归:

public class Solution {
    public int Fibonacci(int n) {
        //n<=39  此处f(n)=f(n-1)+f(n-2){n>=2};
        if(n==0){
            return 0;
        }else if(n==1){
            return 1;
        }else{
            return Fibonacci(n-1)+Fibonacci(n-2);
        }
    }
}

该暴力解法存在效率方面的缺点,会重复计算大部分值。

2、利用循环:

public class Solution {
    public int Fibonacci(int n) {
        //n<=39  此处f(n)=f(n-1)+f(n-2){n>=2};
        if(n==0){
            return 0;
        }else if(n==1){
            return 1;
        }else{
            int f1=0;
            int f2=1;
            int fn=0;
            //利用循环
            for(int i=2;i<=n;i++){
                fn=f1+f2;
                f1=f2;//向后移一位
                f2=fn;
            }
            return fn;
        }
    }
}

9. 跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

斐波那契数列的应用



1.递归:

public class Solution {
    public int JumpFloor(int target) {
        //斐波那契数列的应用
        if(target==1){
            return 1;
        }else if(target==2){
            return 2;
        }else{
            return JumpFloor(target-1)+JumpFloor(target-2);
        }
    }
}

2.循环:

public class Solution {
    public int JumpFloor(int target) {
        //斐波那契数列的应用
        if(target==1){
            return 1;
        }else if(target==2){
            return 2;
        }else{
            int f1=1;
            int f2=2;
            int fn=0;
            for(int i=3;i<=target;i++){
                fn=f1+f2;
                f1=f2;
                f2=fn;
            }
            return fn;
        }
    }
}

10.变态跳台阶 ??

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

关键是求出f(n)的公式。

假设n级台阶,每一次可以跳1、2、3……n阶;f(1)=1;f(2)=2

那么跳n级台阶的跳法f(n)=f(n-1)+f(n-2)+f(n-3)+……+f(n-n)

上述公式的解释:总跳法=第一次跳一级之后的跳法+第一次跳2级之后的跳法+……第一次跳n级的跳法=f(n-1)+f(n-2)+……+f(2)+f(1)+f(0);其中f(n-1)=f(n-2)+f(n-3)+……+f(1)+f(0);

所以f(n)=2*f(n-1)=2*2*f(n-2)=2^((n-1)*f(1)) =2^(n-1)


另一解释:每个台阶可以看作一块木板,让青蛙跳上去,n个台阶就有n块木板,最后一块木板是青蛙到达的位子, 必须存在,其他 (n-1) 块木板可以任意选择是否存在,则每个木板有存在和不存在两种选择,(n-1) 块木板 就有 [2^(n-1)] 种跳法,可以直接得到结果。



1.循环:

//同上题,该题仍有递归和循环两种解法
public class Solution {
    public int JumpFloorII(int target) {
        //1:1; 2:2 3:4; 4:8  2^(n-1)
        if(target==1 || target ==2){
            return target;
        }
        int res=2;
        for(int i=2;i<=target-1;i++){
            res=res*2;
        }
        return res;
    }
}

如有错误,欢迎指正

原文地址:https://www.cnblogs.com/lfz1211/p/12678705.html

时间: 2024-11-09 20:52:11

剑指Offer系列之题6~题10的相关文章

剑指Offer系列之题11~题15

目录 11.矩形覆盖 12.二进制中1的个数 13. 数值的整数次方 14.调整数组顺序使奇数位于偶数前面 15.链表中倒数第k个结点 11.矩形覆盖 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 比如n=3时,2*3的矩形块有3种覆盖方法: 斐波那契数列的应用 第一次竖着放一块类比为走一步,第一次横着放两块类比为走两步 代码与上面的斐波那契数列类题目类似,此处不再赘述:剑指Offer系列之题6~题10. 12.

剑指offer系列4:斐波那契数列

剑指offer第九题,这个题很古老了.第一个想到的肯定是递归,很简单. 1 #include<iostream> 2 #include<vector> 3 using namespace std; 4 class Solution { 5 public: 6 int Fibonacci(int n) { 7 if (n == 0) 8 { 9 return 0; 10 } 11 if (n==1||n==2) 12 { 13 return 1; 14 } 15 else 16 {

剑指offer系列10:合并两个排序的链表

我拿到这个题的时候举的例子是链表1:1.3.5.7和链表2:2.4.6.8.我的思路是以:1为基础,将表2的每个结点插入表1.也就是说我一次性是要给新建立的链表中加入两个元素,分别是两个原始链表的头结点.这个思路我做了半天头脑一片混乱,中间指针实在不知道怎么弄了.于是我去睡了一觉,哈哈,我大概是这个世界上最会逃避的人了…… 看了答案使用了递归的方法,其实我做的时候我有想到要用递归,但是没用的原因是我一般写代码不喜欢用递归,原因有两个,一个是递归容易死循环,一个是递归的复杂度太高.但这道题真的太适

剑指offer系列47:堆成的二叉树

这个题的主要思路是: 用二叉树的左子树的右子树和右子树的左子树比较,再用左子树的左子树和右子树的右子树比较.(好像有点绕,但其实就是堆成的思想) 剑指offer的说法是用数的前序遍历的两个方法,前序遍历应该是:根->左->右.但是我们用另一种前序遍历:根->右->左.如果这两个序列一样就判断它是对称的. 这两个方法在实现上其实是一样的. 1 class Solution { 2 public: 3 bool isSymmetrical(TreeNode* pRoot) 4 { 5

剑指offer系列——48.不用加减乘除做加法

Q:写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. T: 1.使用进制. 两个数异或:相当于每一位相加,而不考虑进位: 两个数相与,并左移一位:相当于求得进位: 将上述两步的结果相加 首先看十进制是如何做的: 5+7=12,三步走 第一步:相加各位的值,不算进位,得到2. 第二步:计算进位值,得到10. 如果这一步的进位值为0,那么第一步得到的值就是最终结果. 第三步:重复上述两步,只是相加的值变成上述两步的得到的结果2和10,得到12. 同样我们可以用三步走的方

剑指Offer系列之题21~题25

目录 21.包含min函数的栈 22.栈的压入.弹出序列 ?? 23.从上往下打印二叉树 24.二叉搜索树的后序遍历序列 ?? 25.二叉树中和为某一值的路径 ?? 21.包含min函数的栈 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). 注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法. 利用辅助栈,存储元素.当最小元素出栈后,次小元素仍在辅助栈中. 辅助栈: import java.util.Sta

剑指Offer系列之题16~题20

目录 16.反转链表 17.合并两个排序的链表 18.树的子结构 ?? 19.二叉树的镜像 20.顺时针打印矩阵 16.反转链表 输入一个链表,反转链表后,输出新链表的表头. 从前往后,依次将当前节点的next指向前结点.用多个变量存储当前节点,下一节点,前结点. public class Solution { public ListNode ReverseList(ListNode head) { if(head==null) return null; //从头开始,依次将节点的next指向前

《剑指offer》第六十题:n个骰子的点数

// 面试题60:n个骰子的点数 // 题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s.输入n,打印出s // 的所有可能的值出现的概率. #include <cstdio> #include <math.h> int g_maxValue = 6; // ====================方法一==================== void Probability(int current, int sum, int* pProbabilities); void

剑指Offer之赋值运算符重载(题1)

1 #include<stdio.h>                                                                                                                            2 #include<assert.h>   3    4 class MyString   5 {   6 public:   7     MyString()   8     {   9