剑指offer刷题记录

 ̄綄美尐妖づ 提交于 2020-04-02 14:00:33

记录了剑指offer的刷题过程,一共67道题,题目来源牛客网-剑指offer

1.数组--二维数组中的查找

题目:

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

思路:

左上角为最小值,右下角为最大值,进行二维二分查找

# python
class Solution:
    def Find(self, target, array):
        w = len(array)
        for i in range(w):
            if target in array[i]:
                return True
/*
* C++
* 参考 https://www.nowcoder.com/profile/9734827/codeBookDetail?submissionId=12713594
* 矩阵是有序的,从左下角来看,向上数字递减,向右数字递增,
* 因此从左下角开始查找,当要查找数字比左下角数字大时。右移
* 要查找数字比左下角数字小时,上移
*/
class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int rowCount = array.size();
        int colCount = array[0].size();
        int i, j;
        for (i=rowCount-1, j=0; i>=0&&j<colCount;){
            if (array[i][j] == target)
                return true;
            if ( target > array[i][j]){
                j += 1;
                continue;
            }
            if (target < array[i][j]){
                i -= 1;
            }
        }
        return false;
    }
};

2.字符串--替换空格

题目:

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

class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        s = list(s)
        for i in range(len(s)):
            if s[i] == ' ':
                s[i] = '%20'
        return ''.join(s)
class Solution {
public:
	void replaceSpace(char *str,int length) {
        int count = 0;
        int i, j;
        for (i=0; i<length; i++){
            if (str[i] == ' ') 
                count ++;
        }
        for (j=length-1; j>=0; j--){
            if (str[j] != ' '){
                str[j+2*count] = str[j];
            }
            else{
                count --;
                str[j+2*count] = '%';
                str[j+2*count+1] = '2';
                str[j+2*count+2] = '0';
            }
        }
	}
};

3.链表--从尾到头打印链表

题目:

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

思路:
从头到尾遍历并保存到数组中,再倒序输出

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        value = []
        while listNode:
            value.append(listNode.val)
            listNode = listNode.next
        return value[::-1]

4.树--重建二叉树

题目:

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

思路:

前序遍历第一个数必定为根节点,以此将中序遍历分为左右两个分支。以此思路递归重构二叉树

# -*- coding:utf-8 -*-
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
        
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        pre, tin = list(pre), list(tin)
        if len(pre) != len(tin):
            raise Exception('input error!')
        elif len(pre) == 0 and len(tin) == 0:
            return None
        elif len(pre) == 1 and len(tin) == 1:
            return TreeNode(pre[0])

        index = tin.index(pre[0])
        head = TreeNode(pre[0])
        head.left = self.reConstructBinaryTree(pre[1:index+1], tin[:index])
        head.right = self.reConstructBinaryTree(pre[index+1:], tin[index+1:])
        return head

5.栈和队列--用两个栈实现队列

题目:

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

class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self, node):
        self.stack2.append(node)
        # write code here
    def pop(self):
        if self.stack1 == []:
            while self.stack2:
                self.stack1.append(self.stack2.pop())
            return self.stack1.pop()
        return self.stack1.pop()

6.查找和排序--旋转数组的最小数字

题目:

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

class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if not rotateArray:
            return 0
        min = rotateArray.pop()
        for tem in rotateArray:
            if tem < min:
                return tem
        return min

7.递归和循环--斐波那契数列

题目:

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

class Solution:
    def Fibonacci(self, n):
        fib = [0,1]
        if n <=1:
            return fib[n]
        else:
            for i in range(n-1):
                fib.append(fib[-1]+fib[-2])
            return fib[-1]

8.递归和循环--跳台阶

题目:

一只青蛙一次可以跳上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

9.递归和循环--变态跳台阶

题目:

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

class Solution:
    def jumpFloorII(self, number):
        # write code here
        num = [1,1,2]
        for i in range(number-2):
            num.append(sum(num))
        return num[number]

10.递归和循环--矩形覆盖

题目:

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

class Solution:
    def rectCover(self, number):
        if number == 0:
            return 0
        a, b = 1, 1
        for i in range(number):
            a, b = b, a+b
        return a

11.位运算--二进制中1的个数

题目:

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

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

12.代码的完整性--数值的整数次方

题目:

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0

class Solution:
    def Power(self, base, exponent):
        # write code here
        flag = 0
        if base == 0:
            return False
        if exponent == 0:
            return 1
        if exponent < 0:
            flag = 1
        result = 1
        for i in range(abs(exponent)):
            result *= base
        if flag == 1:
            result = 1 / result
        return result

13.完整性--调整数组顺序使奇数位于偶数前面

题目:

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

思路:不分配新的内存的情况下,查找遇到偶数后面接奇数的组合就进行位置交换,类似冒泡法。下面答案为分配新内存的方式。

class Solution:
    def reOrderArray(self, array):
        # write code here
        odd, even = [], []
        for num in array:
            if num%2 == 0:
                even.append(num)
            else:
                odd.append(num)
        return odd + even

14.代码的鲁棒性--链表中倒数第K个节点

题目:

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

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        NodeArray = [head]
        if not head or k==0:
            return None
        while head.next:
            head = head.next
            NodeArray.append(head)
        if k > len(NodeArray):
            return None
        return NodeArray[-k]

15.代码的鲁棒性--反转链表

题目:

输入一个链表,反转链表后,输出新链表的表头

class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if not pHead or not pHead.next:
            return pHead
        # 记录相邻两个节点,以便后面进行换序
        first, second = pHead, pHead.next
        tem = second # 临时存储节点信息
        while tem:
            tem = second.next
            # 节点交换顺序
            second.next = first
            first, second = second, tem
        pHead.next = None
        return first

16.代码的鲁棒性--合并两个排序的链表

题目:

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if pHead1 is None:
            return pHead2
        elif pHead2 is None:
            return pHead1
        if pHead1.val > pHead2.val:
            newHead = pHead2
            pHead2 = pHead2.next
        else:
            newHead = pHead1
            pHead1 = pHead1.next
        ptem = newHead
        while pHead1 and pHead2:
            if pHead1.val > pHead2.val:
                ptem.next = pHead2
                ptem = ptem.next
                pHead2 = pHead2.next
            else:
                ptem.next = pHead1
                ptem = ptem.next
                pHead1 = pHead1.next
        if pHead1 is None:
            ptem.next = pHead2
        else:
            ptem.next = pHead1
        return newHead

17.代码的鲁棒性--树的子结构

题目:

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路: 二叉树子结构的判定

class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        if not pRoot1 or not pRoot2:
            return False
        return self.isSubtree(pRoot1, pRoot2) or self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)
    def isSubtree(self, pRoot1, pRoot2):
        if not pRoot2:
            return True
        if not pRoot1 or pRoot1.val!=pRoot2.val:
            return False
        if pRoot2.val == pRoot1.val:
            return self.isSubtree(pRoot1.left, pRoot2.left) and self.isSubtree(pRoot1.right, pRoot2.right)

18.面试思路--二叉树的镜像

题目:

操作给定的二叉树,将其变换为源二叉树的镜像。

class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        # write code here
        if not root:
            return root
        root.left, root.right = self.Mirror(root.right), self.Mirror(root.left)
        return root

19.画图让抽象形象化--顺时针打印矩阵

20.举例让抽象具体化--包含min函数的栈

21.举例让抽象具体化--栈的压入,弹出序列

题目:

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

思路:压入与弹出可以交叉进行,先压入一部分,再弹出一部分,只要压入弹出顺序满足即可。

class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        if not pushV:
            return False
        tem = []
        for v in pushV:
            tem.append(v)
            while len(tem) and tem[-1]==popV[0]:
                tem.pop()
                popV.pop(0)
        if tem:
            return False
        return True

22.举例让抽象具体化--从上往下打印二叉树

题目:

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

思路:借助队列实现

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        # write code here
        if not root:
            return []
        res = []
        queue = [root]
        while queue:
            node = queue.pop(0)
            res.append(node.val)
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        return res

23.举例让抽象具体化--二叉搜索树的后序遍历序列

题目:

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

思路:二叉排序树-左子树指均小于跟节点,又子树值均大于根节点,所有子树亦如此。

class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if not sequence:
            return False
        if len(sequence) <= 2:
            return True
        head = sequence.pop()
        if max(sequence) < head or head < min(sequence):
            return self.VerifySquenceOfBST(sequence)
        for i in range(1,len(sequence)):
            if max(sequence[:i]) < head < min(sequence[i:]):
                return self.VerifySquenceOfBST(sequence[:i]) and self.VerifySquenceOfBST(sequence[i:])
        return False
``

### 24.举例让抽象具体化--二叉树中和为某一值的路径
题目:
> 输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

```python
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def FindPath(self, root, expectNumber):
        # write code here
        if not root:
            return []
        if root and not root.left and not root.right and root.val==expectNumber:
            return [[root.val]]
        res = []
        left = self.FindPath(root.left, expectNumber-root.val)
        right = self.FindPath(root.right, expectNumber-root.val)
        for l in left + right:
            res.append([root.val]+l)
        return res

25.分解让复杂问题简单--复杂链表的复制

题目:

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

def iter_node(root):
    while root:
        yield root
        root=root.next

class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        mem=dict()
        for i,n in enumerate(iter_node(pHead)):
            mem[id(n)]=i
        lst=[RandomListNode(n.label) for n in iter_node(pHead)]
        for t,f in zip(iter_node(pHead),lst):
            if t.next:
                f.next=lst[mem[id(t.next)]]
            if t.random:
                f.random=lst[mem[id(t.random)]]
        return lst[0] if lst else None

26.分解让复杂问题简单--二叉搜索树与双向链表

/*
struct TreeNode {
    int val;
    strcut TreeNode *left;
    strcut TreeNode *right;
    TreeNode(int x): val(x), left(NULL), right(NULL){}
}
*/
class Solution{
public:
    TreeNode
}

27.分解让复杂问题简单--字符串的排列

28.时间效率--数组中出现次数超过一半的数字

29.时间效率--最小的K个数

30.时间效率--连续子数组的最大和

31.时间效率--整数中1出现的次数

32.时间效率--把数组排成最小的数

33.时间空间效率的平衡--丑数

34.时间空间效率的平衡--第一个只出现一次的字符位置

35.时间空间效率的平衡--数组中的逆序对

36.时间空间效率的平衡--两个链表的第一个公共结点

37.知识迁移能力--数字在排序数组中出现的次数

38.知识迁移能力--二叉树的深度

39.知识迁移能力--平衡二叉树

40.知识迁移能力--数组中只出现一次的数字

41.知识迁移能力--和为S的连续正数序列

42.知识迁移能力--和为S的两个数字

43.知识迁移能力--左旋转字符串

44.知识迁移能力--翻转单词顺序列

45.抽象建模能力--扑克牌顺子

46.抽象建模能力--圆圈中最后剩下的数

47.发散思维能力--求1+2+3+...+n

48.发散思维能力--不用加减乘除做加法

49.综合--把字符串转换成整数

50.数组--数组中重复的数字

51.数组--构建乘积数组

52.字符串--正则表达式匹配

53.字符串--表示数值的字符串

54.字符串--字符流中第一个不重复的字符

55.链表--链表中环的入口结点

56.链表--删除链表中重复的结点

57.树--二叉树的下一个结点

58.树--对称的二叉树

59.树--按之字形顺序打印的二叉树

60.树--把二叉树打印成多行

61.树--序列化二叉树

62.树--二叉搜索树的第k个结点

63.树--数据流中的中位数

64.栈和队列--滑动窗口的最大值

65.回溯法--矩阵中的路径

66.回溯法--机器人的运动范围

67.动态规划与贪婪--减绳子

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!