"The Road to Algorithm Clearance"-Chapter19 Comprehension

"The Road to Algorithm Passing" study notes, record your own process of solving questions, please purchase the author's book for detailed content.

Circular shift problem

Rotate array

Question 189:
Given an integer array nums, rotate the elements in the array k positions to the right, where k is a non-negative number.

'''
方法一:复制相同的数组

时间复杂度:O(n)
空间复杂度:O(n)
'''

class Solution:
    def rotate(self, nums: list[int], k: int) -> None:

        copy = nums.copy()
        n = len(nums)

        for i in range(n):
            nums[(k+i)%n] = copy[i]

nums, k = [1,2,3,4,5,6,7], 3
print(nums)
solu = Solution()
solu.rotate(nums, k)
print(nums)
[1, 2, 3, 4, 5, 6, 7]
[5, 6, 7, 1, 2, 3, 4]
'''
方法二:时间换空间(超时)

时间复杂度:O(nk)
空间复杂度:O(1)
'''

class Solution:
    def rotate(self, nums: list[int], k: int) -> None:

        n = len(nums)
        t = None
        offset = n - k % n # 右移变左移
        if offset == 0:
            return
        while offset:
            t = nums[0]
            offset -= 1
            for i in range(n-1):
                nums[i] = nums[i+1]
            nums[n-1] = t

nums, k = [1,2,3,4,5,6,7], 3
print(nums)
solu = Solution()
solu.rotate(nums, k)
print(nums)
[1, 2, 3, 4, 5, 6, 7]
[5, 6, 7, 1, 2, 3, 4]
'''
方法三:空间换时间(不符合题意)

时间复杂度:O(n)
空间复杂度:O(n)
'''

class Solution:
    def rotate(self, nums: list[int], k: int) -> None:

        n = len(nums)
        offset = k % n
        nums = nums + nums.copy()
        return nums[n - offset : n * 2 - offset]

nums, k = [1,2,3,4,5,6,7], 3
print(nums)
solu = Solution()
solu.rotate(nums, k)
[1, 2, 3, 4, 5, 6, 7]
[5, 6, 7, 1, 2, 3, 4]
'''
方法四:利用python迭代器

时间复杂度:O(k)
空间复杂度:O(1)
'''

class Solution:
    def rotate(self, nums: list[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        for i in range(0, -k, -1):
            nums.insert(0,nums.pop())

nums, k = [1,2,3,4,5,6,7], 3
print(nums)
solu = Solution()
solu.rotate(nums, k)
print(nums)
[1, 2, 3, 4, 5, 6, 7]
[5, 6, 7, 1, 2, 3, 4]
'''
方法五:三次翻转法

时间复杂度:O(k)
空间复杂度:O(1)
'''

class Solution:
    def rotate(self, nums: list[int], k: int) -> None:

        def reverse(list: list[int], start: int, end: int) -> None:
            
            while start < end:
                t = list[start]
                list[start] = list[end]
                list[end] = t
                start += 1
                end -= 1
        
        n = len(nums)
        offset = k % n
        if offset == 0:
            return

        reverse(nums, 0, n - offset - 1)
        reverse(nums, n - offset, n - 1)
        reverse(nums, 0, n - 1)

nums, k = [1,2,3,4,5,6,7], 3
print(nums)
solu = Solution()
solu.rotate(nums, k)
print(nums)
[1, 2, 3, 4, 5, 6, 7]
[5, 6, 7, 1, 2, 3, 4]

rotating linked list

Likou Question 61:
You are given the head node of a linked list, rotate the linked list, and move each node of the linked list k positions to the right.

'''
方法一:右移变左移

时间复杂度:O(n)
空间复杂度:O(1)
'''

from typing import Optional

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
        
class Solution:
    def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:

        if not head or k == 0 or not head.next:
            return head

        p1 = head
        res = None
        n = 1

        while p1 and p1.next:
            p1 = p1.next
            n += 1
        
        cur  = 1 # 通过cur计数来寻找断点
        p2 = head
        while cur < n - k % n:
            p2 = p2.next
            cur += 1
        
        p1.next = head
        res = p2.next
        p2.next = None

        return res

edit distance

edit distance

Question 72:
Given two words, word1 and word2, please return the minimum number of operations used to convert word1 into word2.
You can perform the following three operations on a word:
insert a character,
delete a character,
replace a character

'''
方法一:记忆化递归

空间复杂度:O(mn)
'''

class Solution:
    def minDistance(self, s1: str, s2: str) -> int:

        def find_min(s1, i, s2, j, memo):
            if i == -1:
                return j + 1
            if j == -1:
                return i + 1

            if memo[i][j] != -1:
                return memo[i][j]

            if s1[i] == s2[j]:
                memo[i][j] = find_min(s1, i - 1, s2, j - 1, memo)
            else:
                memo[i][j] = min(
                    find_min(s1, i, s2, j - 1, memo) + 1,  # 插入
                    find_min(s1, i - 1, s2, j, memo) + 1,  # 删除
                    find_min(s1, i - 1, s2, j - 1, memo) + 1  # 替换
                )
            return memo[i][j]

        m, n = len(s1), len(s2)
        memo = [[-1] * n for _ in range(m)]
        res = find_min(s1, m - 1, s2, n - 1, memo)
        return res

word1, word2 = "horse", "ros"
solu = Solution()
solu.minDistance(word1, word2)
3
'''
方法二:动态规划

时间复杂度:O(mn)
空间复杂度:O(mn)
'''

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:

        m, n = len(word1), len(word2)

        # dp[i][j]表示字符串word[:i]和word[:j]的最小编辑距离
        dp = [[0 for j in range(n + 1)] for i in range(m + 1)]

        for i in range(1, m + 1):
            dp[i][0] = i
        for j in range(1, n + 1):
            dp[0][j] = j
        
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if word1[i - 1] == word2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1]
                else:
                    dp[i][j] = min(dp[i - 1][j - 1], dp[i][j - 1], dp[i - 1][j]) + 1
        
        return dp[m][n]

word1, word2 = "horse", "ros"
solu = Solution()
solu.minDistance(word1, word2)
3
'''
方法三:动态规划(空间优化)

时间复杂度:O(mn)
空间复杂度:O(n)
'''

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:

        m, n = len(word1), len(word2)
        pre, cur = [0] * (n + 1), [0] * (n + 1)

        for i in range(1, n + 1):
            pre[i] = i
        for i in range(1, m + 1):
            cur[0] = i
            for j in range(1, n + 1):
                if word1[i - 1] == word2[j - 1]:
                    cur[j] = pre[j - 1]
                else:
                    cur[j] = min(pre[j], pre[j - 1], cur[j - 1]) + 1
            pre = cur.copy()
        
        return pre[n] # 解决没有进入循环的情况

word1, word2 = "horse", "ros"
solu = Solution()
solu.minDistance(word1, word2)
3
'''
方法四:动态规划(继续优化空间)

时间复杂度:O(mn)
空间复杂度:O(n)
'''

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:

        m, n = len(word1), len(word2)
        cur = [0] * (n + 1)
        pre = None

        for i in range(1, n + 1):
            cur[i] = i
        for i in range(1, m + 1):
            pre = cur[0]
            cur[0] = i
            for j in range(1, n + 1):
                tmp = cur[j]
                if word1[i - 1] == word2[j - 1]:
                    cur[j] = pre
                else:
                    cur[j] = min(cur[j], cur[j - 1], pre) + 1
                pre = tmp
        
        return cur[n]

word1, word2 = "horse", "ros"
solu = Solution()
solu.minDistance(word1, word2)
3

kth question

The Kth largest element in the array

Question 215:
Given an integer array nums and an integer k, please return the kth largest element in the array.

Please note that you need to find the k-th largest element in the sorted array, not the k-th distinct element.

You must design and implement an algorithm with time complexity O(n) to solve this problem.

'''
方法一:堆排序(调包)

时间复杂度:O(nlogk)
空间复杂度:O(k)
'''

from heapq import nlargest

class Solution:
    def findKthLargest(self, nums: list[int], k: int) -> int:

        # [3,2,1,5,6,4]
        # [6, 5]
        
        return nlargest(k, nums)[-1] 

nums, k = [3,2,1,5,6,4], 2
solu = Solution()
solu.findKthLargest(nums, k)
5

For other solutions, please refer to:
"The Road to Algorithm Clearance" - Chapter 13 Divide and Conquer Method

The Kth largest element in the data stream

Focus on question 703.
Design a class that finds the k-th largest element in the data stream. Note that it is the k-th largest element after sorting, not the k-th different element.

Please implement the KthLargest class:

KthLargest(int k, int[] nums) Initializes an object with an integer k and an integer stream nums.
int add(int val) After inserting val into the data stream nums, return the k-th largest element in the current data stream.

'''
方法一:堆排序(调包)

时间复杂度:O(nlogk)
空间复杂度:O(k)
'''

import heapq

class KthLargest:

    def __init__(self, k: int, nums: list[int]):

        # len(nums) >= k-1,通过加一个元素保证查找k大元素时,数组中至少有k个元素
        self.nums = heapq.nlargest(k, nums + [float('-inf')])
        self.k = k
        heapq.heapify(self.nums)

    def add(self, val: int) -> int:
        heapq.heappushpop(self.nums, val)
        return self.nums[0]

kth_largest =  KthLargest(3, [4, 5, 8, 2])
kth_largest.add(3)   # return 4
kth_largest.add(5)   # return 5
kth_largest.add(10)  # return 5
kth_largest.add(9)   # return 8
kth_largest.add(4)   # return 8
8

Kth smallest element in binary search tree

Question 230:
Given the root node root of a binary search tree and an integer k, please design an algorithm to find the k-th smallest element (counting from 1).

'''
方法一:二分查找

时间复杂度:O(n),最坏O(n2)
空间复杂度:O(n),最坏O(n2)
'''

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        
        # 返回该节点及所有子节点的个数
        def countNodes(node) -> int:
            if node == None:
                return 0
            l = countNodes(node.left)
            r = countNodes(node.right)
            return l + r + 1

        cnt = countNodes(root.left)
        if cnt == k - 1:
            return root.val
        elif cnt > k - 1:
            return self.kthSmallest(root.left, k)
        
        return self.kthSmallest(root.right, k - cnt - 1)

The Kth smallest element in the ordered matrix

Question 378:
Given an nxn matrix matrix, in which the elements in each row and column are sorted in ascending order, find the kth smallest element in the matrix.
Note that it is the kth smallest element after sorting, not the kth distinct element.

You have to find a solution with memory complexity better than O(n2).

'''
方法一:二分查找

时间复杂度:O(nlog(hi-lo))
空间复杂度:O(1)
'''

class Solution:
    def kthSmallest(self, matrix: list[list[int]], k: int) -> int:

        n = len(matrix)
        lo, hi = matrix[0][0], matrix[n - 1][n - 1]

        def countNotGreater(target: int) -> int:
            
            i, j = 0, n - 1
            cnt = 0
            while i < n and j >= 0:
                if matrix[i][j] <= target:
                    cnt += j + 1
                    i += 1
                else:
                    j -= 1
            return cnt
        
        while lo < hi:
            mid = (lo + hi) // 2
            cnt = countNotGreater(mid)

            if cnt < k:
                lo = mid + 1
            else:
                hi = mid
        
        return lo

matrix, k = [[1,5,9],[10,11,13],[12,13,15]], 8
solu = Solution()
solu.kthSmallest(matrix, k)
13

The kth smallest number in the multiplication table

Close question 668:
Almost everyone uses the multiplication table. But can you quickly find the kth smallest number in the multiplication table?

'''
方法一:二分查找

时间复杂度:O(mlogmn)
空间复杂度:O(1)
'''

class Solution:
    def findKthNumber(self, m: int, n: int, k: int) -> int:
        
        lo, hi = 1, m * n

        def countNotGreater(mid: int, m: int, n: int) -> int:
            
            cnt = 0
            for i in range(1, m + 1):
                cnt += min(mid // i, n)
                
            return cnt
        
        while lo < hi:
            mid = (lo + hi) // 2
            if countNotGreater(mid, m, n) < k:
                lo = mid + 1
            else:
                hi = mid
        
        return lo

m, n, k = 3, 3, 5
solu = Solution()
solu.findKthNumber(m, n, k)
3

Guess you like

Origin blog.csdn.net/cjw838982809/article/details/133357511