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

 

 

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