Python 编程进阶经典算法逻辑编程 剑指Offer

目录

1. 找到数组中重复数字(字符),返回出现频次最多

2. 给定一个二维数组,其每一行从左到右递增排序,从上到下也是递增排序。给定一个数,判断这个数是否在该二维数组中。

3. 从尾到头打印链表

4. 用两个栈实现队列

5.  第n项斐波那契数列; 矩形覆盖, n 个 2*1 的小矩形无重叠地覆盖一个 2*n 的大矩形,总共有多少种方法?; 跳台阶

6. 复杂版跳台阶,对于n层台阶,一个青蛙可以一次跳1-n步,有多少种跳法?

7. 二分查找

8. 有序旋转数组最小数字查找

9. 机器人运动范围

10. 剪绳子

11. 矩阵中的路径是否存在

判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向上下左右移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。

12. 进制转换问题

Excel表, A表示第一列, AA表示第27列,AB表示第28列,根据表的字符串索引转换成数字

13. 二进制中1的个数

14. 一条语句判断一个整数是不是2的整数次方

15. 输入两个整数m,n,判断二进制最少改变多少位能得m->n

先求异或,再统计异或结果1的个数

16. 字符串解压缩

如输入 a = '3[ab]acc',则输出'abababacc'

17. O(1)时间删除链表节点

18.寻找所有可能子集合

输入[1,2,3],输出[[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]

19. 输出字符串所有可能排列组合

输入'abc',输出['abc', 'acb', 'bac', 'bca', 'cab', 'cba']。

20. 顺时针打印长宽相等矩阵

21. 找到数组中出现次数超过一半的数字

22. 数组中连续子数组最大和

23. 正则表达式匹配

请实现一个函数用来匹配包括 '.' 和 '*' 的正则表达式。模式中的字符 '.' 表示任意一个字符,而 '*' 表示它前面的字符可以出现任意次(包含 0 次)。

24. 链表反转

25. 礼物最大价值

26. 和为n的所有连续正数列

27. 去除字符串字符连续出现次数大于2的

28. 火柴拼成的数字,从一个数移动一根给另外一个数(只能移动一次),移动后最大值?

29. 股票可以有一次买入和一次卖出,买入必须在前。求最大收益。

30. 圆圈中最后的小孩,n个小孩,第0个开始数到m,无放回出列,再从下一个开始数,最后小孩是都在时候第几个?

31. n个筛子,求扔出去和为s的概率

32. 滑动窗口最大值, 数组a,窗口大小为k

33. 和为s两个数字,有多组选积最小的

34. 一个数组只出现过一次的数,其余均两次

35. 有序数组指定数出现次数

36. 丑数


 

1. 找到数组中重复数字(字符),返回出现频次最多

# 时间复杂度O(N), 空间复杂度O(1)
class Solution(object):
    def find_duplicated(self, a):
        res = 0
        for i in a:
            n = 1 << i-0
            if (res | n) == res:
                return i
            else:
                res |= n

        return res


# 字典方法,时间复杂度O(N), 空间复杂度O(N)
def maxf(x):
    a = dict()
    max = 0
    for i in x:
        tem = str(i)
        a[tem] = a.get(tem,0) + 1
        if max < a[tem]:
            max = a[tem]
    return max

2. 给定一个二维数组,其每一行从左到右递增排序,从上到下也是递增排序。给定一个数,判断这个数是否在该二维数组中。

class Solution(object):
    def find_in_matrix(self, f, a):
        row, column = a.shape
        for i in range(row):
            # 最后一列大于还是小于
            if f > a[i,column-1]:
                continue
            else:
                # 不断左移对比
                while column-1 >= 0:
                    if f == a[i, column-1]:
                        return True
                    else:
                        column -= 1
        return False

3. 从尾到头打印链表

class Solution(object):
    def reverse_print(self, list_node):
        res = []

        while list_node:
            res.append(0, list_node.val)
            list_node = list_node.next
        
        return res

4. 用两个栈实现队列

class Solution(object):
    def __init__(self):
        self.s1 = []
        self.s2 = []

    def pop(self):
        return self.s2.pop()

    def push(self, a):
        for i in a:
            self.s1.append(i)
        while len(self.s1):
            self.s2.append(self.s1.pop())

5.  第n项斐波那契数列; 矩形覆盖, n 个 2*1 的小矩形无重叠地覆盖一个 2*n 的大矩形,总共有多少种方法?; 跳台阶

# 递归
class Solution(object):
    def find_fibo(self, a):
        if a == 0:
            return 0
        elif a == 1:
            return 1
        else:
            return self.find_fibo(a-1) + self.find_fibo(a-2)


# 动态规划 O(N) 最优解
class Solution(object):
    def find_fibo(self, a):
        min1 = 0
        min2 = 1

        if a == 0:
            return 0
        elif a == 1:
            return 1
        else:
            for i in range(2, a+1):
                a = min2
                min2 = min1 + min2
                min1 = a
            return min2

6. 复杂版跳台阶,对于n层台阶,一个青蛙可以一次跳1-n步,有多少种跳法?

# f(n) = f(n-1) + f(n-2) + ... + f(0)
# f(n-1) = f(n-2) + f(n-3) + ... + f(0)
# f(n) - f(n-1) = f(n-1) 等比

class Solution(object):
    def jump_num(self, a):
        if a == 0:
            return 0

        return 2**(a-1)

7. 二分查找

# 时间复杂度O(log2(N))

class Solution(object):

    def main(self, a, b):
        l = 0
        h = len(a) - 1

        while l <= h:
            m = (h + l) // 2

            if a[l] < b and a[m] > b:
                h = m-1
            elif a[h] > b and a[m] < b:
                l = m+1
            elif a[m] == b:
                return m
            else:
                return -1

8. 有序旋转数组最小数字查找

# 时间复杂度O(log2(N)
class Solution(object):
    def find_min(self, a):
        if len(a) == 1:
            return a[0]

        v = a[0]
        l = 0
        h = len(a) - 1
        while l < h:
            mid = (h + l) // 2

            if a[l] <= a[mid]:
                if v > a[l]:
                    v = a[l]
                l = mid
            else:
                if v > a[mid]:
                    v = a[mid]
                h = mid - 1
        return v

9. 机器人运动范围

# a*b矩阵,当a和b每位数之和sum((12,34),sum = 1+2+3+4)<=k时允许进入该格子,统计路径最多能走多远,这个解决的比原题要难一些。

class Solution(object):
    def __init__(self):
        self.rows = None
        self.columns = None

    def check_boundry(self, k, x, y):
        c = 0
        while x > 0:
            c += x % 10
            x = x // 10
        while y > 0:
            c += y % 10
            y = y // 10

        return True if k >= c else False

    def max_move(self, mat, coordinate):
        x, y = coordinate[0], coordinate[1]

        if x < 0 or x >= self.rows:
            return 0
        elif y < 0 or y >= self.columns:
            return 0

        if mat[x, y] == 1:
            mat[x, y] = 0
            return 1 + max(self.max_move(mat, [x-1, y]), self.max_move(mat, [x+1, y]),
                           self.max_move(mat, [x, y-1]), self.max_move(mat, [x, y+1]))
        else:
            return 0

    def main(self, k, m, n):
        if k<0 or m<=0 or n<=0:
            return 0

        self.rows, self.columns = m, n
        mat = np.mat(np.ones((m, n)))
        # 生成矩阵,指明哪些能走,哪些不能走
        for i in range(self.rows):
            for j in range(self.columns):
                if not self.check_boundry(k, i, j):
                    mat[i, j] = 0

        return self.max_move(mat, [0, 0])

10. 剪绳子

# 一根长度为n的绳子,剪成m段,n,m >1且为整数,求子段长度最大乘积。贪婪算法

class Solution(object):
    def maxproduct(self, a):
        if a < 2:
            return 0
        elif a == 2:
            return 1
        elif a == 3:
            return 2
        elif a == 4:
            return 4
        elif a >= 5:
            c = a // 3
            r = a % 3
            if r == 1:
                return (3**(c-1)) * 4
            else:
                return (3**c) * r

11. 矩阵中的路径是否存在

判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向上下左右移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。

例如下面的矩阵包含了一条 bfce 路径。

from numpy import matrix


class Solution(object):
    def __init__(self):
        self.rows = None
        self.columns = None

    def find_root(self, a, m):
        self.rows, self.columns = m.shape
        for i in range(self.rows):
            for j in range(self.columns):
                if self.find(m, [i, j], a):
                    return True

        return False

    def find(self, data, coordinate, a, ):
        x, y = coordinate[0], coordinate[1]

        if x < 0 or x >= self.rows:
            return False
        elif y < 0 or y >= self.columns:
            return False

        if data[x, y] == a[0]:
            if len(a) == 1:
                return True

            data[x, y] = ''
            return self.find(data, [x-1, y], a[1:]) | \
                   self.find(data, [x+1, y], a[1:]) | \
                   self.find(data, [x, y-1], a[1:]) | \
                   self.find(data, [x, y+1], a[1:])
        else:
            return False

# m = matrix([['a','b','c'],['d','e','f'],['g','h','i']])
# s = Solution()
# print(s.find_root('adefc', m))

12. 进制转换问题

Excel表, A表示第一列, AA表示第27列,AB表示第28列,根据表的字符串索引转换成数字

class Solution(object):
    def find_column(self, a):
        res = 0
        l = len(a) - 1
        for i, value in enumerate(a):
            res += (26**(l-i)) * (ord(value) - ord('A') + 1)

        return res

13. 二进制中1的个数

class Solution(object):
    def find_one_num(self, a):
        res = 0
        while a > 0:
            a = a & a-1
            res += 1

        return res

14. 一条语句判断一个整数是不是2的整数次方

class Solution(object):
    def whether_div_two(self, a):
        return True if a & a-1 == 0 else False

15. 输入两个整数m,n,判断二进制最少改变多少位能得m->n

先求异或,再统计异或结果1的个数

16. 字符串解压缩

如输入 a = '3[ab]acc',则输出'abababacc'

class Solution(object):

    def main(self, a):
        res = ""
        check_point_num = 0
        check_point_str = ""
        gate = 0
        for i in a:
            if i.isdigit():
                check_point_num = int(i)
                continue
            elif i == "[":
                gate = 1
                continue
            elif i == "]":
                gate = 2

            if gate == 1:
                check_point_str += i
            elif gate == 2:
                res += check_point_str * check_point_num
                gate = 0
                check_point_num = 0
                check_point_str = ""
            elif gate == 0:
                res += i

        return res

17. O(1)时间删除链表节点

class ListNode(object):
    def __init__(self):
        self.val = None
        self.next = None

class Solution(object):

    def main(self, head, delete):
        if head is None or delete is None:
            return None

        if delete.next is not None:
            next = delete.next
            delete.val = next.val
            delete.next = next.next
        else:
            if head is None:
                head = None
            else:
                cur = head

                while cur != delete:
                    cur = cur.next
                cur.next = None

        return head

18.寻找所有可能子集合

输入[1,2,3],输出[[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]

class Solution(object):

    def main(self, a):
        res = self.find_subset(a)
        for i in a:
            res += [[i]]
        res.append([])

        return res

    def find_subset(self, a):
        
        if len(a) <= 1:
            return []
        # 把当前最长加进去
        res = [a]

        for i,v in enumerate(a):
            # 用子集获取最长串
            for j in self.find_subset(a[0:i]+a[i+1:]):
                if j not in res:
                    res.append(j)

        return res

19. 输出字符串所有可能排列组合

输入'abc',输出['abc', 'acb', 'bac', 'bca', 'cab', 'cba']。

 class Solution(object):
    def main(self, a):
        res = []
        if len(a) == 1:
            return a

        # 把每个都有机会放最前面
        for i, v in enumerate(a):
            for j in self.main(a[:i] + a[i+1:]):
                res.append(v + j)

        return res

20. 顺时针打印长宽相等矩阵

class Solution(object):
    def __init__(self):
        self.rows = 0
        self.columns = 0

    def main(self, m):
        self.rows, self.columns = m.shape

        if self.rows == 1 and self.columns == 1:
            return m[0, 0]

        res = []
        x1, y1 = 0, 0
        x2, y2 = self.rows-1, self.columns-1
        # 打印四个方向规律一样,打印完一圈往里走一圈
        while x1 <= x2 and y1 <= y2:
            if x1 == x2 and y1 == y2:
                res.append(m[x1, y1])
                break

            for i in range(y1, y2+1):
                res.append(m[x1, i])

            for i in range(x1+1, x2+1):
                res.append(m[i, y2])

            for i in range(y1, y2)[::-1]:
                res.append(m[x2, i])

            for i in range(x1+1, x2)[::-1]:
                res.append(m[i, y1])

            x1 += 1
            x2 -= 1
            y1 += 1
            y2 -= 1

        return res

21. 找到数组中出现次数超过一半的数字

# 时间复杂度O(N), 空间复杂度O(1)
class Solution(object):
    def main(self, a):
        if len(a) == 1:
            return a[0]
        # 两两对冲
        res = a[0]
        num = 1
        for i in range(1, len(a)):
            if a[i] != res:
                num -= 1
                if num < 0:
                    res = a[i]
                    num = 1
            else:
                num += 1

        return res

22. 数组中连续子数组最大和

# 初始设置sum为0,遍历数组往后加,遇到加之后小于0情况sum清零并且result记录sum上次大于0的值。
# 时间复杂度O(N)
class Solution(object):
    def main(self, a):
        if len(a) == 1:
            return max(a[0])

        res = 0
        tmp = 0
        checkpoint = 0
        for i in a:
            if checkpoint == 0 and i <= 0:
                continue

            if i >= 0:
                checkpoint += i
            else:
                if res < checkpoint:
                    res = checkpoint

                if checkpoint + i <= 0:
                    checkpoint = 0
                else:
                    checkpoint += i

        return max(res, checkpoint)

23. 正则表达式匹配

请实现一个函数用来匹配包括 '.' 和 '*' 的正则表达式。模式中的字符 '.' 表示任意一个字符,而 '*' 表示它前面的字符可以出现任意次(包含 0 次)。

class Solution(object):
    def main(self, a, pattern):
        if len(pattern) == 0:
            return ""

        res = ""
        pass_flag = False
        for i, v in enumerate(a):
            if res != "":
                return res

            for j, vv in enumerate(pattern):
                if pass_flag:
                    pass_flag = False
                    continue

                # pattern到头
                if j == len(pattern) - 1 and vv == "*":
                    while True:
                        if i < len(a) and res[-1] == a[i]:
                            res += a[i]
                            i += 1
                        else:
                            break

                    return res

                # str到头
                if i >= len(a):
                    res = ""
                    break

                if vv == ".":
                    res += a[i]
                    i += 1
                elif vv == "*":
                    while True:
                        if i >= len(a):
                            res = ""
                            break

                        if res[-1] == a[i]:
                            res += a[i]
                            i += 1
                        else:
                            break
                else:
                    if vv == a[i]:
                        res += a[i]
                        i += 1
                    else:
                        if pattern[j+1] == "*":
                            pass_flag = True
                        else:
                            res = ""
                            break
                            
        return res

24. 链表反转

class Solution(object):
    def main(self, a):
        if a is None or a.next is None:
            return a

        next = a.next
        a.next = None
        b = self.main(next)
        next.next = a

        return b

25. 礼物最大价值

class Solution(object):
    def main(self, m):
        r, c = m.shape

        if r * c == 0:
            return 0

        for i in range(r):
            for j in range(c):
                if i + j == 0:
                    continue

                if i == 0:
                    m[0, j] += m[0, j-1]
                elif j == 0:
                    m[i, 0] += m[i-1, 0]
                else:
                    m[i, j] += max(m[i, j-1], m[i-1, j])

        return m[r-1, c-1]

26. 和为n的所有连续正数列

class Solution(object):
    def main(self, m):
        res = []
        for i in range(1, m//2):
            s = 0
            j = i
            while True:
                if s < m:
                    s += i
                    i += 1
                else:
                    if s == m:
                        res.append([x for x in range(j, i)])
                    break

        return res

27. 去除字符串字符连续出现次数大于2的

# While每次都遍历一遍字符串消除连续出现次数大于2的,直到有一次遍历没问题则跳出
class Solution(object):
    def main(self, a):
        while True:
            checkpoint_v = ""
            checkpoint_i = 0
            counter = 0
            break_flag = True
            for v in a:
                if v == checkpoint_v:
                    counter += 1
                    continue

                if counter > 2:
                    a = a[:checkpoint_i] + a[checkpoint_i + counter:]
                    break_flag = False
                else:
                    checkpoint_i = checkpoint_i + counter

                checkpoint_v = v
                counter = 1

            if break_flag:
                break

        return a

28. 火柴拼成的数字,从一个数移动一根给另外一个数(只能移动一次),移动后最大值?

class Solution(object):
    def __init__(self):
        # 数字根数映射 & 根数对应最大数字映射
        self.counter = {"0":6, "1":2, "2":5, "3":5, "4":4, "5":5, "6":6, "7":3, "8":7, "9": 6}
        self.num_to_max_digit = {"2":"1", "3":"7", "4":"4", "5":"5", "6":"9", "7":"8"}

    def replace_char(self, s, v, idx):
        res = ""
        for i in range(len(s)):
            if i == idx:
                res += v
            else:
                res += s[i]
        return res

    def main(self, a):
        s = str(a)
        if len(s) <= 1:
            return a

        max_value = a
        for i in range(len(s)):
            give_ = s[i]

            if str(self.counter[give_] - 1) not in self.num_to_max_digit:
                continue

            give_after = self.num_to_max_digit[str(self.counter[give_] - 1)]
            b = self.replace_char(s, give_after, i)

            for j, receive_ in enumerate(b):
                if j == i:
                    continue

                if str(self.counter[receive_] + 1) not in self.num_to_max_digit:
                    continue

                receive_after = self.num_to_max_digit[str(self.counter[receive_] + 1)]
                c = self.replace_char(b, receive_after, j)
                if int(c) > max_value:
                    max_value = int(c)

        return max_value

29. 股票可以有一次买入和一次卖出,买入必须在前。求最大收益。

class Solution(object):
    def main(self, n):
        res = 0
        for i in range(1, len(n)):
            sell = n[i]
            buy = min(n[:i])
            profit = sell - buy
            if profit > res:
                res = profit

        return res

30. 圆圈中最后的小孩,n个小孩,第0个开始数到m,无放回出列,再从下一个开始数,最后小孩是都在时候第几个?

class Solution(object):
    def main(self, n, m):
        if n < 1:
            return -1

        children = [i for i in range(n)]
        start = 1
        while len(children) > 1:
            final = m + start - 1

            if final % len(children) == 0:
                children.pop(-1)
                start = 1
            else:
                start = final % len(children)
                children.pop(start - 1)

        return children[0]

31. n个筛子,求扔出去和为s的概率

class Solution(object):
    def main(self, n, s):
        if n == 1 and s <= 6:
            return 1
        elif (n == 1 and s > 6) or (s < n):
            return 0

        return self.main(n-1, s-1) + self.main(n-1, s-2) \
               + self.main(n-1, s-3) + self.main(n-1, s-4) \
               + self.main(n-1, s-5) + self.main(n-1, s-6)

    def result(self, n, s):
        res = self.main(n, s)

        return res/(6**n)

32. 滑动窗口最大值, 数组a,窗口大小为k

class Solution(object):
    def main(self, a, k):
        if k > len(a):
            return []

        res = []
        for i in range(0, len(a)-k+1):
            res.append(max(a[i:i+k]))

        return res

33. 和为s两个数字,有多组选积最小的

class Solution(object):
    def main(self, l, s):
        product = float('inf')
        j = len(l) - 1

        for i in range(len(l)):
            if j <= 0:
                break

            if l[i] + l[j] < s:
                continue
            elif l[i] + l[j] == s:
                p = l[i] * l[j]
                if p < product:
                    product = p
            else:
                j -= 1

        return product

34. 一个数组只出现过一次的数,其余均两次

class Solution(object):
    def main(self, a):
        res = 0
        for i in a:
            res ^= i

        return res

35. 有序数组指定数出现次数

class Solution(object):
    def main(self, a, v):
        l = 0
        r = len(a) - 1
        count = 0
        while l < r:
            m = r // 2
            if a[m] < v:
                l = m
            elif a[m] > v:
                r = m
            else:
                l = m-1
                r = m+1
                count += 1
                while True:
                    if (l < 0 and r >= len(a)) or (a[l] != v and a[r] != v):
                        break

                    if l >= 0 and a[l] == v:
                        count += 1
                        l -= 1
                    if r >= 0 and a[r] == v:
                        count += 1
                        r += 1
                break

        return count

36. 丑数

class Solution(object):
    def main(self, n):
        if n <= 6:
            return n

        i2, i3, i5 = 0, 0, 0
        res = [1]
        cur_num = 1
        while cur_num < n:
            min_value = min(res[i2]*2, res[i3]*3, res[i5]*5)
            res.append(min_value)
            while res[i2]*2 <= min_value:
                i2 += 1
            while res[i3]*3 <= min_value:
                i3 += 1
            while res[i5]*5 <= min_value:
                i5 += 1

            cur_num += 1

        return res[-1]

21。数字序列某一位数字

数字以123456789101112...格式序列化到一个字符序列中,求任意n位对应的数字,13位对应1

思想:前9位长度9,前99位长度2*(99-9)+9,前999位长度3*(999-99)+99

a = input()
b = int(a) 
if b <=9:
    print(n)
p = 9
lenn = 2
L = 9
i = 99
while(L<b):
    tem = L
    lenn1 = lenn
    p1 = p
    L = lenn*(i-p)+ L
    p = i
    i = i*10 + 9
    lenn = lenn+1

result = int((b-tem)/lenn1)+p1
if int((b-tem)%lenn1) == 0:
    result = result%10
else:
    chang = (b-tem)%lenn1
    tem1 = list(str(result+1))
    result = tem1[chang-1]
print(int(result))

 

22.找出数组中和为s的任意两数字

时间复杂度O(n*log2(n)+n)

# 堆排序或快排对a排序,时间复杂度O(N*log2(N))
def find(a,x):
    l= 0
    r = len(a)-1
    while(l < r):
        if a[l]+a[r] > x:
            r = r - 1
        if a[l]+a[r] < x:
            l = l + 1
        if a[l]+a[r] == x:
            return a[l],a[r]
            break

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章