《剑指offer》详解-Python

文章目录

      • 1.二维数组中的查找
      • 2.替换空格
      • 3.从尾到头打印链表arrayList:
      • 4.两个栈实现一个队列:
      • 6.旋转数组的最小数字
      • 7.斐波那契数列
      • 8.跳台阶:
      • 9.变态跳台阶:
      • 10矩形覆盖:
      • 11. 二进制中1的个数:
      • 12.数值的整数次方
      • 13.调整数组顺序使奇数位于偶数前面
      • 14.链表中倒数第k个结点:
      • 15.反转链表:
      • 16.合并两个排序的链表:
      • 17.树的子结构:
      • 18.二叉树的镜像:
      • 20.包含min函数的栈:
      • 28.数组中出现次数超过一半的数字:
      • 29.最小的k个数:
      • 30.连续子数组的和:
      • 31.整数中1出现的次数:
      • 32.把数组排成最小的数:
      • 33.丑数:
      • 34.第一个只出现一次的字符:
      • 35.数组中的逆序对
      • 37.数字在排序数组中出现的次数:
      • 40.数组中只出现一次的数字:
      • 41.和为s的连续正数序列:
      • 42.和为s的两个数字
      • 43.左旋转字符串
      • 44.翻转单词顺序列:
      • 45.扑克牌顺子:
      • 46.孩子们的游戏(圆圈中最后剩下的数)
      • 47.求1+2+3+…+n:
      • 48.不用加减乘除做加法
      • 49.把字符串转换成整数
      • 50.数组中重复的数字
      • 51.构建乘积数组
      • 53.表示数值的字符串
      • 矩阵中的路径
      • 参考资料:

python刷《剑指offer》记录时间复杂度和多种做法。建议在 牛客网刷题,判断是否成功通过所有样例,看懂思路和自己写出来并AC,完全是两码事。若有错误欢迎指正。

题目 难度 复杂度 解法 备注
1.二维数组的查找 Easy O ( n 2 ) , O ( n ) O(n^2),O(n) O(n2),O(n) 遍历二维数组;从右上开始查找 Done
2.替换空格 Easy O ( n ) O(n) O(n) 遍历然后直接替换 Done
3.从尾到头打印链表arrayList Easy O ( n ) O(n) O(n) 遍历保存在list中 Done
4.重建二叉树 ToDo
5.两个栈实现一个队列 Easy 另一个栈作为中转 Done
6.旋转数组的最小数字 Easy O ( n ) , O ( l o g n ) O(n),O(logn) O(n),O(logn) 遍历数组;二分法 Done
7.斐波那契数列 Easy O ( n ) O(n) O(n) 递归;循环的方式实现递归 Done
8.跳台阶 Easy 和第七题类似 Done
9.变态跳台阶 Easy 数学归纳法 Done
10.矩形覆盖 Easy 和第七题类似 Done
11.二进制中1的个数 Medium 按位运算 ToDo
12.数值的整数次方 Medium O ( l o g n ) O(logn) O(logn) 采用递归算法依次降幂即可,按位运算可以加快速度 ToDo
13.调整数组顺序使奇数位于偶数前面 Medium python可以使用lambda ToDo
14.链表中倒数第k个结点 Medium O ( n ) O(n) O(n) 双指针,一前一后 Done
15.反转链表 Medium O ( n ) O(n) O(n) ToDo
16.合并两个排序链表 Medium O ( n + m ) O(n+m) O(n+m) 递归,依次返回两个链表的最小值 Done
17.判断子结构 Medium O ( ) O() O() ToDo
18.二叉树的镜像 Easy O ( ) O() O() 递归依次交换左右子树即可 Done
20.包含min函数的栈 Medium O ( n ) O(n) O(n) 建一个辅助栈,保存当前数的最小值 ToDo
28.数组中出现次数超过一半的数字 Medium O ( n ) ; O ( l o g n ) O(n);O(logn) O(n)O(logn) 遍历数组;从中间向两边展开 Done
29.最小的k个数 Medium O ( n l o g n ) ; O ( n ) O(nlogn);O(n) O(nlogn)O(n) 排序然后输出;挑选替换 Done
30.连续子数组的最大和 Easy O ( n 2 ) ; O(n^2); O(n2) 暴力法,求解所有字符串的和; Done
31.整数1出现的次数 Easy O ( n l o g n ) O(nlogn) O(nlogn) 遍历,然后计算个数 Done
32.把数组排成最小的数 Medium O ( n 2 ) ; O(n^2); O(n2); 字符串两两比较 ToDo
33.丑数 Medium O ( n ) O(n) O(n) 依次生成 Done
34.第一个只出现一次的字符 Easy O ( n ) O(n) O(n) 保存字典然后判断 Done
35.数组中的逆序对 Medium O ( n 2 ) ; O ( n l o g n ) O(n^2);O(nlogn) O(n2);O(nlogn) 暴力; Done
37.数字在排序数组中出现的次数 Easy O ( n ) ; O ( l o g n ) O(n);O(logn) O(n);O(logn) 遍历;二分查找 Done
40.数组中只出现一次的数字 Easy O ( n ) O(n) O(n) 哈希表 Done
41.和为s的连续正数序列 Easy O ( n 2 ) , O ( n ) , O ( l o g n ) O(n^2),O(n),O(logn) O(n2),O(n),O(logn) 双指针;遍历数组求另一个解;二分法 Done
42.和为S的两个数字 Easy O ( n ) O(n) O(n) 双指针 Done
43.左旋转字符串 Easy O ( 1 ) O(1) O(1) 好吧,太简单 Done
44.翻转单词顺序列 Easy O ( n ) O(n) O(n) 翻转组合 Done
45.扑克牌顺子 Easy O ( n ) O(n) O(n) gap和大小王个数比较 Done
46.圆圈中最后剩下的数 Easy O ( n ) O(n) O(n) 模拟这个过程 Done
47.求1+2+3+…+n Easy O ( n ) O(n) O(n) 利用and实现递归终止 Done
48.不用加减乘除做加法 Medium O ( 1 ) O(1) O(1) 利用位运算来实现 ToDO
49.把字符串转换成整数 Easy O ( n ) O(n) O(n) 主要是负数和特殊情况 Done
50.数组中重复的数字 Easy O ( n ) O(n) O(n) 哈希表保存次数然后输出 Done
51.构建乘积数组 Medium O ( n ) O(n) O(n) 正反向遍历,依次保存之前的乘积值 Done
53.表示数值的字符串 Easy O ( 1 ) O(1) O(1) 作弊式操作float Done
矩阵中路径 Medium 回溯法,关键是如何写递归

1.二维数组中的查找

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

A1: 遍历整个二维数组, O ( n 2 ) O(n^2) O(n2)

A2: 从右上或者左下开始查找。从右上开始查找:如果数组中的数比这个整数大,向左移动一位,如果数组中的数比这个数小,向下移动一位, O ( n ) O(n) O(n)

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

2.替换空格

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

A1: 先计算最终需要给出的长度,然后建立两个指针p1,p2,p1指向原始字符串的末尾,p2指向替换后的字符串的末尾。同时移动p1,p2, 将p1指的内容逐个复制到p2, 当p1遇到空格时,在p2处插入 %20, p1向前移动一个位置,p2向前移动3个位置,当p1和p2位置重合时,全部替换完成。

# 30ms
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        if not isinstance(s, str) or len(s) <= 0 or s == None:
            return ''
        spaceNum = 0
        for i in s:
            if i == " ":
                spaceNum += 1
        
        newStrLen = len(s) + spaceNum * 2
        newStr = newStrLen * [None]
        indexOfOriginal, indexOfNew = len(s) - 1, newStrLen - 1
        while indexOfNew >= 0 and indexOfOriginal <= indexOfNew:
            if s[indexOfOriginal] == ' ':
                newStr[indexOfNew - 2: indexOfNew + 1] = ['%', '2', '0']
                indexOfNew -= 3
                indexOfOriginal -= 1
            else: 
                newStr[indexOfNew] = s[indexOfOriginal]
                indexOfNew -= 1
                indexOfOriginal -= 1
        return ''.join(newStr)

A2: python中可以利用append() [O(1)],新建list,一次遍历,碰到空格就添加 %20,否则就添加原始字符串s内容。

# 27ms
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        if not isinstance(s, str) or len(s) <= 0 or s == None:
            return ''
        result = []
        for char in s:
            if char == ' ':
                result.append('%20')
            else:
                result.append(char)
        return ''.join(result)

    def replaceSpace(self, s):
        # write code here
        result = ''
        for char in s:
            if char == ' ':
                result += '%20'
            else:
                result += char
        return result

3.从尾到头打印链表arrayList:

遍历链表,保存在list中,然后倒序输出.

# 运行时间:24ms
# 占用内存:5752k
class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        if listNode == None:
            return []
        result = []
        while listNode != None:
            result.append(listNode.val)
            listNode = listNode.next
        return result[::-1]

同样使用list,但是将其插入在list的0位置处。

# 运行时间:23ms
# 占用内存:5728k
class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        if not listNode:
            return []
        
        result =[]
        
        while listNode:
            result.insert(0, listNode.val)
            listNode = listNode.next
        return result

4.两个栈实现一个队列:

stack2作为中转stack,直接对stack1做push,pop的时候将stack1的pop到stack2中,便可以实现。stack:先入后出,queue:后入先出。

# 运行时间:25ms
# 占用内存:5724k
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
        
    def push(self, node):
        # write code here
        self.stack1.append(node)
        
    def pop(self):
        # return xx
        if len(self.stack1) == 0 and len(self.stack2) == 0:
            return 
        if len(self.stack2) == 0:
            while len(self.stack1) != 0:
                self.stack2.append(self.stack1.pop())
        return self.stack2.pop()

6.旋转数组的最小数字

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

A1: 遍历数组;
A2: 二分查找的变形,旋转数组的首元素肯定不小于旋转数组的尾元素,找一个中间点,如果中间点比首元素大,说明最小数字在中间点后面,如果中间点比尾元素小,说明最小数字在中间点前面。然后循环。 但是在一次循环中,首元素小于尾元素,说明该数组是排序的,首元素就是最小数字,如果出现首元素、尾元素、中间值三者相等,则只能在此区域中顺序查找。

# -*- coding:utf-8 -*-

class Solution:
# 运行时间:1127ms
# 占用内存:5864k
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if len(rotateArray) == 0:
            return 0
        result = rotateArray[0]
        for num in rotateArray:
            if num < result:
                result = num
        return result

class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if len(rotateArray) == 0:
            return 0
        left,right = 0,len(rotateArray)-1

        if rotateArray[left] < rotateArray[right]:
            return rotateArray[left]
        else:
            while (right - left) > 1:
                middle = (left+right)//2
                if rotateArray[middle] <= rotateArray[right]:
                    right = middle
                elif rotateArray[middle] >= rotateArray[left]:
                    left = middle
                elif rotateArray[middle] == rotateArray[right] == rotateArray[left]:
                    minval = rotateArray[0] 
                    for num in rotateArray:
                        minval = min(minval, num)
                    return minval
        return rotateArray[right]

7.斐波那契数列

class Solution:
    def Fibonacci(self, n):
        # write code here
        num1 = 0
        num2 = 1
        target = 0
        for i in range(1, n+1):
            num1 = num2
            num2 = target
            target = num1 + num2
        return target

8.跳台阶:

和第七题类似,跳第n阶有两种情况,由倒数第二阶直接跳到第n阶,倒数第一阶直接跳到第n阶。

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloor(self, number):
        # write code here
        if number == 1:
            return 1
        elif number == 2:
            return 2
        num1 = 1
        num2 = 2
        target = num1 + num2
        for i in range(2, number-1):
            num1 = num2
            num2 = target
            target = num1 + num2
        return target

9.变态跳台阶:

通过归纳法得出规律,然后直接由公式求解。

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

10矩形覆盖:

# -*- coding:utf-8 -*-
class Solution:
    def rectCover(self, number):
        # write code here
        if number == 1:
            return 1
        elif number == 2:
            return 2
        elif number == 0:
            return 0
        num1 = 1
        num2 = 2
        target = num1 + num2
        for i in range(2, number-1):
            num1 = num2
            num2 = target
            target = num1 + num2
        return target

11. 二进制中1的个数:

n n n n − 1 n-1 n1按位做与运算,会将最右边的1设置为0。n不为0一直统计统计个数。

# -*- coding:utf-8 -*-
class Solution:
# 运行时间:27ms
# 占用内存:5728k
    def NumberOf1(self, n):
        # write code here
        count = 0
        if n < 0:
            n = n & 0xffffffff
        while n!= 0:
            count += 1
            n = (n-1)& n
        return count

12.数值的整数次方

通过递归求解,如果幂次是偶数,直接除以2,如果是奇数,提取一个base后除以2。举例发现规律。注意点:幂次是否小于0,奇偶幂次的区分,幂次为0和1

# -*- coding:utf-8 -*-
class Solution:
# 运行时间:23ms
# 占用内存:5624k
    def Power(self, base, exponent):
        # write code here
        try:
            if exponent >= 0:
                return self.Power_value(base, exponent)
            else:
                return 1/self.Power_value(base, abs(exponent))
        except:
            print('base == zero')

    def Power_value(self, base, exponent):
        if exponent == 1:
            return base
        elif exponent == 0:
            return 1
        if exponent%2 == 0:
            return self.Power(base, exponent>>1)**2
        else:
            return base*self.Power(base, exponent>>1)**2

采用位运算可以加快速度,除以2可以通过向右移1位来实现,判断奇偶可以通过与1按位与来实现。

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

python使用lambda解决。

class Solution:
# 运行时间:28ms
# 占用内存:5752k
    def reOrderArray(self, array):
        # write code here
        return sorted(array,key=lambda c:c%2,reverse=True)

14.链表中倒数第k个结点:

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

A: 设置两个指针指向头节点,第一个指针向前走k-1步,走到第k个结点,此时,第二个指针和第一个指针同时移动,当第一个指针到尾节点的时候,第二个指针指向倒数第k个结点,注意链表为空,k为0,k大于链表的长度的情况.

# 27ms
class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        if head == None or k <= 0:
            return None
        
        pointA = head
        pointB = None

        for i in range(k-1):
            if pointA.next != None:
                pointA = pointA.next
            else:
                return None
        
        pointB = head
        while pointA.next != None:
            pointA = pointA.next
            pointB = pointB.next

        return pointB

15.反转链表:

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

A: 主要注意当头结点为空或者整个链表只有一个结点时,翻转后的链表断裂,返回的翻转之后的头节点不是原来的尾节点。所以需要一个翻转后的头节点,一个指向当前结点的指针,两个分别指向当前结点的前后结点的指针,防止断裂。也可以使用递归。

class Solution:
# 35ms
    def ReverseList(self, pHead):
        # write code here
        res = None
        while pHead:
            res,res.next,pHead = pHead,res,pHead.next
        return res

16.合并两个排序的链表:

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

A1递归: 比较头节点大小,小的作为合并后链表的头节点,再比较剩余部分和另一个链表的头节点,取小的,然后一直递归此过程。

class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if pHead1 == None:
            return pHead2
        if pHead2 == None:
            return pHead1
        
        pMergeHead = None
        if pHead1.val < pHead2.val:
            pMergeHead = pHead1
            pMergeHead.next = self.Merge(pHead1.next, pHead2)
        else:
            pMergeHead = pHead2
            pMergeHead.next = self.Merge(pHead1, pHead2.next)
        return pMergeHead

17.树的子结构:

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        result = False
        if pRoot1 != None and pRoot2 != None:
            if pRoot1.val == pRoot2.val:
                result = self.DoesTree1haveTree2(pRoot1, pRoot2)
            
            if not result:
                result = self.DoesTree1haveTree2(pRoot1.left, pRoot2)
            
            if not result:
                result = self.DoesTree1haveTree2(pRoot1.right, pRoot2)
        
        return result

    def DoesTree1haveTree2(self, pRoot1, pRoot2):
        if pRoot2 == None:
            return True
        if pRoot1 == None:
            return False
        if pRoot1.val != pRoot2.val:
            return False

        return self.DoesTree1haveTree2(pRoot1.left, pRoot2.left) & self.DoesTree1haveTree2(pRoot1.right, pRoot2.right)

18.二叉树的镜像:

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

        temp = root.left
        root.left = root.right
        root.right = temp

        self.Mirror(root.left)
        self.Mirror(root.right)

20.包含min函数的栈:

求得栈的最小值,时间复杂度是 O ( 1 ) O(1) O(1)。建立一个辅助栈,每增加一个数,保存目前所有数的最小值在辅助栈的栈顶。

class Solution:
# 运行时间:23ms
# 占用内存:5752k
    def __init__(self):
        self.stack = []
        self.minStack = []
        
    def push(self, node):
        # write code here
        self.stack.append(node)
        if self.minStack == [] or node < self.min():
            self.minStack.append(node)
        else:
            temp = self.min()
            self.minStack.append(temp)
        
    def pop(self):
        # write code here
        if self.stack == None or self.minStack == None:
            return None
        self.minStack.pop()
        self.stack.pop()
        
    def top(self):
        # write code here
        return self.stack[-1]
        
    def min(self):
        # write code here
        return self.minStack[-1]

28.数组中出现次数超过一半的数字:

暴力做法,保存每一个数出现的次数,然后判断每一个数的次数是否超过一半。

# 运行时间:28ms
# 占用内存:5860k
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here

        num_dict = {}
        lenght = len(numbers)
        result = 0
        for num in numbers:
            try:
                num_dict[num] = num_dict[num] + 1
            except:
                num_dict[num] = 1

        for key, values in num_dict.items():
            if values > lenght//2:
                result = key

        return result

如果这个数存在那么一定在数组的中间,提取数组中间这个数,然后统计其出现的次数,判断是否超过一半:

class Solution:
# 运行时间:28ms
#占用内存:5744k
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here

        numbers = sorted(numbers)
        middle = len(numbers)//2
        left = right = middle
        middle_num = numbers[middle]
        print(numbers)
        while left >= 0 and right < len(numbers):
            if numbers[left] != middle_num and numbers[right] != middle_num:
                break
            print(left,right)
            if numbers[left] == middle_num:
                left -= 1
            if numbers[right] == middle_num:
                right += 1


        if right - left-1 > len(numbers)//2:
            return middle_num
        else:
            return 0

29.最小的k个数:

排序然后取前k个:

# 运行时间:29ms
# 占用内存:5624k
# -*- coding:utf-8 -*-
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here
        if k > len(tinput):
            return []
        tinput = sorted(tinput)
        return tinput[:k]

保存前k个值在result中,依次遍历后续n-k个值,如果出现数小于result的最大值,替换这个最大值。

# -*- coding:utf-8 -*-
# 时间:24ms
# 占用内存:5728k
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here
        if k > len(tinput) or k == 0:
            return []
        result = tinput[:k]
        for num in tinput[k:]:
            temp_max = max(result)
            if num < temp_max:
                result.remove(temp_max)
                result.append(num)
        return sorted(result)

30.连续子数组的和:

遍历所有子数组,然后比较大小。

class Solution:
# 运行时间:20ms
# 占用内存:5732k
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        maxsum = -1e19
        for i in range(len(array)-1):
            for j in range(i+1, len(array)+1):
                maxsum = max(maxsum, sum(array[i:j]))
        return maxsum

31.整数中1出现的次数:

遍历1:n,然后求每个数中1的个数,对10取余得到个位数,然后依次除以10。

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        result = 0
        for num in range(1,n+1):
            while num != 0:
                if num%10 == 1:
                    result += 1
                num = num//10
        return result

数学规律法,相对简单但是一般很难想到。

class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        count, m =0, 1
        while m <= n:
            count += (n // m + 8) // 10 * m + (n // m % 10 == 1) * (n % m + 1)
            m*=10
        return count

32.把数组排成最小的数:

对数组内的数字两两比较,寻找str1str2,和str2str1两种组合中较小的一个。两两较小,最后得到的即最小。

# -*- coding:utf-8 -*-
# 运行时间:20ms
# 占用内存:5856k
class Solution:
    def PrintMinNumber(self, numbers):
        # write code hereu
        if not numbers:
            return ''
        numbers = [str(num) for num in numbers]
        for i in range(len(numbers)-1):
            for j in range(i+1, len(numbers)):
                if numbers[j] + numbers[i] < numbers[i] + numbers[j]:
                    numbers[i],numbers[j] = numbers[j],numbers[i]
        return ''.join(numbers)

33.丑数:

生成第K个丑数(质因子只有2,3,5)。建立一个set,从1开始,依次保存和1,2,3分别相乘后值,取较小的值作为下一个丑数,同时从set中去掉已经作为丑数的这个数。

# -*- coding:utf-8 -*-
class Solution:
# 运行时间:28ms
# 占用内存:5856k
    def GetUglyNumber_Solution(self, index):
        # write code here
        if index == 0:
            return 0
        count = 1
        result = 1
        ugly_list = set()
        while count < index:
            ugly_list.add(2*result)
            ugly_list.add(3*result)
            ugly_list.add(5*result)
            result = min(ugly_list)
            ugly_list.remove(result)
            count += 1
        return result

34.第一个只出现一次的字符:

统计每个字符出现的次数,保存在字典中。然后再次遍历字符串,获取每个字符的次数,如果为1,直接输出。

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        char_count = {}
        for char in s:
            try:
                char_count[char] += 1
            except:
                char_count[char] = 1
        for char in s:
            if char_count[char] == 1:
                return s.index(char)
        return -1

35.数组中的逆序对

直接暴力法,双指针,判断当前指针的数是否大于第二个指针的数字。

class Solution:
    def InversePairs(self, data):
        # write code here
        length = len(data)
        count = 0
        for i in range(length-1):
            for j in range(i+1, length):
                if data[i] > data[j]:
                    count += 1
        return count%1000000007

将原数组排序,然后从小到大遍历排序数组,求这个数在原数组中的index,这个index就代表有多少个数字在该数的前面。

class Solution:
    def InversePairs(self, data):
        # write code here
        data2 = sorted(data)
        length = len(data)
        count = 0
        for num in data2:
            count += data.index(num)
            data.remove(num)
        return count%1000000007

37.数字在排序数组中出现的次数:

直接遍历然后求和

运行时间:31ms
占用内存:5712k
# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        count = 0
        for num in data:
            if num == k:
                count += 1
        return count

采用二分查找,通过二分查找依次找到左边,右边和k相等的起始点。

# -*- coding:utf-8 -*-
class Solution:
# 运行时间:23ms
# 占用内存:5752k
    def GetNumberOfK(self, data, k):
        # write code here
        if not data:
            return 0
        if self.GetLastK(data, k) == -1 and self.GetFirstK(data, k) == -1:
            return 0
        return self.GetLastK(data, k) - self.GetFirstK(data, k) + 1
        

    def GetFirstK(self, data, k):
        low = 0
        high = len(data) - 1
        while low <= high:
            mid = (low + high) // 2
            if data[mid] < k:
                low = mid + 1
            elif data[mid] == k and (mid == low or data[mid-1]!=k):
                return mid
            else:
                high = mid - 1
        return -1

    def GetLastK(self, data, k):
        low = 0
        high = len(data) - 1
        while low <= high:
            mid = (low + high) // 2
            if data[mid] > k:
                high = mid - 1
            elif data[mid] == k and (mid == high or data[mid+1]!=k):
                return mid
            else:
                low = mid + 1
        return -1

40.数组中只出现一次的数字:

建立一个Hash表保存每个数出现的次数,然后遍历Hash表输出只出现一次的那个数。

# 运行时间:26ms
# 占用内存:5752k
# -*- coding:utf-8 -*-
class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
        # write code here
        num_count = {}
        result = []
        for num in array:
            num_count[num] = num_count.get(num,0) + 1
        for key,value in num_count.items():
            if value == 1:
                result.append(key)
        return result

采用异或操作,如果两个数相同,那么他们异或是0,不同则非0。有两个只出现一次的数,后面还要判断有点麻烦,如果是只有一个数出现一次,判断起来会相对比较简单。

41.和为s的连续正数序列:

双指针,如果和大于tsum,那么减去最小的值,同时最小值index+1。如果和小于tsum,最大值的index+1,然后增加新的最大值。

# 运行时间:26ms
# 占用内存:5852k
# -*- coding:utf-8 -*-
class Solution:
    def FindContinuousSequence(self, tsum):
        # write code here
        small, big,res = 1, 2, []
        csum = small + big
        while small < big:
            if csum > tsum:
                csum -= small
                small += 1
            elif csum == tsum:
                res.append([i for i in range(small,big+1)])
                big += 1
                csum += big
            else:
                big += 1
                csum += big
        return res

42.和为s的两个数字

双指针,分别从头和尾开始,如果两个数的和小于S,left+=1,大于S,right-=1。

class Solution:
# 运行时间:36ms
# 占用内存:5740k
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        if not array or not tsum:
            return []
        start = 0
        end = len(array) - 1
        while start < end:
            csum = array[start] + array[end]
            if csum < tsum:
                start += 1
            elif csum > tsum:
                end -= 1
            else:
                return [array[start],array[end]]
        return []

43.左旋转字符串

2333这题目逆天吧,前面的提出贴在后面不就好了吗。

class Solution:
    def LeftRotateString(self, s, n):
        # write code here
        return s[n:]+ s[:n]

44.翻转单词顺序列:

翻转组合即可,list.reverse()的复杂度是 O ( n ) O(n) O(n).

# 运行时间:30ms
# 占用内存:5708k
# -*- coding:utf-8 -*-
class Solution:
    def ReverseSentence(self, s):
        # write code here
        s = s.split(' ')
        s.reverse()
        return ' '.join(s)

45.扑克牌顺子:

替换,然后统计gap的次数,如果存在gap,比较大小王的个数,是否大于gap的个数。注意两个数字相等的情况。

# 运行时间:37ms
# 占用内存:5624k
# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        # write code here
        if not numbers or len(numbers) == 0:
            return False
        transdict = {'A':1,'J':11,'Q':12,'K':13}
        numbers = [transdict[num] if num in transdict else num for num in numbers]
        numbers = sorted(numbers)
        count_wang = 0
        while numbers[count_wang] == 0:
            count_wang += 1
        gap = 0
        for i in range(count_wang,len(numbers)-1):
            if numbers[i+1] == numbers[i]:
                return False
            gap += numbers[i+1] - numbers[i]-1
        
        return True if count_wang >= gap else False   

46.孩子们的游戏(圆圈中最后剩下的数)

约瑟夫环问题,可以直接进行模拟,也就是模拟去掉人的过程,直到最后只剩下一个人。注意起点和被去掉的人,循环一圈后如何表达。(start+m-1)%n,n为当时圆圈内的人数,没去掉一个人,n-1.

# 运行时间:22ms
# 占用内存:5860k
# -*- coding:utf-8 -*-
class Solution:
    def LastRemaining_Solution(self, n, m):
        if n < 1 or m < 1:
            return -1
        start = 0
        circle = range(n)
        while circle:
            index = (start+m-1)%n
            end = circle.pop(index)
            start = index
            n -= 1
        return end

47.求1+2+3+…+n:

问题奇葩,直接抛开限制,各种答案比较下:

# 运行时间:22ms
# 占用内存:5724k
def Sum_Solution(self, n):
    return sum(range(1,n+1))

利用and来实现递归的终止,因为不能使用if else来确定终止条件,所以使用and语句。任何数和0与是0(False)。

# 运行时间:20ms
# 占用内存:5864k
def Sum_Solution(self, n):
    return n and self.Sum_Solution(n - 1) + n

48.不用加减乘除做加法

通过位运算来实现。

class Solution:
    def Add(self, num1, num2):
        # write code here
        while num2 != 0:
            temp = num1 ^ num2
            num2 = (num1 & num2) << 1
            num1 = temp & 0xFFFFFFFF
        return num1 if num1 >> 31 == 0 else num1 - 4294967296

49.把字符串转换成整数

直接利用int操作。

class Solution:
    def StrToInt(self, s):
        try:
            return int(s)
        except:
            return 0

不用内部函数来实现:

# 运行时间:21ms
# 占用内存:5732k
# -*- coding:utf-8 -*-
class Solution:
    def StrToInt(self, s):
        if not s or len(s) < 1:
            return 0
        numdict = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
        result = 0
        nums = []
        for char in s:
            if char == '+' or char == '-':
                continue
            elif char in numdict:
                nums.append(numdict[char])
            else:
                return 0
        # 由list得到数值,这个写法要会
        for i in nums:
            result = result*10 + i
        return -1*result if s[0] == '-' else result

50.数组中重复的数字

保存哈希表,然后再遍历依次即可。哈希表的查找时间是 O ( 1 ) O(1) O(1).

# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        count_dict = {}
        for num in numbers:
            count_dict[num] = count_dict.get(num,0) + 1
        for num in numbers:
            if count_dict[num] > 1:
                duplication[0] = num
                return True
        return False

51.构建乘积数组

从左到右递乘,依次将结果保存在result里面,再反向从右到左递乘,保存结果。

# 运行时间:21ms
# 占用内存:5860k
# -*- coding:utf-8 -*-
class Solution:
    def multiply(self, A):
        # write code here
        B = A[::-1]
        length = len(A)
        result = [1]*length
        temp = 1
        for i in range(1,length):
            result[i] = result[i-1] * A[i-1]
        for i in range(length-2,-1,-1):
            temp = temp * A[i+1]
            result[i] *= temp
        return result

53.表示数值的字符串

作弊操作:

def isNumeric(self, s):
    try:
        s = float(s)
        return True
    except:
        return False

矩阵中的路径

Q: 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串”bcced”的路径,但是矩阵中不包含”abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

A: 回溯法。任选一个格子作为路径的起点。假设矩阵中某个格子的字符为ch并且这个格子将对应于路径上的第i个字符。如果路径上的第i个字符不是ch,那么这个格子不可能处在路径上的第i个位置。如果路径上的第i个字符正好是ch,那么往相邻的格子寻找路径上的第i+1个字符。除在矩阵边界上的格子外,其他各自都有4个相邻的格子。重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。

# -*- coding:utf-8 -*-
class Solution:
    def hasPath(self, matrix, rows, cols, path):
        # write code here
        if not matrix:
            return False
        if not path:
            return True
        array = [list(matrix[i*cols:(i+1)*cols]) for i in range(rows)]
        
        for i in range(rows):
            for j in range(cols):
                m,n = i,j
                if self.searchPath(array, i, j, path):
                    return True
    
    def searchPath(self, matrix, i, j, path):
        if matrix[i][j] == path[0]:
            
            if not path[0:]:
                return True
            
            matrix[i][j] == ''
            if i < len(rows)-1 and self.searchPath(matrix, i+1, j, path[1:]):
                return True
            if i > 1 and self.searchPath(matrix, i-1, j, path[1:]):
                return True
            if j < len(cols)-1 and self.searchPath(matrix, i, j+1, path[1:]):
                return True
            if j > 1 and self.searchPath(matrix, i, j-1, path[1:]):
                return True
            
            matrix[i][j] == path[0]
            return False
        else:
            return False

参考资料:

[1] 作者博客:http://zhedahht.blog.163.com/

你可能感兴趣的:(杂记,python)