51. N-Queens
The n-queens puzzle is the problem of placing n
queens on an n x n
chessboard such that no two queens attack each other.
Given an integer n
, return all distinct solutions to the n-queens puzzle. You may return the answer in any order.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q'
and '.'
both indicate a queen and an empty space, respectively.
Example 1:
Input: n = 4
Output: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above
Example 2:
Input: n = 1
Output: [["Q"]]
题意的要求简单来说就是在一个8*8的棋盘上摆上8个棋子,使它们不在同一行、同一列、同一斜线上。这题是一个很经典的问题。难点在问题的描述。这里我们使用一个数组board,board中元素下标代表第几行,元素值board[i]代表第i行Queen摆放的位置。下面来看这三个约束条件:
1.不同行:这个自然满足,数组board下标不同
2不同列:这个只要使board中各元素值不相同就行了。即board[i]!=board[j]
3.不同斜线:这个只要使board中元素相应的横纵坐标差的绝对值不等就行了。即|board[i]-board[j]|!=|i-j|
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
board_list = []
# place n queens on an n x n chessboard
def dfs( each_row_queen_position, diagonal_asc, diagonal_desc ):
# number of queens
if len( each_row_queen_position ) == n: # the number of queens is equal to n
board = [ '.' * q_idx + 'Q' + '.' * (n-1-q_idx)
for q_idx in each_row_queen_position
]
board_list.append( board )
return
# else the number of queens is not enough(<n)
# Layout row by row
cur_row_idx = len( each_row_queen_position ) # The row currently to be laid out
# Note, only can put 1 Queen on diagonal ascending, '/'
# cur_row_idx + col_idx == n-1 since idx start from 0 to n-1
# 1 Queen on diagonal descending, '\'
# cur_row_idx - col_idx == 0
for col_idx in range(n):
if col_idx in each_row_queen_position or cur_row_idx + col_idx in diagonal_asc or cur_row_idx - col_idx in diagonal_desc:
continue
else:
dfs( each_row_queen_position + [col_idx],
diagonal_asc + [cur_row_idx + col_idx],
diagonal_desc + [cur_row_idx - col_idx],
)
dfs( [], [], [] )
return board_list
52. N-Queens II
The n-queens puzzle is the problem of placing n
queens on an n x n
chessboard such that no two queens attack each other.
Given an integer n
, return the number of distinct solutions to the n-queens puzzle.
Example 1:
Input: n = 4
Output: 2
Explanation: There are two distinct solutions to the 4-queens puzzle as shown.
Example 2:
Input: n = 1
Output: 1
class Solution:
def totalNQueens(self, n: int) -> int:
self.number_of_solutions = 0
# place n queens on an n x n chessboard
def dfs( each_row_queen_position, diagonal_asc, diagonal_desc ):
if len( each_row_queen_position ) == n: # the number of queens is equal to n
self.number_of_solutions +=1
return
# else the number of queens is not enough(<n)
# Layout row by row
cur_row_idx = len( each_row_queen_position )
# Note, only can put 1 Queen on diagonal ascending, '/'
# cur_row_idx + col_idx == n-1 since idx start from 0 to n-1
# 1 Queen on diagonal descending, '\'
# cur_row_idx - col_idx == 0
for col_idx in range(n):
if col_idx in each_row_queen_position or cur_row_idx+col_idx in diagonal_asc or cur_row_idx-col_idx in diagonal_desc:
continue
else:
dfs( each_row_queen_position+[col_idx], diagonal_asc+[cur_row_idx+col_idx], diagonal_desc+[cur_row_idx-col_idx] )
dfs([],[],[])
return self.number_of_solutions
53. Maximum Subarray
Given an integer array nums
, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example 1:
Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Example 2:
Input: nums = [1]
Output: 1
Example 3:
Input: nums = [5,4,-1,7,8]
Output: 23
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
# As long as the previous number is positive, add it to the current value
for i in range( 1, len(nums) ):
if nums[i-1] > 0:
nums[i] += nums[i-1]
return max(nums)
54. Spiral Matrix螺旋矩阵
Given an m x n
matrix
, return all elements of the matrix
in spiral order.
Example 1:
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [1,2,3,6,9,8,7,4,5]
while loop:
- # step1. matrix.pop(0) ==> [1, 2, 3]
- # step2. *matrix ==> [4, 5, 6] [7, 8, 9] # two lists
- # step3. list( zip(*matrix) ) ==> [ (4, 7), (5, 8), (6, 9) ]
- # step4. list( zip(*matrix) )[::-1] ==> [(6, 9), (5, 8), (4, 7)]
Example 2:
Input: matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
Output: [1,2,3,4,8,12,11,10,9,5,6,7]
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
result = []
while matrix:
result += matrix.pop(0) # ==> [1, 2, 3]
# matrix = list( zip(*matrix) )[::-1]
matrix = [ *zip(*matrix) ][::-1]
return result
OR
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
# matrix: [[1,2,3],[4,5,6],[7,8,9]]
# step1. matrix.pop(0) ==> [1, 2, 3]
# step2. *matrix ==> [4, 5, 6] [7, 8, 9] # two lists
# step3. list( zip(*matrix) ) ==> [ (4, 7), (5, 8), (6, 9) ]
# for i in map( list, zip(*matrix) ):
# print(i)
# output:
# [4, 7]
# [5, 8]
# [6, 9]
# why use list?
# since zip(*matrix)[::-1] and the 'zip' object( (4, 7) (5, 8) (6, 9) ) is not subscriptable
# step4. list( zip(*matrix) )[::-1] ==> [(6, 9), (5, 8), (4, 7)]
# OR [ *zip(*matrix) ][::-1]
# step5. self.spiralOrder( list(zip(*matrix))[::-1] )
# step1. matrix.pop(0) ==> (6,9) so [*matrix.pop(0)]
# while matrix is not None
# return matrix and [ *matrix.pop(0) ] + self.spiralOrder( [*zip(*matrix)][::-1] )
# OR
return matrix and [*matrix.pop(0)]+ self.spiralOrder( list( zip(*matrix) )[::-1] )
55. Jump Game
(45. Jump Game II
https://blog.csdn.net/Linli522362242/article/details/118349075)
Given an array of non-negative integers nums
, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
Example 1:
Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:
Input: nums = [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.
class Solution:
def canJump(self, nums: List[int]) -> bool:
# 1 <= nums.length <= 10^4
if len(nums) ==1:
return True # we don't need to jump since it is the last index
# nums[i]: maximum jump length at the position index i
# i+nums[i]: current postion index + maximum jump length at the position index i == > current_farthest_postion_index
# Assuming the previous farthest postion index = -1
# the search range should be 0 = -1 + 1
left_index = 0 # index of the current position starting from the left
current_farthest_position_index= nums[0] # = left_index + nums[left_index] = 0+nums[0]
# steps = 1
while current_farthest_position_index < len(nums)-1:
# Breadth First Search
next_farthest_postion_index = max( i+nums[i] for i in range(left_index,
current_farthest_position_index +1)
)
# steps+=1
left_index = current_farthest_position_index+1
current_farthest_position_index = next_farthest_postion_index
if left_index > current_farthest_position_index: # added
return False
return True # return steps
56. Merge Intervals
Given an array of intervals
where intervals[i] = [starti, endi]
, merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.
Example 1:
Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
Example 2:
Input: intervals = [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considered overlapping.
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
# less memory
# 1 <= intervals.length <= 10^4
if len(intervals) ==1:
return intervals
i=1
intervals.sort()
while i< len(intervals):
if intervals[i-1][-1] >= intervals[i][0]:
intervals[i-1][-1] = max( intervals[i-1][-1] , intervals.pop(i)[-1] )# intervals[i][-1] )
# del intervals[i]
continue
else:
i+=1
return intervals
OR
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
# less memory
# # 1 <= intervals.length <= 10^4
# if len(intervals) ==1:
# return intervals
# i=1
# intervals.sort()
# while i< len(intervals):
# if intervals[i-1][-1] >= intervals[i][0]:
# intervals[i-1][-1] = max( intervals[i-1][-1] , intervals.pop(i)[-1] )# intervals[i][-1] )
# # del intervals[i]
# continue
# else:
# i+=1
# return intervals
# faster
merged_intervals=[]
for interval in sorted( intervals ):
if merged_intervals and merged_intervals[-1][-1] >= interval[0]:
# why use max? since [[1,4],[2,3]] expects [[1,4]]
merged_intervals[-1][-1] = max(merged_intervals[-1][-1], interval[-1])
else:
merged_intervals.append( interval )
return merged_intervals
57. Insert Interval
Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).
You may assume that the intervals were initially sorted according to their start times.
Example 1:
Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]
Example 2:
Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8] Output: [[1,2],[3,10],[12,16]] Explanation: Because the new interval[4,8]
overlaps with[3,5],[6,7],[8,10]
.
Example 3:
Input: intervals = [], newInterval = [5,7]
Output: [[5,7]]
Example 4:
Input: intervals = [[1,5]], newInterval = [2,3]
Output: [[1,5]]
Example 5:
Input: intervals = [[1,5]], newInterval = [2,7]
Output: [[1,7]]
class Solution:
def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
# 0 <= intervals.length <= 10^4
left_part = []
right_part = []
for interval in intervals:
if interval[-1]< newInterval[0]:
# left_part+=[interval]
left_part.append(interval)
elif newInterval[-1]<interval[0]:
# right_part+=[interval]
right_part.append(interval)
else:
newInterval[0] = min(interval[0], newInterval[0])
newInterval[-1] = max(interval[-1], newInterval[-1])
return left_part + [newInterval] + right_part
58. Length of Last Word
Given a string s
consists of some words separated by spaces, return the length of the last word in the string. If the last word does not exist, return 0
.
A word is a maximal substring consisting of non-space characters only.
Example 1:
Input: s = "Hello World"
Output: 5
Example 2:
Input: s = " "
Output: 0
class Solution:
def lengthOfLastWord(self, s: str) -> int:
# " " ==> s.split() ==> []
t = s.split() # Delimiter default: spaces, newlines (\n), tabs (\t), etc.
if len(t)==0:
return 0
else:
return len( t[-1] )
OR
class Solution:
def lengthOfLastWord(self, s: str) -> int:
# " " ==> s.split() ==> []
# t = s.split() # Delimiter default: spaces, newlines (\n), tabs (\t), etc.
# if len(t)==0:
# return 0
# else:
# return len( t[-1] )
# less space
# " " ==> s.split(' ') ==> ['', '']
# " " ==> len( s.split(' ')[-1] ) ==> 0
# note: 'a ' ==> s.split(' ') ==> ['a', ''] but expected return 1
# so we have to use s.strip() first
return len( s.strip().split(' ')[-1] )
59. Spiral Matrix II
Given a positive integer n
, generate an n x n
matrix
filled with elements from 1
to n^2
in spiral order.
Example 1:
<==range(1,4)=
+list( zip(*mat[::-1]) ) and mat=[[4, 5], (9, 6), (8, 7)]
# [[9]]
# [[8]]+[(9,)] ==> [[8], (9,)]
# [[6, 7]] + [(9, 8)] ==> [[6, 7], (9, 8)]
# [[4, 5]] + [(9, 6), (8, 7)] ==> [[4, 5], (9, 6), (8, 7)]
# [[1, 2, 3]] + [(8, 9, 4), (7, 6, 5)] ==> [[1, 2, 3], (8, 9, 4), (7, 6, 5)]
Input: n = 3
Output: [[1,2,3],[8,9,4],[7,6,5]]
Example 2:
Input: n = 1
Output: [[1]]
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
mat = [[n*n]]
lo = n*n # [0, n*n+1)
while lo>1:
# print( mat )
lo, hi = lo-len(mat), lo
# list() can generate a range to a list of number, or convert tuple to a list
# print(*mat)
# e.g. [[8], (9,)] ==> *mat ==> [8] (9,)
# ==> *mat[::-1] ==> (9,) [8]
# ==> list( zip( *mat[::-1] ) ) ==> [(9,8)]
mat = [ list( range(lo, hi) ) ] + list( zip(*mat[::-1]) )
# OR # * to unpack a tuple then put its elements in a list
# mat = [ list( range(lo, hi) ) ] + [ *zip( *mat[::-1] ) ]
# [[9]]
# [[8]]+[(9,)] ==> [[8], (9,)]
# [[6, 7]] + [(9, 8)] ==> [[6, 7], (9, 8)]
# [[4, 5]] + [(9, 6), (8, 7)] ==> [[4, 5], (9, 6), (8, 7)]
# [[1, 2, 3]] + [(8, 9, 4), (7, 6, 5)] ==> [[1, 2, 3], (8, 9, 4), (7, 6, 5)]
# print(mat)
return mat
OR faster
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
mat = [[n*n]]
lo = n*n # [0, n*n+1)
while lo>1:
# print( mat )
lo, hi = lo-len(mat), lo
# list() can generate a range to a list of number, or convert tuple to a list
# print(*mat)
# e.g. [[8], (9,)] ==> *mat ==> [8] (9,)
# ==> *mat[::-1] ==> (9,) [8]
# ==> list( zip( *mat[::-1] ) ) ==> [(9,8)]
# mat = [ list( range(lo, hi) ) ] + list( zip(*mat[::-1]) )
mat = [ range(lo, hi) ] + list( zip(*mat[::-1]) )
# [[9]]
# [range(8, 9), (9,)]
# [range(6, 8), (9, 8)]
# [range(4, 6), (9, 6), (8, 7)]
# [range(1, 4), (8, 9, 4), (7, 6, 5)]
# print(mat)
return mat
60. Permutation Sequence
The set [1, 2, 3, ..., n]
contains a total of n!
unique permutations.
By listing and labeling all of the permutations in order, we get the following sequence for n = 3
:
"123"
"132"
"213"
"231"
"312"
"321"
Given n
and k
, return the kth
permutation sequence.
Example 1:
Input: n = 3, k = 3
Output: "213"
Example 2:
Input: n = 4, k = 9
Output: "2314"
Example 3:
Input: n = 3, k = 1
Output: "123"
class Solution:
def getPermutation(self, n: int, k: int) -> str:
seq = [_ for _ in range(1, n+1)] # if n=4, seq=[1,2,3,4]
k = k-1 # if k=9, then k-1=8
res = []
while len(seq) > 1:
# k_i = k/(n-1)!
fac = 1
for i in range(1,n): # if n=4, then factorial = (4-1)!= 3x2x1=6
fac *= i # if n=3, then factorial = (3-1)!= 2x1=2
# if n=2, then factorial = (2-1)!= 1
k_i = k//fac # k_i = 8//6 = 1 ~ seq[k_i] = 2 # seq=[1,2,3,4]
# k_i = 2//2 = 1 ~ seq[k_i] = 3 # seq=[1,3,4]
# k_i = 0//2 = 0 ~ seq[k_i] = 1 # seq=[1,4]
res.append( str( seq.pop(k_i) ) ) # ==> seq=[1,3,4] ==> seq=[1,4] ==>[4]
# k = k%(n-1)!
k = k % fac # k = 8%6 = 2 # k = 2%2 = 0 # k = 0%2 = 0
n = n-1 # n = 4-1=3 # n = 3-1 =2 # n = 2-1
res.append( str( seq[0] ) )
return ''.join( res )
class Solution:
def getPermutation(self, n: int, k: int) -> str:
import math
seq = [_ for _ in range(1, n+1)]
k = k-1
res = []
while len(seq) > 1:
n = n-1
# k_i = k/(n-1)!
fac = math.factorial(n)
k_i = k//fac
res.append( str( seq.pop(k_i) ) )
# k = k%(n-1)!
k = k % fac
res.append( str( seq[0] ) )
return ''.join( res )
OR
class Solution:
def getPermutation(self, n: int, k: int) -> str:
import itertools as it
# seq = [_ for _ in range(1, n+1)]
# seq = list( it.permutations(seq) )[k-1]
# print( "".join([str(_) for _ in seq]) )
# seq = list( it.permutations( seq ) )[k-1]
# seq = list( it.permutations( range(1,n+1) ) )[k-1]
# return "".join([str(_) for _ in seq])
return "".join([ str(_) for _ in list(
it.permutations( range(1,n+1) )
)[k-1]
])
61. Rotate List
Given the head
of a linked list, rotate the list to the right by k
places.
Example 1:
Input: head = [1,2,3,4,5], k = 2
Output: [4,5,1,2,3]
Example 2:
Input: head = [0,1,2], k = 4
Output: [2,0,1]
# 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: ListNode, k: int) -> ListNode:
# The number of nodes in the list is in the range [0, 500]
if head is None:
return None
# Count the length of the linked list
move_to_back = head
length = 1
while move_to_back.next:
move_to_back = move_to_back.next
length +=1
#now length == 5 if head = [1,2,3,4,5]
move_to_back.next = head # Note: forms a cycle
find_new_head = head
k = k%length # -1: point to --> new_head
for _ in range( length-k-1 ):
find_new_head = find_new_head.next
head = find_new_head.next # new head
find_new_head.next = None # cut off the link for processing the cyble
return head
62. Unique Paths
A robot is located at the top-left corner of a m x n
grid (marked 'Start' in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
How many possible unique paths are there?
Example 1:
Input: m = 3, n = 7
Output: 28
Example 2:
Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Down -> Down
2. Down -> Down -> Right
3. Down -> Right -> Down
Example 3:
Input: m = 7, n = 3
Output: 28
Example 4:
Input: m = 3, n = 3
Output: 6
The combination of time steps to go down from the number of steps m+n-2=m-1+n-1 (as long as you choose which time to go down, the time step to go right is determined). 在总数为m + n - 2
中的数目中挑选n - 1
个位置放竖着的走
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
# steps = m + n - 2 # m-1 + n-1
# down_steps = m-1 # number of steps that need to go down
# def combination( n, r ):
# A = 1
# for i in range(n, n-r,-1):
# A *= i
# m_fac=1 # factorial of m
# for i in range( r, 0, -1 ):
# m_fac *= i
# return int(A/m_fac)
# return combination( steps, min(down_steps, steps-down_steps) )
C=1.
steps = m+n-2
down_steps = m-1 # number of steps that need to go down
r = min( down_steps, steps-down_steps )
# e.g. C_(2,8) = 8x7 // 1x2 = (8-1+1)*(8-2+1)//(1x2)
for i in range( 1,r+1):
C = C* (steps-i+1.)/i # False: C *= (steps-i+1.)/i since divided by 2
return int(C)
OR DP
https://www.youtube.com/watch?v=fEcyKrdIkho
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [ [0]* n for _ in range(m) ]
for i in range(m):
for j in range(n):
if i==0 or j==0: # slower if i=j=0 for only set dp[0][0] =0
dp[i][j]=1
continue
# hidden: [-1][j]=0 and dp[i][-1]=0 since dp = [ [0]*n for _ in range(m) ]
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
OR
suppose 2 robost walk from bottom-right corner to top-left corner(start)
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
# suppose 2 robost walk from bottom-right corner(start) to top or left corner(end)
def dfs( m, n, memory ):
if m==0 or n==0:
return 1
if memory[m][n]:
return memory[m][n]
walk_up = dfs(m-1, n, memory)
walk_left = dfs(m, n-1, memory)
memory[m][n] = walk_up + walk_left
return memory[m][n]
memory = [ [None]*n for _ in range(m) ] # mxn
# accumulate steps
return dfs( m-1, n-1, memory)
63. Unique Paths II
A robot is located at the top-left corner of a m x n
grid (marked 'Start' in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
Now consider if some obstacles are added to the grids. How many unique paths would there be?
An obstacle and space is marked as 1
and 0
respectively in the grid.
Example 1:
Input: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
Output: 2
Explanation: There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right
Example 2:
Input: obstacleGrid = [[0,1],[0,0]]
Output: 1
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
# The following line contains two assignment statements
# and must be separated by ‘,’ and cannot be written in two lines
m, n = len(obstacleGrid), len(obstacleGrid[0])
# why?
# m = len(obstacleGrid)
# print(m) # (3,) # tuple
dp = [ [0]*n for _ in range(m) ]
for i in range(m):
for j in range(n):
if obstacleGrid[i][j] == 0:
if i==j==0: # dp[0][0]=1
dp[i][j] = 1
continue
else: # hidden: [-1][j]=0 and dp[i][-1]=0 since dp = [ [0]*n for _ in range(m) ]
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
64. Minimum Path Sum
Given a m x n
grid
filled with non-negative numbers, find a path from top left to bottom right, which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
Example 1:
Input: grid = [[1,3,1],[1,5,1],[4,2,1]]
Output: 7
Explanation: Because the path 1 → 3 → 1 → 1 → 1 minimizes the sum.
Example 2:
Input: grid = [[1,2,3],[4,5,6]]
Output: 12
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
# 1 <= m, n <= 200
m, n = len(grid), len(grid[0])
for i in range( m ):
for j in range( n ):
if i==0 and j==0:
continue
elif i == 0: # and j>0
grid[i][j] += grid[i][j-1]
continue
elif j == 0: # and i>0
grid[i][j] += grid[i-1][j]
continue
else: # i>0 and j>0
grid[i][j] += min( grid[i-1][j], grid[i][j-1] )
return grid[m-1][n-1]
65. Valid Number
A valid number can be split up into these components (in order):
- A decimal number or an integer.
- (Optional) An
'e'
or'E'
, followed by an integer.
A decimal number can be split up into these components (in order):
- (Optional) A sign character (either
'+'
or'-'
). - One of the following formats:
- One or more digits, followed by a dot
'.'
. - One or more digits, followed by a dot
'.'
, followed by one or more digits. - A dot
'.'
, followed by one or more digits.
- One or more digits, followed by a dot
An integer can be split up into these components (in order):
- (Optional) A sign character (either
'+'
or'-'
). - One or more digits.
For example, all the following are valid numbers: ["2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"]
, while the following are not valid numbers: ["abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]
.
Given a string s
, return true
if s
is a valid number.
Example 1:
Input: s = "0"
Output: true
Example 2:
Input: s = "e"
Output: false
Example 3:
Input: s = "."
Output: false
Example 4:
Input: s = ".1"
Output: true
Constraints:
1 <= s.length <= 20
class Solution:
def isNumber(self, s: str) -> bool:
# # wrong: "inf" expect False but return True
# try:
# float(s)
# return True
# except:
# return False
s=s.strip()
if len(s)==0:
return False
transition = [
{ 'sign': 1, 'digit':2, '.':3 }, # [0] valid start character:specified dict
{ 'digit':2, '.':3 }, # [1] after sign
{ 'digit':2, '.':4, 'e':5 }, # [2] after digit
{ 'digit':4 }, # [3]
{ 'digit':4, 'e':5 }, # [4]
{ 'sign':6, 'digit':7}, # [5]
{ 'digit':7 }, # [6]
{ 'digit':7 }, # [7]
]
current_state = 0
for c in s:
if c>='0' and c<='9':
c = 'digit'
if c in ['+', '-']:
c = 'sign'
if c.lower() =='e': # "1E9" # Expected:true
c = 'e'
if c not in transition[current_state].keys():
return False
current_state = transition[current_state][c]
if current_state not in [2,4,7]: # final state_list
return False
return True
66. Plus One
Given a non-empty array of decimal digits representing a non-negative integer, increment one to the integer.
The digits are stored such that the most significant digit is at the head of the list, and each element in the array contains a single digit.
You may assume the integer does not contain any leading zero, except the number 0 itself.
Given a non-empty array of decimal digits representing a non-negative integer, increment one to the integer.
The digits are stored such that the most significant digit is at the head of the list, and each element in the array contains a single digit.
You may assume the integer does not contain any leading zero, except the number 0 itself.
Example 1:
Input: digits = [1,2,3]
Output: [1,2,4]
Explanation: The array represents the integer 123. and 123+1=124
Example 2:
Input: digits = [4,3,2,1]
Output: [4,3,2,2]
Explanation: The array represents the integer 4321. and 4321+1=4322
Example 3:
Input: digits = [0]
Output: [1] # 0 + 1=1
class Solution:
def plusOne(self, digits: List[int]) -> List[int]:
carry = 1
for i in range( len(digits)-1, -1, -1): # (-1, len(digit)]
if digits[i] + carry == 10:
digits[i] = 0
continue
else:
digits[i] = digits[i] + carry
carry = 0
break
if carry==1:
digits.insert(0,carry)
return digits
67. Add Binary
Given two binary strings a
and b
, return their sum as a binary string.
Example 1:
Input: a = "11", b = "1"
Output: "100"
Example 2:
Input: a = "1010", b = "1011"
Output: "10101"
class Solution:
def addBinary(self, a: str, b: str) -> str:
a = list(a)
b = list(b)
carry = 0
i = len(a)-1
while i>-1 or b or carry==1:
if b:
carry += int( b.pop() ) # == a.pop(-1)
if i>-1: # Traverse list a
carry += int( a[i] )
a[i] = str( carry % 2 )
i -= 1
else:
a.insert(0, str(carry%2) )
carry //= 2
return ''.join(a)
68. Text Justification
Given an array of strings words
and a width maxWidth
, format the text such that each line has exactly maxWidth
characters and is fully (left and right) justified.
You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' '
when necessary so that each line has exactly maxWidth
characters.
Extra spaces between words should be distributed as evenly as possible. If the number of spaces on a line does not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right except the last line.
For the last line of text, it should be left-justified and only one extra space is inserted between words.(Correct the description of the original title: For the last line of text, it should be left-justified and no extra space is inserted between words.)
Note:
- A word is defined as a character sequence consisting of non-space characters only.
- Each word's length is guaranteed to be greater than 0 and not exceed maxWidth.
- The input array
words
contains at least one word.
Example 1:
Input: words = ["justification.","This", "is", "an", "example", "of", "text"],
maxWidth = 16
Output:
[ "justification. ",
"This is an",
"example of text "
]
Input: words = ["This", "is", "an", "example", "of", "text", "justification."], maxWidth = 16
Output:
[
"This is an",
"example of text",
"justification. "
]
Example 2:
Input: words = ["What","must","be","acknowledgment","shall","be"], maxWidth = 16
Output:
[
"What must be",
"acknowledgment ",
"shall be "
]
Explanation: Note that the last line is "shall be " instead of "shall be", because the last line must be left-justified instead of fully-justified.
Note that the second line is also left-justified becase it contains only one word.
Example 3:
Input: words = ["Science","is","what","we","understand","well","enough","to","explain","to","a","computer.","Art","is","everything","else","we","do"], maxWidth = 20
Output:
[
"Science is what we",
"understand well",
"enough to explain to",
"a computer. Art is",
"everything else we",
"do "
]
class Solution:
def fullJustify(self, words: List[str], maxWidth: int) -> List[str]:
cur, n_chars_in_cur, res = [], 0, []
for w in words:
# word + space + new_word
if n_chars_in_cur + len(cur) + len(w) > maxWidth:
# number of spaces need to be appened to each word
# in cur except last one
for i in range( maxWidth - n_chars_in_cur):
# loaction: i % (number of words in cur-1)
# 0%1 for only word
cur[ i % (len(cur)-1 if len(cur)>1 else 1) ] += ' '
res.append( ''.join(cur) )
cur, n_chars_in_cur = [], 0
cur.append(w)
n_chars_in_cur += len(w)
# For the last line of text, it should be left-justified and no extra
# space is inserted between words.
# str.ljust(width[, fillchar]) #default fillchar is space
return res + [ ' '.join(cur).ljust(maxWidth) ]
69. Sqrt(x)
Given a non-negative integer x
, compute and return the square root of x
.
Since the return type is an integer, the decimal digits are truncated, and only the integer part of the result is returned.
Note: You are not allowed to use any built-in exponent function or operator, such as pow(x, 0.5)
or x ** 0.5
.
Example 1:
Input: x = 4
Output: 2
Example 2:
Input: x = 8
Output: 2
Explanation: The square root of 8 is 2.82842..., and since the decimal part is truncated, 2 is returned.
class Solution:
def mySqrt(self, x: int) -> int:
x_next = x
while x_next*x_next > x:
# Newton's iterative formula for f(x)=x*2: x_1 = x_0 - f(x_0)/f'(x_0)
# x_1 = x_0 - x_0*x_0 / (2*x_0)
# x_2 = x_1 - f(x_1)/f'(x_1)
# x_2 = x_1 - x_1*x_1 / (2*x_1)
# x_3 = x_2 - f(x_2)/f'(x_2)
# x_3 = x_2 - x_2*x_2 / (2*x_2)
# ... ...
# x_cur_next = x_cur - (x_cur*x_cur-x_initial) / (2*x_cur)
# x_next = x_next - (x_next*x_next - x)/(2*x_next)
# x_next = x_next/2 + x/(x_next*2)
x_next = (x_next + x/x_next)//2
return int(x_next)
class Solution:
def mySqrt(self, x: int) -> int:
x_i = x
while x_i*x_i > x:
# x_i = x_i - (x_i*x_i - x)/(2*x_i)
# x_i = x_i/2 + x/(x_i*2)
x_i = (x_i + x/x_i)//2
return int(x_i)
OR
class Solution:
def mySqrt(self, x: int) -> int:
# x_i = x
# while x_i*x_i > x:
# # x_i = x_i - (x_i*x_i - x)/(2*x_i)
# # x_i = x_i/2 + x/(x_i*2)
# x_i = (x_i + x/x_i)//2
# return int(x_i)
l, r = 0, x
while l<=r:
mid = (l+r)//2
if mid*mid <= x < (mid+1)*(mid+1): # e.g. x=8, root=2
return mid
elif x < mid*mid:
r = mid-1
continue
else: #elif x>= (mid+1)*(mid+1):
l = mid+1
70. Climbing Stairs
You are climbing a staircase. It takes n
steps to reach the top.
Each time you can either climb 1
or 2
steps. In how many distinct ways can you climb to the top?
Example 1:
Input: n = 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
Example 2:
Input: n = 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
class Solution:
def climbStairs(self, n: int) -> int:
# n = 1 : output = 1
# n = 2 : output = 2
# n = 3 : output = 3
# n = 4 : output = 5
# n = 5 : output = 8
if n<=3:
return n
way_list = [1,2,3]
for i in range(3,n):
way_list.append( way_list[i-1] + way_list[i-2] )
return way_list[n-1] # n-1 since index start from 0
71. Simplify Path
Given a string path
, which is an absolute path (starting with a slash '/'
) to a file or directory in a Unix-style file system, convert it to the simplified canonical path.
In a Unix-style file system,
- a period
'.'
refers to the current directory, - a double period
'..'
refers to the directory up a level, and - any multiple consecutive slashes (i.e.
'//'
) are treated as a single slash'/'
. - For this problem, any other format of periods such as
'...'
are treated as file/directory names.
The canonical path should have the following format:
- The path starts with a single slash
'/'
. - Any two directories are separated by a single slash
'/'
. - The path does not end with a trailing
'/'
. - The path only contains the directories on the path from the root directory to the target file or directory (i.e., no period
'.'
or double period'..'
)
Return the simplified canonical path.
Example 1:
Input: path = "/home/"
Output: "/home"
Explanation: Note that there is no trailing slash after the last directory name.
Example 2:
Input: path = "/../"
Output: "/"
Explanation: Going one level up from the root directory is a no-op, as the root level is the highest level you can go.
Example 3:
Input: path = "/home//foo/"
Output: "/home/foo"
Explanation: In the canonical path, multiple consecutive slashes are replaced by a single one.
Example 4:
Input: path = "/a/./b/../../c/"
Output: "/c"
path = "/a/./b/../../c/", =>"/c"
整个过程:
l “/”根目录
l “a”进入子目录a,目前处于“/a”
l “.”当前目录,不操作仍处于“/a”
l “/b”进入子目录b,目前处于“/a/b”
l “..”返回上级目录,处于“/a”
l “..”返回上级目录,处于根目录“/”
l “c”进入子目录c,目前处于“/c”
class Solution:
def simplifyPath(self, path: str) -> str:
# a period '.' refers to the current directory
# dirs = [ p for p in path.split('/') if p!='' and p!='.']
# # ['home']
# # ['..']
# # ['home', 'foo']
# # ['a', 'b', '..', '..', 'c']
stack = []
for p in path.split('/'):
if p == '..':
if stack: # len(stack) > 0
stack.pop()
elif p!='' and p!='.':# '.' refers to the current directory
stack.append(p) # first step
return '/' + '/'.join(stack)
72. Edit Distance
Given two strings word1
and word2
, return the minimum number of operations required to convert word1
to word2
.
You have the following three operations permitted on a word:
- Insert a character
- Delete a character
- Replace a character
Example 1:
Input: word1 = "horse", word2 = "ros" Output: 3 Explanation: horse -> rorse (replace 'h' with 'r') rorse -> rose (remove 'r') rose -> ros (remove 'e')
Example 2:
Input: word1 = "intention", word2 = "execution" Output: 5 Explanation: intention -> inention (remove 't') inention -> enention (replace 'i' with 'e') enention -> exention (replace 'n' with 'x') exention -> exection (replace 'n' with 'c') exection -> execution (insert 'u')
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
rows, cols = len(word1)+1, len(word2)+1
dp = [ [ 0 for c in range(cols) ]
for r in range(rows)
]
for c in range(cols):
dp[0][c] = c
for r in range(rows):
dp[r][0] = r
# r,c means advance one position (r-1 or c-1)in the original string
for r in range( 1, rows ):
for c in range( 1, cols ):
if word1[r-1] == word2[c-1]:
dp[r][c] = dp[r-1][c-1] # + 0 operation
else:
# Choose the shortest path, or the least operation
dp[r][c] = min( dp[r][c-1], # + 1 insert operation
dp[r-1][c], # + 1 remove operation
dp[r-1][c-1] # + 1 replace operation
)+1
print(dp)
return dp[rows-1][cols-1]
73. Set Matrix Zeroes
Given an m x n
integer matrix matrix
, if an element is 0
, set its entire row and column to 0
's, and return the matrix.
You must do it in place.
Example 1:
Input: matrix = [[1,1,1],[1,0,1],[1,1,1]] Output: [[1,0,1],[0,0,0],[1,0,1]]
Example 2:
Input: matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]] Output: [[0,0,0,0],[0,4,5,0],[0,3,1,0]]
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
rows = []
cols = []
for r in range( len(matrix) ):
for c in range( len(matrix[0]) ):
if matrix[r][c] == 0:
rows.append(r)
cols.append(c)
for r in rows:
matrix[r] = [0]*len(matrix[0]) # [0,0,...]
for c in cols:
for r in range( len(matrix) ):
matrix[r][c] = 0
return matrix
74. Search a 2D Matrix
Write an efficient algorithm that searches for a value in an m x n
matrix. This matrix has the following properties:
- Integers in each row are sorted from left to right.
- The first integer of each row is greater than the last integer of the previous row.
Example 1:
Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3 Output: true
Example 2:
Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13 Output: false
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
for r in matrix:
if target>r[-1]:
continue
return target in r
return False
OR
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
# for r in matrix:
# if target>r[-1]:
# continue
# return target in r
# return False
for r in matrix:
if target>r[-1]:
continue
left, right =0, len(r)-1
while left<=right:
mid = (left + right)//2
if r[mid] == target:
return True
elif r[mid] < target:
left = mid+1
elif target < r[mid]:
right = mid-1
return False
75. Sort Colors
Given an array nums
with n
objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white, and blue.
We will use the integers 0
, 1
, and 2
to represent the color red, white, and blue, respectively.
You must solve this problem without using the library's sort function.
class Solution:
def sortColors(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
# 1 <= nums.length <= 300
start_idx, end_idx, cur_idx = 0, len(nums)-1, 0
while start_idx < end_idx and nums[start_idx]<1:
start_idx+=1
cur_idx+=1
while end_idx>0 and nums[end_idx]>1:
end_idx -= 1
while cur_idx<=end_idx:
if nums[cur_idx] > 1:
nums[cur_idx], nums[end_idx] = nums[end_idx], nums[cur_idx]
end_idx -= 1
continue
elif nums[cur_idx] < 1:
nums[start_idx], nums[cur_idx] = nums[cur_idx], nums[start_idx]
start_idx += 1
cur_idx += 1
continue
else:
cur_idx += 1