from functools import lru_cache
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
@lru_cache(maxsize = None)
def distance(i, j):
if i == 0:
return j
if j == 0:
return i
# delete
d1 = distance(i-1, j) + 1
# insert
d2 = distance(i, j-1) + 1
d3 = distance(i-1, j-1)
# replace
if word1[i-1] != word2[j-1]:
d3 += 1
return min(d1, d2, d3)
return distance(len(word1), len(word2))
5/31/2020
[LeetCode] 72. Edit Distance
[LeetCode] 71. Simplify Path
class Solution {
public String simplifyPath(String path) {
Deque<String> deque = new LinkedList<>();
StringBuilder token = new StringBuilder();
if (path.charAt(path.length()-1) != '/') {
path += "/";
}
for (char c : path.toCharArray()) {
if (c == '/') {
if ( ".".equals(token.toString()) || token.length() == 0) {
// do nothing
} else if ("..".equals(token.toString())) {
if (!deque.isEmpty()) {
deque.pollLast();
}
} else {
deque.offerLast(token.toString());
}
// reset the token
token.setLength(0);
} else {
token.append(c);
}
}
StringBuilder result = new StringBuilder();
while (!deque.isEmpty()) {
result.append("/");
result.append(deque.pollFirst());
}
return result.length() != 0 ? result.toString() : "/";
}
}
Edited on 03/13/2022. Use deque to push / pop from the rear and pop in the front of the intermediate 'directory name' list.
[LeetCode] 70. Climbing Stairs
The top-down solution:
class Solution:
def climbStairs(self, n: int) -> int:
@cache
def stairs(x):
return stairs(x-1) + stairs(x-2) if x > 2 else x
return stairs(n)
The bottom-up solution:
class Solution:
def climbStairs(self, n: int) -> int:
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return b
Edited on 10/05/2021. Update the top-down and buttom-up solutions.
[LeetCode] 69. Sqrt(x)
class Solution(object):
def mySqrt(self, x):
"""
:type x: int
:rtype: int
"""
left, right = 0, x
while left < right:
mid = left + (right - left) // 2
if mid * mid == x:
return mid
if mid * mid > x:
right = mid
else:
left = mid + 1
return right - 1 if x > 1 else x
[LeetCode] 68. Text Justification
from functools import reduce
class Solution(object):
def fullJustify(self, words, maxWidth):
"""
:type words: List[str]
:type maxWidth: int
:rtype: List[str]
"""
def width(row):
"""
calculate row width with 1 space between each word
"""
return reduce(lambda x, y: x + len(y), row, 0) + len(row) - 1
def justify(row, leftJustified):
"""
justify text on this row
"""
if len(row) == 1:
return row[0] + ' ' * (maxWidth - len(row[0]))
line = ""
rowSize = reduce(lambda x, y: x + len(y), row, 0)
space = (maxWidth - rowSize) // (len(row) - 1)
extraSpace = (maxWidth - rowSize) % (len(row) - 1)
if not leftJustified:
for i in range(len(row)):
line += row[i]
if i < len(row) - 1:
if extraSpace > 0:
# add extra spaces as evenly as possible
line += ' ' * (space + 1)
extraSpace -= 1
else:
line += ' ' * space
else:
for i in range(len(row)):
line += row[i]
if i < len(row) -1:
line += ' '
line += ' ' * (maxWidth - len(line))
return line
rows = []
for w in words:
if not rows:
rows.append([w])
continue
if width(rows[-1]) + len(w) + 1 <= maxWidth:
# pack as many words as possible to one line
rows[-1].append(w)
else:
rows.append([w])
result = []
for i in range(len(rows)):
result.append(justify(rows[i], i == len(rows) - 1))
return result
5/30/2020
[LeetCode] 67. Add Binary
class Solution {
public String addBinary(String a, String b) {
int n = Math.max(a.length(), b.length()) + 1;
char[] buffer = new char[n];
int i = a.length() - 1;
int j = b.length() - 1;
int k = n - 1;
int carry = 0;
while (i >= 0 || j >= 0 || carry == 1) {
int A = i >= 0 ? a.charAt(i--) - '0' : 0;
int B = j >= 0 ? b.charAt(j--) - '0' : 0;
buffer[k--] = (char)('0' + (A + B + carry) % 2);
carry = (A + B + carry) / 2;
}
if (buffer[0] != 0) {
return new String(buffer);
}
return new String(Arrays.copyOfRange(buffer, 1, n));
}
}
Edited on 02/13/2023. Replace with an optimized Java version solution.
Edited on 01/09/2022. Replace with the Java version solution.
[LeetCode] 66. Plus One
class Solution:
def plusOne(self, digits: List[int]) -> List[int]:
result = [0] * (len(digits) + 1)
i = len(digits) - 1
j = i + 1
carry = 1
while i >= 0 or carry > 0:
if i >= 0:
result[j] = (digits[i] + carry) % 10
carry = (digits[i] + carry) // 10
i -= 1
j -= 1
else:
result[j] = carry
j -= 1
carry = 0
return result if j == -1 else result[j+1:]
[LeetCode] 65. Valid Number
class Solution:
def isNumber(self, s: str) -> bool:
state = 'sign'
for w in s:
if state == 'sign':
if w in '+-':
state = 'integer_start'
continue
if w.isdigit():
state = 'integer'
continue
if w == '.':
state = 'decimal_start'
continue
return False
if state == 'integer_start':
if w.isdigit():
state = 'integer'
continue
if w == '.':
state = 'decimal_start'
continue
return False
if state == 'integer':
if w.isdigit():
continue
if w in 'eE':
state = 'sign_e'
continue
if w == '.':
state = 'decimal'
continue
return False
if state == 'decimal_start':
if w.isdigit():
state = 'decimal'
continue
return False
if state == 'decimal':
if w.isdigit():
continue
if w in 'eE':
state = 'sign_e'
continue
return False
if state == 'sign_e':
if w in '+-':
state = 'num_e_start'
continue
if w.isdigit():
state = 'num_e'
continue
return False
if state == 'num_e_start':
if w.isdigit():
state = 'num_e'
continue
return False
if state == 'num_e':
if w.isdigit():
continue
return False
if state == 'integer_start':
return False
if state == 'decimal_start':
return False
if state == 'num_e_start':
return False
if state == 'sign_e':
return False
return True
Edited on 05/15/2021. Refactor FSM code.
[LeetCode] 64. Minimum Path Sum
from functools import lru_cache
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
@lru_cache(maxsize=None)
def dfs(i, j):
if i - 1 >= 0 and j - 1 >= 0:
return min(dfs(i - 1, j), dfs(i, j - 1)) + grid[i][j]
if i - 1 >= 0:
return dfs(i - 1, j) + grid[i][j]
if j - 1 >= 0:
return dfs(i, j - 1) + grid[i][j]
return grid[i][j]
row = len(grid)
column = len(grid[0])
return dfs(row - 1, column - 1)
The bottom-up solution:
class Solution {
public int minPathSum(int[][] grid) {
int ROW = grid.length;
int COLUMN = grid[0].length;
int[][] dp = new int[ROW][COLUMN];
dp[0][0] = grid[0][0];
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COLUMN; j++) {
if (i == 0 && j == 0) {
continue;
}
dp[i][j] = grid[i][j] + Math.min(i-1>=0 ? dp[i-1][j] : Integer.MAX_VALUE, j-1>=0 ? dp[i][j-1] : Integer.MAX_VALUE);
}
}
return dp[ROW-1][COLUMN-1];
}
}
Edited on 11/25/2021. Add the bottom-up solution.
[LeetCode] 63. Unique Paths II
from functools import lru_cache
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
@lru_cache(maxsize = None)
def paths(i, j):
if i < 0 or j < 0:
return 0
if obstacleGrid[i][j] == 1:
return 0
# 1 step to start from the top-left cell
if i == 0 and j == 0:
return 1
return paths(i-1, j) + paths(i, j-1)
m = len(obstacleGrid)
n = len(obstacleGrid[0])
return paths(m-1, n-1)
A bottom-up DP solution.
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
ROW = len(obstacleGrid)
COLUMN = len(obstacleGrid[0])
dp = [[0] * (COLUMN+1) for _ in range(ROW+1)]
dp[ROW-1][COLUMN-1] = 1 if obstacleGrid[ROW-1][COLUMN-1] != 1 else 0
for y in reversed(range(ROW)):
for x in reversed(range(COLUMN)):
if y == ROW-1 and x == COLUMN-1:
continue
if obstacleGrid[y][x] == 1:
continue
dp[y][x] = dp[y+1][x] + dp[y][x+1]
return dp[0][0]
Edited on 04/28/2021. Add the DP solution.
[LeetCode] 62. Unique Paths
from functools import lru_cache
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
@lru_cache(maxsize=None)
def paths(i, j):
if j <= 0 or i <= 0:
return 0
# 1 step to start from the top-left cell
if i == 1 and j == 1:
return 1
return paths(i, j-1) + paths(i-1, j)
return paths(m, n)
5/29/2020
[LeetCode] 61. Rotate List
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def rotateRight(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
if not head:
return None
p = head
total = 1
while p.next:
total += 1
p = p.next
# link th tail and head
p.next = head
# find the new head position
k = total - (k % total) - 1
p = head
while k > 0:
p = p.next
k -= 1
head = p.next
p.next = None
return head
5/27/2020
[LeetCode] 60. Permutation Sequence
from operator import imul
class Solution(object):
def getPermutation(self, n, k):
"""
:type n: int
:type k: int
:rtype: str
"""
nums = [str(i) for i in range(1, n+1)]
# total = n!
total = reduce(imul, range(1,n+1))
result = ""
k -= 1 # number index starts from 0
while n > 0:
group = total // n
i = k // group
result += nums[i]
nums.pop(i)
k = k % group
total = total // n
n -= 1
return result
5/26/2020
[LeetCode] 59. Spiral Matrix II
class Solution(object):
def generateMatrix(self, n):
"""
:type n: int
:rtype: List[List[int]]
"""
board = [[0] * n for _ in range(n)]
i = 1
board[0][0] = 1
y, x = 0, 0
padding_y, padding_x = 0, 0
state = 'right'
while True:
if state == 'right':
if x + 1 >= n - padding_x:
state = 'down'
else:
x += 1
i += 1
board[y][x] = i
elif state == 'down':
if y + 1 >= n - padding_y:
state = 'left'
else:
y += 1
i += 1
board[y][x] = i
elif state == 'left':
if x - 1 < padding_x:
state = 'up'
padding_y += 1
else:
x -= 1
i += 1
board[y][x] = i
elif state == 'up':
if y - 1 < padding_y:
state = 'right'
padding_x +=1
else:
y -= 1
i += 1
board[y][x] = i
if i >= n * n:
break
return board
[LeetCode] 58. Length of Last Word
class Solution(object):
def lengthOfLastWord(self, s):
"""
:type s: str
:rtype: int
"""
result = 0
for i in reversed(range(len(s))):
if s[i] == ' ' and result > 0:
break
if s[i] != ' ':
result += 1
return result
[LeetCode] 57. Insert Interval
class Solution {
public int[][] insert(int[][] intervals, int[] newInterval) {
Deque<int[]> result = new LinkedList<>();
boolean added = false;
int i = 0;
while (i <= intervals.length) {
int[] next;
if (i < intervals.length && (added || intervals[i][0] <= newInterval[0])) {
next = intervals[i];
i += 1;
} else if (!added) {
next = newInterval;
added = true;
} else {
break;
}
if (result.peekLast() == null || result.peekLast()[1] < next[0]) {
result.offerLast(next);
} else {
result.peekLast()[0] = Math.min(result.peekLast()[0], next[0]);
result.peekLast()[1] = Math.max(result.peekLast()[1], next[1]);
}
}
return result.toArray(new int[0][0]);
}
}
Binary search based solution:
class Solution:
def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
newStart, newEnd = newInterval
# find the lower bound insertion position
left, right = 0, len(intervals)
while left < right:
mid = left + (right - left) // 2
start, end = intervals[mid]
if start <= newStart <= newEnd <= end:
return intervals
if start < newStart:
left = mid + 1
elif start > newStart:
right = mid
else: # start == newStart
right = mid
if left == len(intervals):
intervals.append(newInterval)
intervals.insert(left, newInterval)
# merge intervals
i = j = left - 1 if left - 1 >= 0 else 0
while j < len(intervals):
if intervals[i][0] <= intervals[j][0] <= intervals[i][1]:
intervals[i][0] = min(intervals[i][0], intervals[j][0])
intervals[i][1] = max(intervals[i][1], intervals[j][1])
else:
i += 1
intervals[i][0] = intervals[j][0]
intervals[i][1] = intervals[j][1]
j += 1
return intervals[:i+1]
Updated on 01/15/2023. Updated the linear scan approach with a concise implementation.
[LeetCode] 56. Merge Intervals
from operator import itemgetter
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
intervals.sort()
result = []
for start, end in intervals:
if result and result[-1][0] <= start <= result[-1][1]:
result[-1][0] = min(result[-1][0], start)
result[-1][1] = max(result[-1][1], end)
else:
result.append([start, end])
return result
5/25/2020
[LeetCode] 55. Jump Game
class Solution:
def canJump(self, nums: List[int]) -> bool:
N = len(nums)
maxSoFar = 0
for i, n in enumerate(nums):
if maxSoFar >= N - 1:
return True
if i > maxSoFar:
return False
if i + nums[i] > maxSoFar:
maxSoFar = i + nums[i]
return False
A memorization solution:
class Solution:
def canJump(self, nums: List[int]) -> bool:
N = len(nums)
@cache
def helper(x):
if x >= N-1: return True
return any(helper(x + s) for s in reversed(range(1, nums[x] + 1)))
return helper(0)
[LeetCode] 54. Spiral Matrix
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
ROW = len(matrix)
COLUMN = len(matrix[0])
nextPos = {'right': (0, 1), 'down': (1, 0), 'left': (0, -1), 'up': (-1, 0)}
nextDir = {'right': 'down', 'down': 'left', 'left': 'up', 'up': 'right'}
y, x = 0, -1
direction = 'right'
result = []
visited = defaultdict(bool)
while len(result) < ROW * COLUMN:
ny, nx = y + nextPos[direction][0], x + nextPos[direction][1]
if 0 <= ny < ROW and 0 <= nx < COLUMN and not visited[ny,nx]:
visited[ny, nx] = True
result.append(matrix[ny][nx])
y, x = ny, nx
else:
direction = nextDir[direction]
return result
Edited on 09/16/2021. Refactor by using dictionary to save next position to move forward and next direction when need to make a turn.
5/24/2020
[LeetCode] 53. Maximum Subarray
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
result = -2 ** 31
tmp = 0
for i in range(len(nums)):
# restart sub-array from i if its sum less than nums[i]
tmp = max(tmp + nums[i], nums[i])
result = max(result, tmp)
return result
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
def helper(start, end):
if end - start == 1:
return nums[start]
mid = start + (end - start) // 2
# max of left sub-array
left_max = helper(start, mid)
# max of right sub-array
right_max = helper(mid, end)
# max of middle
mid_max = nums[mid]
t = mid_max
for i in range(mid-1, start-1, -1):
t += nums[i]
mid_max = max(mid_max, t)
t = mid_max
for i in range(mid+1, end):
t += nums[i]
mid_max = max(mid_max, t)
return max(left_max, mid_max, right_max)
return helper(0, len(nums))
[LeetCode] 52. N-Queens II
class Solution:
def totalNQueens(self, n: int) -> int:
@cache
def getOccupies(y, x):
occupies = [(y, x)]
for dy, dx in [(1,0), (0,1), (1,1), (1,-1)]:
tmpY, tmpX = y+dy, x+dx
while 0 <= tmpY < n and 0 <= tmpX < n:
occupies.append((tmpY, tmpX))
tmpY += dy
tmpX += dx
return occupies
def backtrack(y, board):
if y == n:
yield 1
else:
for x in range(n):
if board[y][x]:
# skip this position as it has been occupied
continue
myOccupies = getOccupies(y,x)
for py, px in myOccupies:
board[py][px] += 1
yield from backtrack(y+1, board)
for py, px in myOccupies:
board[py][px] -= 1
board = [[0] * n for _ in range(n)]
return sum(backtrack(0, board))
Edited on 05/22/2021. Use memorization to simplify the code for checking whether one position is valid to put a Queen.
Edited on 05/29/2021. Optimize performance by only marking positions on right and on rows below.
[LeetCode] 51. N-Queens
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
board = [[0] * n for _ in range(n)]
result = []
def toBoard(queens):
return [''.join(['Q' if x == queens[y] else '.' for x in range(n)]) for y in range(n)]
@cache
def getOccupied(y, x):
occupied = [(y,x)]
# because we scan from left to right and top to bottom
# it only needs to mark the poisition on right and on rows below
for dy, dx in [(1,0), (0,1), (1, 1), (1, -1)]:
tmpY, tmpX = y + dy, x + dx
while 0 <= tmpY < n and 0 <= tmpX < n:
occupied.append((tmpY, tmpX))
tmpY += dy
tmpX += dx
return occupied
def backtrack(y, queens):
if y == n:
yield toBoard(queens)
else:
for x in range(n):
if board[y][x]:
continue
myOccupied = getOccupied(y, x)
for occupiedY, occupiedX in myOccupied:
board[occupiedY][occupiedX] += 1
queens.append(x)
yield from backtrack(y+1, queens)
queens.pop()
for occupiedY, occupiedX in myOccupied:
board[occupiedY][occupiedX] -= 1
return list(backtrack(0, []))
Edited on 05/22/2021. Simplify the method for caculating occupied positions.
Edited on 05/29/2021. Optimize performance by only marking poisition on right and on rows below.
[LeetCode] 50. Pow(x, n)
class Solution(object):
class Solution:
def myPow(self, x: float, n: int) -> float:
@lru_cache(maxsize = None)
def helper(i):
if i == 0:
return 1
if i == 1:
return x
return helper(i//2) * helper(i//2) * helper(i % 2)
return helper(n) if n >= 0 else 1 / helper(-1 * n)
class Solution:
def myPow(self, x: float, n: int) -> float:
if n == 0:
return 1
if n == 1:
return x
positive = True
if n < 0:
positive = False
n *= -1
result = self.myPow(x, n // 2)
result *= result
if n % 2:
result *= x
return result if positive else 1 / result
[LeetCode] 49. Group Anagrams
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
seen = defaultdict(list)
for s in strs:
seen[tuple(sorted(s))].append(s)
return seen.values()
[LeetCode] 48. Rotate Image
class Solution(object):
def rotate(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: None Do not return anything, modify matrix in-place instead.
"""
# reverse rows
left, right = 0, len(matrix)-1
while left <= right:
matrix[left], matrix[right] = matrix[right], matrix[left]
left += 1
right -= 1
# swap the symmetry
for i in range(len(matrix)):
for j in range(i+1, len(matrix[i])):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
# reverse each row
for i in range(len(maxtrix)):
reverse(matrix[i])
# swap the symmetry
for i in range(len(matrix)):
for j in range(i+1, len(matrix[i])):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
[LeetCode] 47. Permutations II
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
# sort to group number with same value together
nums.sort()
result = []
def backtrack(tmp):
if not nums:
# no more candidate number left
if tmp:
result.append(partial)
return
for i in range(0, len(nums)):
# skip number with same value to avoid duplicatation
if i > 0 and nums[i] == nums[i-1]:
continue
# take the selected number out of candidate array
n = nums.pop(i)
backtrack(tmp + [n])
# restore candidate array
nums.insert(i, n)
backtrack([])
return result
Use hash table to avoid duplicate permutation
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
result = []
def backtrack(start):
if start == len(nums):
result.append(nums[:])
else:
seen = set()
for i in range(start, len(nums)):
if nums[i] in seen:
continue
seen.add(nums[i])
nums[start], nums[i] = nums[i], nums[start]
backtrack(start + 1)
nums[start], nums[i] = nums[i], nums[start]
backtrack(0)
return result
A hash table backed backtracking approach.
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
result = []
counter = Counter(nums)
keys = counter.keys()
def backtrack(tmp):
if len(tmp) == len(nums):
result.append(tmp)
else:
for k in keys:
if counter[k] == 0:
continue
counter[k] -= 1
backtrack(tmp + [k])
counter[k] += 1
backtrack([])
return result
[LeetCode] 46. Permutations
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
if not nums: return []
N = len(nums)
result = []
def swap(i, j):
nums[i], nums[j] = nums[j], nums[i]
def backtrack(start):
if start == N:
result.append(nums[:])
else:
for i in range(start, N):
swap(i, start)
backtrack(start+1)
swap(i, start)
backtrack(0)
return result
[LeetCode] 45. Jump Game II
class Solution:
def jump(self, nums: List[int]) -> int:
max_int = 2 ** 31 - 1
dp = [max_int] * len(nums)
dp[0] = 0
for i in range(len(nums)):
# The furthest postion can be reached
# from index i is nums[i+nums[i]].
#
# However, there is routine with less step
# to reach to nums[i+nums[i]].
#
# So including nums[i] in routine does not
# decrease the total steps
if i + nums[i] < len(nums) and dp[i] + 1 >= dp[i + nums[i]]:
continue
for j in range(1, nums[i]+1):
if i + j >= len(nums) - 1:
dp[-1] = min(dp[-1], dp[i] + 1)
else:
dp[i+j] = min(dp[i+j], dp[i]+1)
return dp[-1]
class Solution:
def jump(self, nums: List[int]) -> int:
result = 0
last_furthest = 0
furthest = 0
for i in range(0, len(nums) - 1):
# Extend the furthest position can be reached
if furthest >= i and nums[i] + i > furthest:
furthest = nums[i] + i
# If current position equals to the last furthest position
# can be reached or it equals to the end of list, increase step counter.
# As it needs one more step to reach to the current furthest position.
if i == last_furthest or furthest >= len(nums) - 1:
last_furthest = furthest
result += 1
if furthest >= len(nums) - 1:
break
return result
5/23/2020
[LeetCode] 44. Wildcard Matching
- Use '*' to match the current character in S and keep the '*' for the next character matching
- Skip '*' as '*' is used to match empty sequence. Then use next character in P to match current character in S.
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
memo = [[0] * (len(p)+1) for _ in range(len(s)+1)]
def helper(i, j):
if j >= len(p):
return i >= len(s)
if memo[i][j] != 0:
return memo[i][j] == 1
if i < len(s) and s[i] == p[j]:
return helper(i+1, j+1)
if i < len(s) and p[j] == '?':
return helper(i+1, j+1)
if i < len(s) and p[j] == '*':
# Match S[i] with '*'
# Move to next character of S
# Keep '*' in P
if helper(i+1, j):
memo[i][j] = 1
return True
# Use '*' to match empty sequence
# Stay on the current character of S
# Move to next character of P
if helper(i, j+1):
memo[i][j] = 1
return True
if i == len(s) and p[j] == '*':
return helper(i, j+1)
memo[i][j] = -1
return False
return helper(0, 0)
5/21/2020
[LeetCode] 43. Multiply Strings
class Solution:
def multiply(self, num1: str, num2: str) -> str:
def mul(a, b):
result = []
carry = 0
for n in a[::-1]:
t = n * b + carry
result.append(t%10)
carry = t // 10
if carry:
result.append(carry)
return result[::-1]
def plus(a, b):
i, j = len(a)-1, len(b)-1
carry = 0
result = []
while i >= 0 or j >= 0 or carry:
t = carry
if i >= 0:
t += a[i]
if j >= 0:
t += b[j]
result.append(t%10)
carry = t // 10
i -= 1
j -= 1
return result[::-1]
num1 = [int(n) for n in num1]
num2 = [int(n) for n in num2]
base = 0
tmp = []
for n in num2[::-1]:
t = mul(num1, n)
for i in range(base):
t.append(0)
tmp.append(t)
base += 1
result = [0]
for i in range(len(tmp)):
result = plus(tmp[i], result)
return ''.join(map(str,result)) if result[0] != 0 else '0'
Edited on 11/07/2021. Tidy the solution.
[LeetCode] 42. Trapping Rain Water
class Solution:
def trap(self, height: List[int]) -> int:
N = len(height)
if N < 2: return 0
# left[i] = maximum height from left of position i
left = [0] * N
mx = 0
for i in range(N):
left[i] = mx
mx = max(mx, height[i])
# right[i] = maximum height from right of position i
right = [0] * N
mx = 0
for i in reversed(range(N)):
right[i] = mx
mx = max(mx, height[i])
result = 0
for i in range(N):
# maximum water can be contained at ith position
result += max(0, min(left[i], right[i]) - height[i])
return result
Monotonic stack based solution. Time Complexity = O ( 2 * N ), because for every position it could be visited at most 2 times.
class Solution:
def trap(self, height: List[int]) -> int:
# maintain a monotonic decreasing stack
stack = []
result = 0
for right in range(len(height)):
# it can form a cavity if we find a taller right bar
while stack and height[stack[-1]] < height[right]:
bottom = stack.pop()
# break if cannot find left bar
if not stack:
break
left = stack[-1]
# calculate the portion of water can be contained by this position
bound_distance = right - left - 1
bound_height = min(height[left], height[right]) - height[bottom]
result += bound_distance * bound_height
stack.append(right)
return result
Edited on 06/18/2021. Update a more intuitive solution.
Edited on 08/01/2021. Add the monotonic stack based solution.
5/17/2020
[LeetCode] 41. First Missing Positive
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
memo = set(nums)
i = 1
while i in memo:
i += 1
return i
class Solution(object):
def firstMissingPositive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
for i in range(len(nums)):
while nums[i] > 0 and nums[i] <= len(nums) and nums[nums[i]-1] != nums[i]:
# swap nums[i] and nums[nums[i] -1]
# must save nums[i] with tmp
# because current value of nums[i]
# will be used to calculate index
tmp = nums[i]
nums[i] = nums[nums[i]-1]
nums[tmp-1] = tmp
for i in range(len(nums)):
if nums[i] != i + 1:
return i + 1
return len(nums) + 1
5/15/2020
[LeetCode] 40. Combination Sum II
class Solution(object):
def combinationSum2(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
result = []
L = len(candidates)
candidates.sort()
def backtracking(start, partial, n):
if n == 0:
if partial:
result.append(partial)
for i in range(start, L):
if n - candidates[i] < 0:
break
# skip candidates with same value to avoid duplicate result
if i > start and candidates[i] == candidates[i-1]:
continue
backtracking(i + 1, partial + [candidates[i]], n - candidates[i])
backtracking(0, [], target)
return result
[LeetCode] 39. Combination Sum
class Solution(object):
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
N = len(candidates)
result = []
def backtracking(start, partial, n):
if n == 0:
if partial:
result.append(partial)
return
for i in range(start, N):
if n - candidates[i] >= 0:
backtracking(i, partial + [candidates[i]], n - candidates[i])
else:
# since the rest of candiates are larger than current one
# it can safely terminate here.
break
# sort the candidates first for faster searching.
candidates.sort()
backtracking(0, [], target)
return result
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
result = []
for i in range(len(candidates)):
n = candidates[i]
if n == target:
result.append([n])
elif n < target:
# [n] + combinations of numbers sum to (target - n)
# use candidates[i:] to avoid duplicate combo
for combo in self.combinationSum(candidates[i:], target - n):
result.append([n] + combo)
return result
Let A + B = C and Helper(B) = all combinations which sum to target B.
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
candidates.sort()
@lru_cache(maxsize = None)
def helper(target):
result = []
# candidates is array of distinct integers
# it is safe to iterate each number
for n in candidates:
if n == target:
result.append([n])
elif n < target:
for combo in helper(target - n):
# to avoid duplicate result,
# only combine when the first number is larger or equal to n
if n <= combo[0]:
result.append([n] + combo)
return result
return helper(target)
The bottom-up solution:
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
HashMap<Integer, List<List<Integer>>> memo = new HashMap();
List<List<Integer>> emptyList = new ArrayList();
emptyList.add(new ArrayList<Integer>());
memo.put(0, emptyList);
for (int n : candidates) {
for (int t = n; t <= target; t++) {
if (!memo.containsKey(t-n)) {
continue;
}
if (!memo.containsKey(t)) {
memo.put(t, new ArrayList<List<Integer>>());
}
for (List<Integer> prefix : memo.get(t-n)) {
List<Integer> tmp = new ArrayList();
tmp.addAll(prefix);
tmp.add(n);
memo.get(t).add(tmp);
}
}
}
return memo.getOrDefault(target, new ArrayList<List<Integer>>());
}
}
Edited on 12/02/2021. Add the bottom-up solution.
[LeetCode] 38. Count and Say
class Solution(object):
def countAndSay(self, n):
"""
:type n: int
:rtype: str
"""
if n == 1:
return "1"
result = ""
stack = []
for w in self.countAndSay(n-1):
if not stack or stack[-1] == w:
stack.append(w)
else:
result += str(len(stack)) + stack[-1]
stack = [w]
if stack:
result += str(len(stack)) + stack[-1]
return result
[LeetCode] 37. Sudoku Solver
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
ROW = 9
COLUMN = 9
rowMask = [0] * 9
columnMask = [0] * 9
subboxMask = [0] * 9
for y in range(ROW):
for x in range(COLUMN):
if board[y][x] != '.':
n = int(board[y][x])
rowMask[y] |= (1 << n)
columnMask[x] |= (1 << n)
subboxMask[3*(y//3) + x//3] |= (1<<n)
def helper(y, x):
if y >= ROW:
return True
nx = x + 1
ny = y
if nx >= COLUMN:
nx = 0
ny += 1
if board[y][x] != '.':
return helper(ny, nx)
else:
for i in range(1, 10):
if rowMask[y] & (1 << i):
continue
if columnMask[x] & (1 << i):
continue
if subboxMask[3*(y//3) + x//3] & (1 << i):
continue
board[y][x] = str(i)
rowMask[y] |= (1 << i)
columnMask[x] |= (1 << i)
subboxMask[3*(y//3) + x//3] |= (1 << i)
if helper(ny, nx):
return True
board[y][x] = '.'
rowMask[y] ^= (1 << i)
columnMask[x] ^= (1 << i)
subboxMask[3*(y//3) + x//3] ^= (1 << i)
return False
helper(0,0)
Edited on 08/21/2021. Use bitmask to improve performance.
5/12/2020
[LeetCode] 36. Valid Sudoku
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
ROW = COLUMN = 9
def verifyRows():
for y in range(ROW):
seen = set()
for x in range(COLUMN):
if board[y][x] == '.':
continue
if board[y][x] in seen:
return False
seen.add(board[y][x])
return True
def verifyColumns():
for x in range(COLUMN):
seen = set()
for y in range(ROW):
if board[y][x] == '.':
continue
if board[y][x] in seen:
return False
seen.add(board[y][x])
return True
def verifySubBoxs():
for sy in range(0, ROW, 3):
for sx in range(0, COLUMN, 3):
seen = set()
for y in range(sy, sy+3):
for x in range(sx, sx+3):
if board[y][x] == '.':
continue
if board[y][x] in seen:
return False
seen.add(board[y][x])
return True
return verifyRows() and verifyColumns() and verifySubBoxs()
Edited on 08/20/2021. Tidy the solution.
[LeetCode] 35. Search Insert Position
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0; int right = nums.length;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
}
Edited on 11/25/2021. Update the Java solution.
5/11/2020
[LeetCode] 34. Find First and Last Position of Element in Sorted Array
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
def leftMost(left, right):
while left < right:
mid = left + (right - left) // 2
if nums[mid] < target:
left = mid + 1
else:
right = mid # push 'right' to left as far as possible
if right < len(nums) and nums[right] == target:
return right
return -1
def rightMost(left, right):
while left < right:
mid = left + (right - left) // 2
if nums[mid] <= target:
left = mid + 1 # push 'left' to right as far as possible
else:
right = mid
return left - 1
left = leftMost(0, len(nums))
if left == -1:
return [-1, -1]
return [left, rightMost(left, len(nums))]
Use built-in function:
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
left = bisect.bisect_left(nums, target)
if left == len(nums) or nums[left] != target:
return -1, -1
right = bisect.bisect_right(nums, target) - 1
return left, right
Edited on 02/27/2021. Use buillt-in lib.
[LeetCode] 33. Search in Rotated Sorted Array
0 1 2 4 5 6 7
7 0 1 2 4 5 6
6 7 0 1 2 4 5
5 6 7 0 1 2 4
4 5 6 7 0 1 2
2 4 5 6 7 0 1
1 2 4 5 6 7 0
Base on the sample data, it shows that when nums[mid] < nums[right], the right part is sorted. Otherwise, the left part is sorted. So we may use the "First" and "Last" number of the sorted part to decide search in left of right part.
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
left, right = 0, len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] == target:
return mid
if nums[mid] < nums[right]:
# right part is sorted
if nums[mid] < target <= nums[right]:
left = mid + 1
else:
right = mid - 1
else:
# left part is sorted
if nums[left] <= target < nums[mid]:
right = mid - 1
else:
left = mid +1
return -1
[LeetCode] 32. Longest Valid Parentheses
class Solution:
def longestValidParentheses(self, s: str) -> int:
if not s: return 0
N = len(s)
dp = [0] * N
for i in range(1, N):
if s[i] == '(':
continue
# s[i] == ')'
if s[i-1] == '(':
dp[i] = dp[i-2] + 2
else:
left = i - dp[i-1] - 1
if left >= 0 and s[left] == '(':
dp[i] = dp[i-1] + 2
if left - 1 >= 0:
dp[i] += dp[left - 1]
return max(dp)
A Top-Down approach:
class Solution:
def longestValidParentheses(self, s: str) -> int:
@lru_cache(maxsize = None)
def helper(i):
if i <= 0 or s[i] == '(': return 0
# s[i] == ')'
if i - 1 >= 0:
if s[i-1] == '(':
return helper(i-2) + 2
else:
# s[i-1] == ')'
n = helper(i-1)
if n > 0:
left = i - n - 1
if left >= 0 and s[left] == '(':
return helper(left-1) + 2 + helper(i-1)
return 0
N = len(s)
return max(map(helper, range(N))) if N > 0 else 0
Edit on 04/03/2021. Add the Top-Down approach.
5/10/2020
[LeetCode] 31. Next Permutation
class Solution(object):
def nextPermutation(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
def reverse(nums, start, end):
left = start
right = end - 1
while left < right:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right -= 1
if len(nums) < 2:
return nums
i = len(nums) - 2
# find pivot which is the first number from back where acending order starts
while i >= 0 and nums[i] >= nums[i+1]:
i -= 1
if i == -1:
nums.sort()
return nums
# find the first number from back which is just larger than the pivot number
j = len(nums) - 1
while j > i and nums[j] <= nums[i]:
j -= 1
# swap
nums[i], nums[j] = nums[j], nums[i]
# reverse the right of pivot
reverse(nums, i+1, len(nums))
return nums
[LeetCode] 30. Substring with Concatenation of All Words
from collections import defaultdict
class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
result = []
if not s or not words:
return result
L = len(words)
N = len(words[0])
wordCnt = defaultdict(int)
for w in words:
wordCnt[w] += 1
for i in range(len(s) - N*L + 1):
# counter of a valid word in range [i : i+N*L+1]
strCnt = defaultdict(int)
for j in range(L):
substr = s[i+j*N: i+j*N+N]
if wordCnt[substr] == 0:
break
strCnt[substr] += 1
if strCnt[substr] > wordCnt[substr]:
break
else:
result.append(i)
return result
[LeetCode] 29. Divide Two Integers
MAX_INT = 2 ** 31 - 1
MIN_INT = -2 ** 31
class Solution:
def divide(self, dividend: int, divisor: int) -> int:
if dividend == 0: return 0
sign = -1 if (dividend > 0) ^ (divisor > 0) else 1
if dividend == MIN_INT:
if divisor == MIN_INT: return 1
if divisor == -1: return MAX_INT
divisor = abs(divisor)
return sign * (1 + self.divide(abs(dividend + divisor), divisor))
if divisor == MIN_INT: return 0
if abs(divisor) == 1: return sign * abs(dividend)
dividend = abs(dividend)
divisor = abs(divisor)
result = 0
while divisor <= dividend:
tmp = divisor
count = 1
while tmp << 1 <= dividend:
count <<= 1
tmp <<= 1
dividend -= tmp
result += count
return sign * result
Edited on 02/27/2021. Process edge case when dividend == MIN_INT.
5/09/2020
[LeetCode] 28. Implement strStr()
class Solution(object):
def strStr(self, haystack, needle):
"""
:type haystack: str
:type needle: str
:rtype: int
"""
if not needle:
return 0
for i in range(len(haystack) - len(needle) + 1):
for j in range(len(needle)):
if haystack[i+j] != needle[j]:
break
else:
# for-loop completed without break
return i
return -1
[LeetCode] 27. Remove Element
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
p1, p2 = 0, 0
while p2 < len(nums):
if nums[p2] != val:
nums[p1] = nums[p2]
p1 += 1
p2 += 1
return p1
[LeetCode] 26. Remove Duplicates from Sorted Array
class Solution(object):
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums:
return 0
p1, p2 = 1, 1
last = nums[0]
while p2 < len(nums):
if nums[p2] != last:
nums[p1] = nums[p2]
last = nums[p2]
p1 += 1
p2 += 1
return p1
[LeetCode] 25. Reverse Nodes in k-Group
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
if not head:
return None
# find the first k nodes
i = 0
p = head
while i < k and p:
p = p.next
i += 1
# return the original list if it has less nodes than k
if i < k:
return head
# reverse the first k nodes
pre = None
cur = head
while cur != p:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
# append to the rest reversed groups
head.next = self.reverseKGroup(p, k)
return pre
Updated on 07/18/2021. Update for a simpler recursive solution.
[LeetCode] 24. Swap Nodes in Pairs
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def swapPairs(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head and head.next:
tmp = head.next.next
left, right = head, head.next
right.next = left
left.next = self.swapPairs(tmp)
return right
return head
[LeetCode] 23. Merge k Sorted Lists
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
def merge(l1, l2):
if l1 and l2:
if l1.val < l2.val:
l1.next = merge(l1.next, l2)
return l1
else:
l2.next = merge(l1, l2.next)
return l2
return l1 if l1 else l2
def helper(left, right):
if left == right:
return None
if right - left == 1:
return lists[left]
if right - left == 2:
return merge(lists[left], lists[left+1])
mid = left + (right - left) // 2
return merge(helper(left, mid), helper(mid, right))
return helper(0, len(lists))
Use priority queue to merge K sorted list. N = max length of lists
Time Compleixty = O(N * Log K)
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode dummy = new ListNode();
ListNode p = dummy;
PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> a.val - b.val);
for (ListNode head : lists) {
if (head != null) pq.offer(head);
}
while (!pq.isEmpty()) {
p.next = pq.poll();
p = p.next;
if (p.next != null) pq.offer(p.next);
}
return dummy.next;
}
}
[LeetCode] 22. Generate Parentheses
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
def helper(left, right, tmp):
if left == right == n:
yield "".join(tmp)
else:
if left < n:
tmp.append("(")
yield from helper(left + 1, right, tmp)
tmp.pop()
if left > right:
tmp.append(")")
yield from helper(left, right + 1, tmp)
tmp.pop()
return list(helper(0, 0, []))
Edited on 06/16/2021. Refactor by using 'yield'.
[LeetCode] 21. Merge Two Sorted Lists
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
dummy = ListNode()
p = dummy
while l1 and l2:
if l1.val < l2.val:
p.next = l1
l1 = l1.next
else:
p.next = l2
l2 = l2.next
p = p.next
if l1:
p.next = l1
elif l2:
p.next = l2
return dummy.next
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if l1 and l2:
if l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
elif l1:
return l1
elif l2:
return l2
[LeetCode] 20. Valid Parentheses
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
Map<Character, Character> pairs = new HashMap<>() {
{
put('(', ')');
put('[', ']');
put('{', '}');
}
};
for (char a : s.toCharArray()) {
if (pairs.containsKey(a)) {
stack.push(a);
} else {
if (stack.isEmpty() || pairs.get(stack.pop()) != a) return false;
}
}
return stack.isEmpty();
}
}
Edited on 03/12/2022. Use map to pair brackets.
[LeetCode] 19. Remove Nth Node From End of List
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
# use dummy head node to handle the case that needs to remove the first node.
dummy = ListNode(0)
dummy.next = head
p1, p2 = dummy, dummy
while p2 and n >= 0:
p2 = p2.next
n -= 1
while p2 and p1:
p2 = p2.next
p1 = p1.next
if p1 and p1.next:
p1.next = p1.next.next
return dummy.next
[LeetCode] 18. 4Sum
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
nums.sort()
L = len(nums)
result = []
for i in range(L-3):
if i > 0 and nums[i] == nums[i-1]:
continue
for j in range(i+1, L-2):
if j > i + 1 and nums[j] == nums[j-1]:
continue
left, right = j + 1, L - 1
while left < right:
# early termination
if nums[i] + nums[j] + nums[left] + nums[left] > target:
break
tmp = nums[i] + nums[j] + nums[left] + nums[right]
if tmp < target:
k = left + 1
while k < right and nums[k] == nums[left]:
k += 1
continue
left = k
elif tmp > target:
l = right - 1
while l > left and nums[l] == nums[right]:
l -= 1
continue
right = l
else:
result.append([nums[i], nums[j], nums[left], nums[right]])
k = left + 1
while k < right and nums[k] == nums[left]:
k += 1
continue
left = k
l = right - 1
while l > left and nums[l] == nums[right]:
l -= 1
continue
right = l
return result
[LeetCode] 17. Letter Combinations of a Phone Number
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
letters = {"2": "abc", "3": "def", "4": "ghi", "5": "jkl", "6": "mno", "7": "pqrs", "8": "tuv", "9":"wxyz"}
result = []
def backtrack(i, tmp):
if i == len(digits):
if tmp:
result.append(tmp)
return
for t in letters[digits[i]]:
backtrack(i+1, tmp + t)
backtrack(0, "")
return result
BFS based solution:
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
letters = {"2": "abc", "3": "def", "4": "ghi", "5": "jkl", "6": "mno", "7": "pqrs", "8": "tuv", "9":"wxyz"}
if not digits: return []
result = []
queue = deque([[l, 1] for l in letters[digits[0]]])
while queue:
for _ in range(len(queue)):
w , index = queue.popleft()
if index == len(digits):
result.append(w)
else:
for l in letters[digits[index]]:
queue.append([w + l, index + 1])
return result
An iterative solution. Start from the last digit to the first digit, add letter of current digit to the front of last letter combinations.
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits: return []
letters = {'2': 'abc', '3': 'def', '4':'ghi', '5':'jkl', '6':'mno', '7':'pqrs', '8':'tuv', '9':'wxyz' }
ds = [d for d in digits]
result = [[l] for l in letters[ds.pop()]]
while ds:
suffix = result[:]
result = []
for l in letters[ds.pop()]:
for s in suffix:
result.append([l] + s)
return [''.join(t) for t in result]
Edited 04/24/2021. Add the iterative solution.
[LeetCode] 16. 3Sum Closest
class Solution(object):
def threeSumClosest(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
nums.sort()
N = len(nums)
result = nums[0] + nums[1] + nums[2] # assume the init value of result
for i in range(N-2):
if i > 0 and nums[i] == nums[i-1]:
continue
left, right = i + 1, N-1
while left < right:
tmp = sum([nums[i], nums[left], nums[right]])
if abs(result - target) > abs(tmp - target):
result = tmp
if tmp == target:
return target
if tmp < target:
j = left + 1
while j < right and nums[j] == nums[left]:
j += 1
left = j
else:
k = right - 1
while k > left and nums[k] == nums[right]:
k -= 1
right = k
return result
Edited of 07/27/2021. Update result variable's init value.