剑指offer--斐波那契数列,跳台阶,变态跳台阶,二维数组中的查找,替换空格,用两个栈实现队列,旋转数组的最小数字,调整数组顺序使奇数位于偶数前面,从尾到头打印链表,包含min函数的栈

1.菲波那契题目描述

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

分析

首先是使用递归的方法,但是使用这种方法会使编译器超时
另一种就是使用循环的方法,每次获取前一次的两个值,进行循环

循环代码

# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        if n==0:
            return 0
        if n==1:
            return 1
        a=0
        b=1
        for i in range(1,n):
            c=a+b 
            a=b 
            b=c 
        return c 

2.跳台阶 题目描述

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

分析

由于一只青蛙最后跳的台阶数不是一阶就是二阶,所以可以看为青蛙是从n往回跳,也就是当青蛙从n开始跳时,只能跳到n-1或n-2,也就是说此时n的跳法就是由f(n-1)+f(n-2)决定的。此时所计算的是跳台阶的方法,所以直接将n-1和n-2加起来就行,n=1时一种方法,n=2时有两种方法,代码如同斐波那契数列类似,都是使用了循环的方法,递归的方法可能存在超时。

代码

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloor(self, number):
        if number==1:
            return 1
        if number==2:
            return 2
        a=1
        b=2
        for i in range(2,number):
            c=a+b 
            a=b 
            b=c 
        return c 

变态跳台阶 题目描述

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

分析

对于跳台阶问题,首先分析其规律
f(n) = f(n-1)+f(n-2)+ …+f(1)
f(n-1) = f(n-2) + f(n-3)+ … f(1)
所以 f(n) = 2f(n-1)
如上所示,可以将台阶数量逐级乘以2
比较方便的直接输出 2
n-1

代码

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # f(n) = f(n-1)+f(n-2)+ ...+f(1)
        # f(n-1) = f(n-2) + f(n-3)+ ... f(1)
        #所以 f(n) = 2*f(n-1)
        if number == 1:
            return 1
        ans = 1
        a = 1
        for i in range(2, number+1):
            ans = 2*a 
            a = ans
        return ans

了解数组、栈、队列的概念

二维数组中的查找

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

分析

首先,可以使用双重循环的方式,首先这种方式比较消耗内存,并且也没有使用行列递增这一个条件。
所以使用另一种方式
首先利用题中所给的条件,假设例子:
1,2,3,4
5,6,7,8
9,10,11,12
可以看到每一个右上拐角的数字都是本行最大的以及本列之下最小的,是从左往右以及从上往下看。所以只需要与右上角的数字进行对比,那么就可以确定当前数字是在要由这一行往下,或者这一列往左进行判断:

代码

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        '''
        #暴力循环
        for i in range(len(array)):
            for j in range(len(array[0])):
                if target == array[i][j]:
                    return True
        return False
        '''
        # 使用题目规则进行循环判断
        row_count = len(array)
        colmun_count = len(array[0])
        i = 0
        j = colmun_count - 1
        while i < row_count and j >= 0:
            value = array[i][j]
            #分为三种情况,一种为数据匹配,一种为比当前值小,那么这一列往左,另一种是比当前值大,那么当前行向下。
            if value == target:
                return True
            elif value > target:
                j -= 1
            else:
                i += 1
        return False

替换空格

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

分析

对数组进行操作,创建连个数组即可

代码

# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        b = []
        for i in s:
            if i == ' ':
                b.append("%20")
                #b.append("2")
                #b.append("0")
            else:
                b.append(i)
        return ''.join(b)
        

用两个栈实现队列

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

分析

对于两个栈合并实现队列,首先了解栈和队列的特性。
在本题中,首先需要创建两个栈,其中一个栈用来实现入队,用另一个栈来实现出队。
当将数据压入第一个输入栈后,此时要将栈底元素输出,直接将这个栈中所有元素压入另一个栈中,然后将最顶元素出栈即可。
如果此时输出栈中存在元素,那么直接将栈顶元素出栈即可,直接就是按照队列顺序输出的。
如果此时输出栈中没有数据,那么需要将输入栈中数据全部压入输出栈中,这样可以继续对存有数据的输出栈进行操作。
如果两个栈都不存在数据,那么输出为None。

# -*- coding:utf-8 -*-
class Solution:
    # 初始化两个栈
    def __init__(self):
        self.outputstack = []
        self.acceptstack = []
    # 将数据压入栈中,类似于进入队列
    def push(self, node):
        self.acceptstack.append(node)
        # write code here
    #将数据pop出栈中,类似于出队
    def pop(self):
        #判断当输出栈为空时,将输入栈中的数据依次添加到输出栈中
        if self.outputstack == []:
            while self.acceptstack != []:
                self.outputstack.append(self.acceptstack.pop())
        #当输出栈不为空时,直接将栈最顶上的数据出栈
        if self.outputstack != []:
            return self.outputstack.pop()
        #如果两个栈中都没有数据,那么输出为none
        else:
            return None
        # return xx

旋转数组的最小数字 题目描述

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

分析

首先对题目进行分析,需要获取经过旋转的数组的最小值,要寻找最小值,可以使用遍历的方式,但是这种方法是O(n)的复杂度,并且忽略了题中所提到的有序数组这一条件。
根据提示,使用的是二分查找的方法。
使用二分查找需要数组为有序数组,本题中的旋转数组将有序数组进行了重新排序,将有序数组分为了两个部分,所以需要对二分查找重新进行判断,需要十分了解二分查找。
如果所选取的mid比mid的前一个数值小,那么表示当前mid为最小值
如果mid是比最右边的值小,那么最小值在mid左边
如果mid是比最左边的小,那么最小值正在右边

代码

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        '''return min(rotateArray)'''
        #需要使用二分查找的方法
        if not rotateArray:
            return None
        # 使用二分查找需要数组为有序数组,本题中的旋转数组将有序数组进行了重新排序,
        #将有序数组分为了两个部分,所以需要对二分查找重新进行判断,需要十分了解二分查找
        left = 0
        right = len(rotateArray)-1
        while left <= right:
            #将mid进行表示
            mid = (left+right)>>1
            #如果所选取的mid比mid的前一个数值小,那么表示当前mid为最小值
            if rotateArray[mid] < rotateArray[mid-1]:
                return rotateArray[mid]
            # 如果mid是比最右边的值小,那么最小值在mid左边
            elif rotateArray[mid] < rotateArray[right]:
                right = mid-1
            #如果mid是比最左边的小,那么最小值正在右边
            else:
                left = mid+1
        return None

调整数组顺序使奇数位于偶数前面 题目描述

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

分析

第一种方法:
使用外加一个数组的方法,遍历原数组,先判断奇数,将奇数添加到数组中,进行第二次遍历,将偶数添加到数组中,就可,本方法使用python写出
第二种方法:
如果不能使用第二个数组,那么我们需要使用的是冒泡排序的思想。
使用冒泡排序的方法,对数组进行双重循环,判断是否当前数为偶数,并且下一个数为奇数,如果是则交换,通过这样的交换,将偶数往后交换,经过两重交换就可以实现前面为奇数,后面为偶数,这一种方法使用的是c++代码。

代码

第一种方法

# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        # 使用外加一个数组的方法
        ret = []
        for i in array:
            if i%2 == 1:
                ret.append(i)
        for i in array:
            if i % 2 == 0:
                ret.append(i)
        return ret 

第二种方法:

class Solution {
public:
    void reOrderArray(vector<int> &array) {
        //获取数组size信息
        int loop = array.size();
        int flag = false;
        //进行双重循环
        for (int i = 0; i < loop ;i++)
        {
            for(int j = 0;j < loop ; j++)
            {
            //判断数据为偶数接奇数
                if (array[j] % 2 == 0 && array[j+1] % 2 == 1 )
                {
                    swap(array, j ,j+1);
                    flag = true;
                }
            }
        }
        if(flag == true)
        {
            return ;
        }
    }
    //交换函数
    void swap(vector<int> &array, int i , int j)
    {
        auto temp = array[i];
        array[i] = array[j];
        array[j]=temp;
    }
};

从尾到头打印链表 题目描述

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

分析

主要方法为使用一个栈来存储链表从头到尾的数据,之后将栈依次输出。

代码

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        // 创建一个vector容器,用来动态的存储从尾到头的数据,实际上相当于数组
        vector<int> ans;
        //创建一个栈,用来存储从链表中获取到的数据
        stack<int> s;
        //进行循环,将链表中val依次获取并压入栈中
        while(head){
            s.push(head->val);
            head = head->next;
        }
        int num;
        // 判断当栈空时停止,将栈顶元素取出并存入ans之中,使用push_back()方法
        while(!s.empty()){
            num = s.top();
            ans.push_back(num);
            s.pop();
        }
        return ans;
    }
};

包含min函数的栈 题目描述

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

分析

主要要求在与时间复杂度的要求为O1,所以要增加空间来达到其时间复杂度的要求。

代码

# -*- coding:utf-8 -*-
class Solution:
    # 创建栈已经最小值的一个栈
    def __init__(self):
        self.stack = []
        self.minvalue = []
    # 在push操作中,对于最小值的栈,首先判断顶部是否有值,如果有值,那么与当前节点进行比较,
    #如果比当前节点大,那么就将node存入栈中,否则就将顶部数据重复导入顶部数据,这是为了保证两个栈中数据一致
    def push(self, node):
        self.stack.append(node)
        if self.minvalue :
            if self.minvalue[-1] > node:
                self.minvalue.append(node)
            else:
                self.minvalue.append(self.minvalue[-1])
        else:
            self.minvalue.append(node)
        # write code here
    # 在 pop操作中,要相应的进行对min栈的pop操作,保证栈中数据的一致
    def pop(self):
        if self.stack ==[]:
            return None
        self.minvalue.pop()
        return self.stack.pop()
        
        # write code here
    def top(self):
        if self.stack ==[]:
            return None
        return self.stack[-1]
        # write code here
    # 经过两个栈保持一致的栈的操作,可以保证复杂度为O(1),值需要调用此方法就可以返回数据
    def min(self):
        if self.minvalue == []:
            return None
        return self.minvalue[-1]
        # write code here
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值