牛客网《剑指Offer》66题 题解

牛客网《剑指Offer》66题 题解

pdf下载链接: 链接: https://pan.baidu.com/s/1hsXSGN6 密码: xavv
  1. 字符串的排列

    输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

    输入描述:

    输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

    dfs, 但是牛客网有些尴尬,list的顺序还得保障,所以结果得sort一下。为了防止重复,用了set。

    class Solution:
        def Permutation(self, ss):
            if not ss: return []
            res = set()
    
            def dfs(res, ss, s):
                if not ss: res.add(s)
                for i in range(len(ss)):
                    s = s + ss[i]
                    dfs(res, ss[:i] + ss[i + 1:], s)
                    s = s[:-1]
    
            dfs(res, ss, '')
            return sorted(list(res))

    当然,这只是简单得写法。高级得用swap实现,详情见STL中得permutation经典算法。

  2. 链表中倒数第k个结点

    输入一个链表,输出该链表中倒数第k个结点。

    先求链表长度n,然后输出第n-k节点。注意k>n的情况。

    
    # -*- coding:utf-8 -*-
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
        def FindKthToTail(self, head, k):
            # write code here
            n = 0
            p = head
            while p:
                n += 1
                p = p.next
            if k > n: return None
            t = n - k
            p = head
            for _ in range(t):
                p = p.next
            return p
  1. 跳台阶

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

    ,斐波那契数列的变体。

    
    class Solution:
        def jumpFloor(self, number):
            # write code here
            a, b = 1, 1
            for i in range(number):
                a, b = b, a + b
            return a 
  1. 变态跳台阶

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

    数学推导:

    ,因而有

    
    class Solution:
        def jumpFloorII(self, number):
            # write code here
            return 2 ** (number-1)

  2. 不用加减乘除做加法

    写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

    也就是用二进制的加法,二进制位相加用异或,进位用与并左移一位。

    
    class Solution {
    public:
        int Add(int num1, int num2)
        {
            int tmp;
            while(num2 != 0){
                tmp = num1 ^ num2;
                num2 = (num1 & num2) << 1;
                num1 = tmp;
            }
            return num1;
        }
    };

    上述的实现有些技巧,主要利用c++整数逸出会变0解决的情况,而python则没有逸出的概念,所以我们要与上0xffffffff。

    
    class Solution(object):
        def getSum(self, a, b):
            """
            :type a: int
            :type b: int
            :rtype: int
            """
            # 32 bits integer max
            MAX = 0x7FFFFFFF
            # 32 bits interger min
            MIN = 0x80000000
            # mask to get last 32 bits
            mask = 0xFFFFFFFF
            while b != 0:
                # ^ get different bits and & gets double 1s, << moves carry
                a, b = (a ^ b) & mask, ((a & b) << 1) & mask
            # if a is negative, get a's 32 bits complement positive first
            # then get 32-bit positive's Python complement negative
            return a if a <= MAX else ~(a ^ mask)

  3. 替换空格

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

    
    class Solution:
        # s 源字符串
        def replaceSpace(self, s):
            # write code here
            import re
            s = re.sub(' ', '%20', s)
            return s

  4. 顺序针打印矩阵

    输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

    
    class Solution:
        # matrix类型为二维列表,需要返回列表
        def printMatrix(self, matrix):
            # write code here
            return matrix and list(matrix.pop(0)) + self.printMatrix(list(zip(*matrix))[::-1])

  5. 二维数组中的查找

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

    类似二叉搜索树,从右上角开始依次左、下遍历,或者从左下角开始依次上、右遍历。

    
    class Solution:
        # array 二维列表
        def Find(self, target, array):
            # write code here
            m, n = len(array), len(array[0])
            i, j = 0, n - 1
            while i < m and j >= 0:
                if array[i][j] == target: return True
                elif array[i][j] < target: i += 1
                else: j -= 1
            return False

  6. 包含min函数的栈

    定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。

    同时维护一个最小栈。

    
    class Solution:
        def __init__(self):
            self.stack = []
            self.minstack = []
            
        def push(self, node):
            # write code here
            self.stack.append(node)
            if not self.minstack:
                self.minstack.append(node)
            elif node < self.minstack[-1]:
                self.minstack.append(node)
            else:
                self.minstack.append(self.minstack[-1])
        
        def pop(self):
            # write code here
            self.stack.pop()
            self.minstack.pop()
            
        def top(self):
            # write code here
            return self.stack[-1]
        
        def min(self):
            # write code here
            return self.minstack[-1]

  7. 重建二叉树

    输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

    
    class Solution:
        def reConstructBinaryTree(self, preorder, inorder):
            """
            :type preorder: List[int]
            :type inorder: List[int]
            :rtype: TreeNode
            """
            if inorder:
                id = inorder.index(preorder.pop(0))
                root = TreeNode(inorder[id])
                root.left = self.reConstructBinaryTree(preorder, inorder[:id])
                root.right = self.reConstructBinaryTree(preorder, inorder[id+1:])
                return root

  8. 用两个栈实现队列

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

    一个in栈,一个out栈,in栈用于直接push,out栈用于逆向pop in 栈中的元素。

    
    class Solution:
        def __init__(self):
            self.instack = []
            self.outstack = []
    
        def push(self, node):
            self.instack.append(node)
    
        def pop(self):
            if not self.outstack:
                while self.instack:
                    self.outstack.append(self.instack.pop())
            return self.outstack.pop()

  9. 旋转数组的最小数字

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

    二分查找的变体,采用左闭右开的写法,维持l是最小值。

    
    class Solution:
        def minNumberInRotateArray(self, rotateArray):
            if not rotateArray: return 0
            l, h = 0, len(rotateArray) - 1
            while l < h:
                m = (l + h) // 2
                if rotateArray[m] > rotateArray[h]:
                    l = m + 1
                else:
                    h = m
            return rotateArray[l]

  10. 斐波那契数列

    大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。

    n<=39

    用a, b 两个变量记录前后两个斐波那契数,c记录第几个。(注意n=0, 0)

    
    class Solution:
        def Fibonacci(self, n):
            a, b = 0, 1
            c = 0
            while c < n:
                b, a, c = a, a + b, c + 1
            return a

  11. 矩阵覆盖

    我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

    还是斐波那契的变体形式,不想写递推了,直接递归实现。不过python会超时,所以改用java拉。

    
    public class Solution {
        public int RectCover(int target) {
            if(target==0)
                return 0;
            else if(target==1)
                return 1;
            else if(target==2)
                return 2;
            else
                return RectCover(target-1)+RectCover(target-2);
        }
    }

  1. 二进制中1的个数

    输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

    先求出二进制,然后不同向右移位,统计最低位为1的数量。

    
    class Solution:
        def NumberOf1(self, n):
            return sum([(n >> i & 1) for i in range(0, 32)])

  2. 数值的整数次方

    给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

    
    class Solution:
        def Power(self, base, exponent):
            return base ** exponent

    当然有高深的解法,也就是==>快速幂.(https://www.cnblogs.com/CXCXCXC/p/4641812.html)

    
    class Solution:
        def Power(self, base, exponent):
            ans = 1
            while exponent:
                if exponent & 1: ans *= base
                base *= base
                exponent >>= 1
            return ans

    这种再牛客网上提交会超时,毕竟python,时间限制的严。但是这确实是O(log n)的解法。

    主要思想是分解exponent,如base=a, exponent=11,,也就是说

    也就是不停判断exponent的最低一位,a则不停翻倍,实现a=>a2=>a3 ,如果b的最低位是1就乘上去呗。

  1. 调整数组顺序使奇数位于偶数前面

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

    类似冒泡算法,前偶后奇数就交换:

    
    class Solution:
        def reOrderArray(self, array):
            n = len(array)
            for i in range(n):
                for j in range(n-1, i, -1):
                    if array[j] & 1 and not array[j - 1] & 1:
                        array[j], array[j-1] = array[j-1], array[j]

    当然最简单的还是耗空间的解法,遍历楼。

  2. 反转链表

    输入一个链表,反转链表后,输出链表的所有元素。

    链表经典题型拉。三个指针拉,pre, cur, pos。cur.next = pre是关键。

    
    class Solution:
        # 返回ListNode
        def ReverseList(self, pHead):
            pre = None
            while pHead:
                pos = pHead.next
                pHead.next = pre
                pre 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部