LeetCode 51-70题

本博客记录的是 LeetCode 51 到 70 题的题解

之前很少使用的语法

string(n, '.')
INT_MIN, INT_MAX

// 58. Length of Last Word
stringstream ssin(s);
string word;
int res;
while (ssin >> word)    res = word.size();

// 60. Permutation Sequence
next_permutation(res.begin(), res.end());




# 51. N-Queens
ans.append([''.join(graph[i]) for i in range(n)])

# 58. Length of Last Word
len(s.rstrip().split(" ")[-1])


// 60. Permutation Sequence
res.append(str(nums.pop(tk // mod)))

# 63. Unique Paths II
f = [[0] * (m + 1) for i in range(n + 1)]   # 先 m 后 n
f[i][j] = (f[i - 1][j] if i + 1 else 0) + (f[i][j - 1] if j + 1 else 0)



51. N-Queens

挺简单的 N 皇后问题,主要是 三个维度进行打表,配合 DFS遍历行

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        cols = [False] * n
        diag = [False] * (2 * n + 10)
        anti_diag = [False] * (2 * n + 10)
        ans = []
        graph = [['.'] * n for i in range(n)]
        
        def dfs(cur):
            if cur == n:
                ans.append([''.join(graph[i]) for i in range(n)])
                return

            for i in range(n):
                if not cols[i] and not diag[cur - i + n] and not anti_diag[cur + i]:
                    cols[i] = diag[cur - i + n] = anti_diag[cur + i] = True 
                    graph[cur][i] = 'Q'
                    dfs(cur + 1)
                    graph[cur][i] = '.'
                    cols[i] = diag[cur - i + n] = anti_diag[cur + i] = False
        dfs(0)
        return ans

52. N-Queens II

和上一题一模一样,不过返回的数值不同,不必维护 graph 数组了

class Solution:
    def totalNQueens(self, n: int) -> int:
        cols = [False] * n
        diag = [False] * (2 * n + 10)
        anti_diag = [False] * (2 * n + 10)
        ans = [0]
        
        def dfs(cur):
            if cur == n:
                ans[0] += 1
                return

            for i in range(n):
                if not cols[i] and not diag[cur - i + n] and not anti_diag[cur + i]:
                    cols[i] = diag[cur - i + n] = anti_diag[cur + i] = True 
                    dfs(cur + 1)
                    cols[i] = diag[cur - i + n] = anti_diag[cur + i] = False
        dfs(0)
        return ans[0]

53. Maximum Subarray

本题其实对应两种做法,第一种是 O(N) 的DP,第二种是简化的线段树O(nlogn)

动态规划

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        last = res = int(-1e10)
        n = len(nums)
        for i in range(n):
            last = nums[i] + max(0, last)
            res = max(last, res)
        return res

线段树

没必要真正的开数组查询,这里我们仅仅只需要一次查询,所以说不需要把数组开出来。
就像是线段树中的 build函数,然后我们查询头结点的数值就可以得到结果

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        def get_max(l, r):
            if l == r:
                ret = [nums[l], nums[l], nums[l], nums[l]]
            else:
                mid = (l + r) // 2
                t1 = get_max(l, mid)
                t2 = get_max(mid + 1, r)
                ret = [max(max(t1[0], t2[0]), t1[2] + t2[1]), max(t1[1], t1[3] + t2[1]),
                        max(t2[2], t2[3] + t1[2]), t1[3] + t2[3]]
            return ret


        res = get_max(0, n - 1)
        return res[0]

54. Spiral Matrix

两个循环搞定,一个循环是改变方向,一个循环是沿着方向不断行走

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        n, m = len(matrix), len(matrix[0])
        st = [[False] * m for i in range(n)]
        def check(x, y):
            return x >= 0 and y >= 0 and x < n and y < m

        dx, dy = [0, 1, 0, -1], [1, 0, -1, 0]
        res = [matrix[0][0]]
        cx, cy = 0, 0
        st[0][0] = True
        
        cur_dir = -1
        while len(res) != n * m:
            cur_dir = (cur_dir + 1) % 4
            while check(cx + dx[cur_dir], cy + dy[cur_dir]) and not st[cx + dx[cur_dir]][cy + dy[cur_dir]]:
                cx, cy = cx + dx[cur_dir], cy + dy[cur_dir]
                st[cx][cy] = True
                res.append(matrix[cx][cy])

        return res

        

55. Jump Game

注意我们之前证明过的 JUMP GAME II 的单调性即可

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        n = len(nums)
        j = -1
        max_idx = 0
        while max_idx > j:
            i, j = j + 1, max_idx
            for k in range(i, j + 1):
                max_idx = max(max_idx, nums[k] + k)
            if max_idx >= n - 1:
                return True
        return False

更简洁的代码

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        n = len(nums)
        j = 0
        for i in range(n):
            if i > j:
                return False
            j = max(j, nums[i] + i)
        return True

56. Merge Intervals

较为简单的区间合并问题,主要是通过端点排序,然后进行贪心处理

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort(key=lambda x: [x[0], x[1]])
        res = []
        n = len(intervals)
        pre_start = 0
        max_end = -1e9
        for i in range(n):
            if intervals[i][0] <= max_end:
                max_end = max(max_end, intervals[i][1])
            else:
                if pre_start <= max_end:
                    res.append([pre_start, max_end])
                pre_start = intervals[i][0]
                max_end = intervals[i][1]
        res.append([pre_start, max_end])

        return res

57. Insert Interval

和上一题类似,不过是需要自己插入排序一下

class Solution:
    def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
        n = len(intervals)
        if n == 0 or newInterval[0] > intervals[-1][0]:
            intervals.append(newInterval)
        else:
            for i in range(n):
                if intervals[i][0] >= newInterval[0]:
                    intervals.insert(i, newInterval)
                    break
        
        n += 1
        pre_start, max_end = 0, -1e9
        res = []
        for i in range(n):
            if intervals[i][0] <= max_end:
                max_end = max(max_end, intervals[i][1])
            else:
                if pre_start <= max_end:
                    res.append([pre_start, max_end])
                pre_start, max_end = intervals[i][0], intervals[i][1]
        res.append([pre_start, max_end])
        return res

仔细读题发现 intervals没有交集,因此我们可以将 intervals 不和 newInterval 重叠的部分放入到 res中,计算中间重叠部分的最早起点和最晚终点即可;

class Solution:
    def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
        n = len(intervals)
        res = []
        
        k = 0
        while k < n and intervals[k][1] < newInterval[0]:
            res.append(intervals[k])
            k += 1

        pre_start, max_end = newInterval[0], newInterval[1]
        while k < n and intervals[k][0] <= max_end:
            pre_start = min(pre_start, intervals[k][0])
            max_end = max(max_end, intervals[k][1])
            k += 1
        res.append([pre_start, max_end])

        while k < n:
            res.append(intervals[k])
            k += 1

        return res

58. Length of Last Word

简单的模拟题

class Solution:
    def lengthOfLastWord(self, s: str) -> int:
        n, cnt = len(s), 0
        for i in range(n - 1, -1, -1):
            if s[i] == ' ' and cnt != 0:
                break
            cnt = cnt + 1 if s[i] != ' ' else cnt
        return cnt
class Solution:
    def lengthOfLastWord(self, s: str) -> int:
        return len(s.rstrip().split(" ")[-1])

有点意思的C++语法

class Solution {
public:
    int lengthOfLastWord(string s) {
        stringstream ssin(s);
        int res = 0;
        string word;
        while (ssin >> word)    res = word.size();
        return res;
    }
};

59. Spiral Matrix II

最方便的就是使用数组打表

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        dx, dy = [0, 1, 0, -1], [1, 0, -1, 0]
        cur_dir = 0
        st = [[False] * n for i in range(n)]
        res = [[-1] * n for i in range(n)]
        cx, cy = 0, 0
        for i in range(n * n):
            st[cx][cy] = True
            res[cx][cy] = i + 1
            nx, ny = cx + dx[cur_dir], cy + dy[cur_dir]
            if nx < 0 or nx >= n or ny < 0 or ny >= n or st[nx][ny]:
                cur_dir = (cur_dir + 1) % 4
                nx, ny = cx + dx[cur_dir], cy + dy[cur_dir]
            cx, cy = nx, ny
        return res

60. Permutation Sequence

寻找排列组合的规律即可
每一个位置上,他往后的位置对应的组合数量。

class Solution:
    def getPermutation(self, n: int, k: int) -> str:
        res = []
        st = [False] * 11
        order = [-1 for i in range(11)]
        tk = k - 1
        mod = 2
        for i in range(n - 2, -1, -1):
            order[i] = tk % mod
            tk //= mod
            mod += 1
        order[n - 1] = 0


        for i in range(n):
            cnt = 0
            for j in range(1, n + 1):
                if not st[j]:
                    if cnt == order[i]:
                        res.append(str(j))
                        st[j] = True
                        break
                    else:
                        cnt += 1
            
        return ''.join(res)

更为简洁的代码

class Solution:
    def getPermutation(self, n: int, k: int) -> str:
        res = []
        nums = list(range(1, n + 1))
        tk = k - 1
        for i in range(n):
            mod = 1
            for j in range(i + 1, n):
                mod *= (j - i)
            res.append(str(nums.pop(tk // mod)))
            tk %= mod
            
        return ''.join(res)

61. Rotate List

链表模拟,头尾相接后,查找新的头和尾

# Definition for singly-linked list.
# 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:
            return head
        t, n = head, 0
        end = None
        while t:
            n += 1
            if not t.next:
                end = t
            t = t.next
        k %= n
        end.next = head

        t = head
        for i in range(0, n - 1 - k):
            t = t.next
        head = t.next
        t.next = None
        return head

62. Unique Paths

dp 求解组合数

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        # C(m + n - 2, m - 1)
        # C(x, y) = C(x - 1, y) + C(x - 1, y - 1)
        x, y = m + n - 2, min(m - 1, n - 1)
        f = [[0] * (m + n + 1)  for i in range(m + n + 1)]
        f[0][0] = 1
        for i in range(1, x + 1):
            for j in range(x + 1):
                f[i][j] = f[i - 1][j] + (f[i - 1][j - 1] if j else 0)
        return f[x][y]
        

python 的大整数

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        # C(m + n - 2, m - 1)
        x, y = m + n - 2, min(m - 1, n - 1)
        fenmu, fenzi = 1, 1
        for i in range(1, y + 1):
            fenmu *= i
            fenzi *= (x - i + 1)
        return fenzi // fenmu
        

63. Unique Paths II

class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        n, m = len(obstacleGrid), len(obstacleGrid[0])
        f = [[0] * (m + 1) for i in range(n + 1)]   # 先 m 后 n
        f[0][0] = 1
        for i in range(n):
            for j in range(m):
                if obstacleGrid[i][j]:
                    f[i][j] = 0
                elif not (i == 0 and j == 0):
                    f[i][j] = (f[i - 1][j] if i + 1 else 0) + (f[i][j - 1] if j + 1 else 0)

        return f[n - 1][m - 1]

64. Minimum Path Sum

简单 DP

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        n, m = len(grid), len(grid[0])
        f = [[400001010] * (m + 1) for i in range(n + 1)]
        f[0][0] = grid[0][0]
        for i in range(n):
            for j in range(m):
                if not (i == 0 and j == 0):
                    f[i][j] = grid[i][j] + min(f[i - 1][j] if i + 1 else 101010100, 
                                               f[i][j - 1] if j + 1 else 101010100)
        return f[n - 1][m - 1]
        

65. Valid Number

主要是学会写函数模块,重复利用起来就好

class Solution:
    def check_integer(self, s:str) -> bool:
        if not s:
            return False
        return self.check_digits(s[1:]) if s[0] == '+' or s[0] == '-' else self.check_digits(s) 

    def check_digits(self, s: str) -> bool:
        if not s:
            return False
        for i in range(len(s)):
            if '0' <= s[i] <= '9':
                continue
            return False
        return True
  
    def check_decimal_number(self, s: str) -> bool:
        if not s:
            return False
        s = s[1:] if s[0] == '+' or s[0] == '-' else s
        
        n, pos = len(s), -1
        for i in range(n):
            if s[i] == '.':
                pos = i
                break
        if pos == -1:
            return False
        if pos == 0:
            return self.check_digits(s[1:])
        elif pos == n - 1:
            return self.check_digits(s[:-1])
        else:
            return self.check_digits(s[:pos]) and self.check_digits(s[pos+1:])
        

    def isNumber(self, s: str) -> bool:
        if not s:
            return False
        pos = -1
        for i in range(len(s)):
            if s[i] == 'e' or s[i] == 'E':
                pos = i
                break
        
        if pos != -1:
            return (self.check_decimal_number(s[:pos]) or self.check_integer(s[:pos])) \
                and self.check_integer(s[pos + 1:])
        else:
            return self.check_integer(s) or self.check_decimal_number(s)

66. Plus One

简单模拟即可, O(n)复杂度

class Solution:
    def plusOne(self, digits: List[int]) -> List[int]:
        n = len(digits)
        digits[-1] += 1
        k = n - 1
        while digits[k] > 9:
            digits[k] = 0
            k -= 1
            if k < 0:
                k = 0
                digits.insert(0, 0)
            digits[k] += 1
        return digits

67. Add Binary

模拟按位加法就可以

class Solution:
    def addBinary(self, a: str, b: str) -> str:
        a = a[::-1]
        b = b[::-1]
        n, m = len(a), len(b)
        if n < m:
            a, b = b, a
            n, m = m, n
        
        t = 0
        res = ""
        for i in range(n):
            t += int(a[i])
            if i < m:
                t += int(b[i])
            res += str(t % 2)
            t //= 2
        if t:
            res += str(t)
        return res[::-1]

68. Text Justification

简单的模拟题

class Solution:
    def fullJustify(self, words: List[str], maxWidth: int) -> List[str]:
        n = len(words)
        i = 0
        res = []
        while i < n:
            s = ''
            # st - ed 为双指针范围  
            st = i
            len_cnt = len(words[i])
            ed = i + 1
            while ed < n and len_cnt + len(words[ed]) + 1 <= maxWidth:
                len_cnt += len(words[ed]) + 1
                ed += 1

            # st --> ed - 1 为字符串范围,刚好 ed 我下一个 i 的位置
            # 下面我们分配字符串
            word_cnt = ed - st
            if ed != n:
                if word_cnt == 1:
                    s = words[st] + (maxWidth - len_cnt) * ' '
                else:
                    s = words[st]
                    len_cnt -= (word_cnt - 1)
                    for j in range(st + 1, ed):
                        if j - st <=  (maxWidth - len_cnt) % (word_cnt - 1):
                            s += ' '
                        s += ' ' * ((maxWidth - len_cnt) // (word_cnt - 1)) + words[j]
            else:
                len_cnt = len(words[st])
                s = words[st]
                for j in range(st + 1, ed):
                    s += ' ' + words[j]
                    len_cnt += len(words[j]) + 1
                s += (maxWidth - len_cnt) * ' '
            i = ed
            res.append(s)
        return res

69. Sqrt(x)

简单二分题目

class Solution:
    def mySqrt(self, target: int) -> int:
        # 二分 x ** 2 <= target 的最大值
        l, r = 0, 100010
        while l < r:
            mid = (l + r + 1) // 2
            if mid * mid <= target:
                l = mid
            else:
                r = mid - 1
        return l

70. Climbing Stairs

斐波那契额数列做法很多

  1. dp 模拟
  2. 快速幂
  3. 数学公式

dp

# f[n] = f[n - 1] + f[n - 2]
class Solution:
    def climbStairs(self, n: int) -> int:
        a, b = 1, 1
        if n == 0 or n == 1:
            return 1
        else:
            for i in range(2, n + 1):
                c = a + b
                a, b = b, c
            return c

矩阵快速幂

快速幂推导图示

# 2. 快速幂
class Solution:
    def mult(self, A, B):
        T = [[0, 0], [0, 0]]
        for i in range(2):
            for j in range(2):
                for k in range(2):
                    T[i][j] += A[i][k] * B[k][j]
        return T.copy()
    
    def climbStairs(self, n: int) -> int:
        if n == 0 or n == 1:
            return 1
        t = n - 1
        B = [[1, 1], [1, 0]]
        C = [[1, 0], [0, 1]]    # 单位矩阵,快速幂结束后为 B^(n-1)
        while t:
            if t % 2 == 1:
                C = self.mult(B, C)
            B = self.mult(B, B)
            t //= 2
        A = [[1, 1], [0, 0]]
        C = self.mult(A, C)
        return C[0][0]
            

数学公式


但是当 n 很大时候,可能会出现精度问题

# 数学公式
class Solution:
    def qmi(self, x, y):
        res = 1.0
        while y:
            if y % 2 == 1:
                res *= x
            x *= x
            y //= 2
        return res

    
    def climbStairs(self, n: int) -> int:
        if n == 0 or n == 1:
            return 1
        n += 1
        t = 5 ** 0.5
        return round((self.qmi((1 + t) / 2, n) - self.qmi((1 - t) / 2, n)) / t)
posted @ 2022-01-09 15:06  lucky_light  阅读(51)  评论(0编辑  收藏  举报