zoukankan      html  css  js  c++  java
  • 《剑指Offer》第二章(一)题 9 -12

    第二章

    面试题9:用两个栈实现队列

    题目:如面试题,给你两个栈, 实现队列的先进先出,即在队列头删除一个元素以及在队列的尾部添加一个元素

    思路:这个题的分析感觉很巧妙,从一个具体的例子入手,找出其中的规律,进而得到一种解决方法。解决方法几句话就能说完,但是这种思维很重要,放个图留着自己以后体会吧。

    图好大。。

    代码如下:

    stack1 = []
    stack2 = []
    # 尾部添加一个节点
    def appendTail(val):
        stack1.append(val)
    
    # 头部删除一个元素
    def deleteHead():
        if stack2.__len__() == 0 and stack1.__len__() == 0:
            return "error"
        if stack2.__len__() == 0:
            while stack1.__len__() != 0:
                stack2.append(stack1.pop())
        return stack2.pop()
    

    测试代码:

    appendTail(1)
    appendTail(2)
    appendTail(3)
    print(deleteHead())
    print(deleteHead())

    代码用Python写还是比较简洁的,java要多写挺多的,python牛逼

    类似题目:两个队列实现一个栈。

    自己画一下就知道了,加的时候往有元素的队列加,当然一开始直接往1队列加。出的时候,把有元素的队列其中的n-1个元素都取出来,放到另一个队列之中,剩下最后一个元素,即为目标元素,其它同理。

    面试题10:斐波那切数列

    做过很多次了。记住一点,对于这类问题,先假设n很小的时候,求出n==1,2....或者其它一般情况之下的值,然后规模为的问题进行分解,想办法分解为n-1和规模的问题,最终就可以缩小成1,2.....的问题,进而求解出N问题。难点还是在分解问题上,看自己能不能想到。

    非递归的写法:

    def solution(n):
        result = [0,1]
        if n < 2:
            return result[n]
        x = 1
        y = 0
        target = None
        for i in range(1,n):
            target = x + y
            y = x
            x = target
        return target
    

    代码不多说了,一看就会。

     面试题11:求旋转数组之中的最小值

    题目:旋转数组是指将一个有序的数组前面的x个数移动到最后面,类似于,原数组【1,2,3,4,5】,旋转过后的数组:【3,4,5,1,2】,当然这个x也可以是0,就是不移动,但是它本身也是一个旋转数组。如题,求该数组之中的最小值。

    思路分析:首先能想到的肯定是O(N)的方法,遍历数组然后找出最小值,但是这肯定是不行的,需要找到一个O(logn)复杂度的方法,一般来讲,这种查找数字的,而且是部分有序,都可以用二分查找的思想进行。可以看到了这个旋转数组,它仍然可以划分为两个有序的子数组,一个是【3,4,5】,一个是【1,2】,前面数组的值都大于等于后面数组之中的值, 我们需要找的数字是1,二分查找,自然是需要两个边界指针,和一个中间指针,比较中间和两边的值,进而一步步缩小目标值的范围,从而达到O(logn)复杂度的查找方法。对于【3,4,5,1,2】,设有指针left,right,middle,初始时,分别指向3,2,5,比较5>3,说明left到middle之间的数字,都是处于第一个数组之中的,所以最小值肯定是在midlle~right之间,同理,如果旋转数组为【4,5,1,2,3】,1<3,说明midlle~right之间都是后面那个子数组的元素,所以最小值肯定是位于middle~left之间的,之后的都同理。总体上说,就是通过比较middle和两边的值,不断缩小最小值的区间,当最小值区间大小为2时,nums[right]的值就是最小值。

    但是需要注意两个特殊情况:

    一,就是刚开始说得,旋转了0个或者n个数字的情况,此时第一个数字就是最小数字,没有必要再进行查找了,所以,如果第一个数小于最后一个数字,说明旋转了n个或者0个数字,直接返回第一个数字就可以了。

    二,如果midlle,left,right这三个数字都相等的话,那么就无法继续缩小区间,比如这个数组【0,1,1,1,1】,旋转之后可以是【1,0,1,1,1】,【1,1,1,0,1】,可以看到,按照之前的规则是有可能得出错误的结果的,所以如果这种情况,那么就只能采用顺序查找的方法了。

    个人认为这题需要考虑的很多,现阶段我肯定是考虑不到这么周全的,继续加油。

    代码如下:

    def min(nums):
        if len(nums) == 0 or nums == None:
            return False
        left = 0
        right = len(nums)-1
        # 旋转了0或者n
        if nums[left] < nums[right]:
            return nums[0]
        # 正常旋转
        while nums[left] >= nums[right]:
            # 查找到了最小值
            if right - left == 1:
                return nums[right]
            middle = int((right+left)/2)
    
            if nums[middle] == nums[left] == nums[right]:
                # 顺序查找
                return orderSearch(nums, left, end)
            # 正常缩小区间
            if nums[middle] >= nums[left]:
                left = middle
            elif nums[middle] <= nums[right]:
                right = middle
    
    # 顺序查找
    def orderSearch(nums, start, end):
        result = nums[start]
        for i in range(start, end+1):
            if nums[i] < result:
                result = nums[i]
        return result
    

    面试题12:矩阵之中的路径

    题目:给定一个字符矩阵以及一个字符串,寻找在该字符矩阵之中是否有一条路径,连起来的顺序刚好是给定的字符串,只能上下左右相连,不能斜着相连,并且一个字符格走过之后就不能再走这个了,相当于不能重复走过同一个矩阵之中的格子。

    思路:这个问题相当于从一个点开始,下一步可以有好几种走法,每次判断一下是否达到了目标,以及能够达到目标,达到目标了直接结束,没有达到的话说明当前步骤行不通,回溯到上一步,尝试其他路径是否可行。这种问题一般都是用回溯法来解决。

    具体到这个问题:以矩阵之中任何一个字符格为起点进行考察,判断当前字符是否等于字符串第一个字符,等于了进行下步,以该字符的上下左右四个字符作为下一个考察点(有的话),看看是否等于字符串的第二个字符,等于的话,重复上一次的步骤,不等于则停止以当前字符为基准的判断,回溯到上一个格子,尝试其它可行的路径,以此类推。

    思路还是比较容易理解的,代码虽然很长,但是其中的思路很明了。

    代码如下:

    def hasPath(matrix, rows, cols, word):
        if matrix == None or rows < 1 or cols <1 or word == None:
            return False
        visited = []
        for i in range(rows):
            visited.append([])
            for j in range(cols):
                visited[i].append(False)
        pathLength = 0
        for i in range(rows):
            for j in range(cols):
                # 以每一个矩阵格子为起点进行考察
                if hasPathCore(matrix, rows, cols, i, j, word, pathLength, visited):
                    return True
        return False
    
    
    def hasPathCore(matrix, rows, cols, row, col, word, pathLength, visited):
        # 判断是否到了字符串结尾
        if word[pathLength] == '#':
            return True
        hasPath = False
        # 判断当前字符是否在矩阵之中并且需要等于第pathLength个字符
        # 而且不能已经访问过了
        if row < rows and row >= 0 and col < cols and col >= 0 and 
                word[pathLength] == matrix[row][col] and visited[row][col] == False:
            # 进行下一个字符的查找
            pathLength += 1
            visited[row][col] = True
            # 对上下左右四条路径进行查找
            hasPath = hasPathCore(matrix, rows, cols, row+1, col, word, pathLength, visited) or 
                      hasPathCore(matrix, rows, cols, row-1, col, word, pathLength, visited) or 
                      hasPathCore(matrix, rows, cols, row, col+1, word, pathLength, visited) or 
                      hasPathCore(matrix, rows, cols, row, col-1, word, pathLength, visited)
            if hasPath:   # 没有找到,回溯到上一个字符
                visited[row][col] = False
                pathLength -= 1
        return hasPath
    

     测试代码如下:

    nums = [
        ['a', 'b', 't', 'g'],
        ['c', 'f', 'c', 's'],
        ['j', 'd', 'e', 'h'],
    ]
    
    print(hasPath(nums, 3, 4, 'cehsg#'))
    
  • 相关阅读:
    spring3.0使用annotation完全代替XML(续)
    spring3.0使用annotation完全代替XML
    Hibernate Session中的save(),update(),delete(),saveOrUpdate() 细粒度分析
    SpringMVC介绍之Validation
    Mysql 5.7 使用SSL安全连接
    深入分析Java ClassLoader原理
    Hibernate 动态分页查询
    【翻译自mos文章】Linux的/var/log/messages是空的(0k),messages.0, messages.1也是空的
    <html>
    Android Notification和权限机制探讨
  • 原文地址:https://www.cnblogs.com/eenio/p/12317324.html
Copyright © 2011-2022 走看看