class Solution:
def validUtf8(self, data: List[int]) -> bool:
x = 0
for i in data:
if i > 247 or x > 0 and (i > 191 or i < 128): return False
elif x > 0:
x -= 1
continue
if i > 239: x = 3 # "11110***"需要跟范围 (127, 192) 中的三个数
elif i > 223: x = 2
elif i > 191: x = 1
elif i > 127: return False
return x < 1
class Solution {
public boolean validUtf8(int[] data) {
int x = 0;
for (int i : data){
if (i > 247 || x > 0 && (i > 191 || i < 128)) return false;
else if (x > 0){
x--;
continue;
}
if (i > 239) x = 3; // "11110***"需要跟范围 (127, 192) 中的三个数
else if (i > 223) x = 2;
else if (i > 191) x = 1 ;
else if (i > 127) return false;
}
return x < 1;
}
}
class Solution:
def corpFlightBookings(self, bookings: List[List[int]], n: int) -> List[int]:
res = [0] * n
for a, b, x in bookings: # 从 a 到 b 各个航班
res[a-1] += x # 从 a - 1 (航班转换为索引) 开始 +
if b < n:
res[b-1+1] -= x # 到 b - 1, 后面结束 -。
return list(accumulate(res)) # 前缀和统计
class Solution {
public int[] corpFlightBookings(int[][] bookings, int n) {
int[] res = new int[n];
for (int[] b : bookings){
res[b[0] - 1] += b[2];
if (b[1] < n) res[b[1]] -= b[2];
}
for (int i = 1; i < n; i++) res[i] += res[i-1];
return res;
}
}
class Solution:
def goodDaysToRobBank(self, security: List[int], time: int) -> List[int]:
n = len(security)
res, front, back = [], [0] * n, [0] * n
for i in range(1, n):
if security[i] <= security[i - 1]:
front[i] += front[i - 1] + 1
else: front[i] = 0
for j in range(n - 2, -1, -1):
if security[j] <= security[j + 1]:
back[j] += back[j + 1] + 1
else: back[j] = 0
for k in range(n):
if front[k] >= time and back[k] >= time: res.append(k)
return res
class Solution:
def convert(self, s: str, numRows: int) -> str:
if numRows in [1, len(s)]: return s # 一行或一列
# i, flag, res = 0, -1, [''] * numRows
# for c in s:
# res[i] += c
# # 关键点,转折点。i 初值为 -1.
# if i == 0 or i == numRows -1:
# flag = -flag
# i += flag
# return ''.join(res)
i, flag, res = 0, -1, [[] for _ in range(numRows)]
for c in s:
res[i].append(c)
if i == 0 or i == numRows - 1: flag = -flag
i += flag
return ''.join(''.join(col) for col in res)
# return ''.join(c for col in res for c in col)
class Solution {
public String convert(String s, int numRows) {
if (numRows == 1 || numRows == s.length()) return s;
int i = 0, flag = -1;
String[] res = new String[numRows];
Arrays.fill(res, "");
for (char c : s.toCharArray()){
res[i] += c;
if (i == 0 || i == numRows - 1) flag = -flag;
i += flag;
}
return String.join("", res);
}
}
class Solution {
public String convert(String s, int numRows) {
if (numRows == 1 || numRows == s.length()) return s;
List<StringBuilder> rows = new ArrayList<StringBuilder>();
for (int i = 0; i < numRows; i++) rows.add(new StringBuilder());
int i = 0, flag = -1;
for(char c : s.toCharArray()) {
rows.get(i).append(c);
if(i == 0 || i == numRows -1) flag = - flag;
i += flag;
}
StringBuilder res = new StringBuilder();
for(StringBuilder row : rows) res.append(row);
return res.toString();
}
}
class Solution {
public String convert(String s, int numRows) {
if (numRows == 1 || numRows == s.length()) return s;
StringBuilder[] rows = new StringBuilder[numRows];
for (int i = 0; i < numRows; i++) rows[i] = new StringBuilder(); // ok
// for (StringBuilder row : rows) row = new StringBuilder(); // 不行 ?
// Arrays.fill(rows, new StringBuilder()); // 同一个实例填充
int i = 0, flag = -1;
for(char c : s.toCharArray()) {
rows[i].append(c);
if(i == 0 || i == numRows -1) flag = - flag;
i += flag;
}
StringBuilder res = new StringBuilder();
for(StringBuilder row : rows) res.append(row);
return res.toString();
}
}
只要 “R.L” 点就不倒,左右不论多少。
class Solution:
def pushDominoes(self, dominoes: str) -> str:
# 只要 "R.L" 点就不倒,左右不论多少。
while '.L' in dominoes or 'R.' in dominoes:
dominoes = dominoes.replace("R.L", "T").replace(".L", "LL").replace("R.", "RR")
return dominoes.replace("T", "R.L")
# 方法二:
d = list(dominoes) + ['R'] # 添加哨兵。
pre, i = 'L', 0
for j, c in enumerate(d):
if c == '.': continue # '.' 路过
if pre == c: # R -> R 填充 R, L -> L 填充 L
d[i:j] = [c] * (j - i)
if c == 'L' and pre == 'R': # R -> L 各分一半,奇数留中。
k, r = divmod(j-i, 2)
d[i:j] = ['R']*k + ['.']*r + ["L"]*k
i = j + 1
pre = c
return ''.join(d[:-1])
class Solution {
public String pushDominoes(String dominoes) {
char[] d = (dominoes + "R").toCharArray();
char pre = 'L';
int i = 0;
for (int j = 0; j < d.length; j++){
if (d[j] == '.') continue;
if (pre == d[j]) Arrays.fill(d, i, j, d[j]);
if (pre == 'R' && d[j] == 'L') {
int k = (j - i) / 2;
Arrays.fill(d, i, i + k, 'R');
Arrays.fill(d, j - k, j, 'L');
}
i = j + 1;
pre = d[j];
}
return new String(Arrays.copyOfRange(d, 0, d.length - 1));
}
}
煎饼排序,唯一允许的操作是反转序列的某些前缀的元素。
arr 是 1 到 n 的一个排列,最大值是 n。把最大值开始的前缀进行反转,整体再反转,最大值放在最后。
class Solution:
def pancakeSort(self, arr: List[int]) -> List[int]:
res, m = [], len(arr)
for n in range(m, 1, -1):
k = arr.index(n) + 1 # 找到 k 反转 arr[:k],再反转。
res.append(k)
arr[:k] = arr[:k][::-1]
res.append(n)
arr[:n] = arr[:n][::-1]
return res
class Solution: # 递归
def __init__(self): self.q = []
def pancakeSort(self, arr: List[int]) -> List[int]:
# 递归一 定义成员变量 q
# n = len(arr) # 长度 = 最大值
# if n <= 1: return []
# if arr[-1] < n:
# k = arr.index(n) + 1
# self.q.append(k)
# arr[:k] = arr[:k][::-1]
# self.q.append(n)
# arr = list(reversed(arr))
# self.pancakeSort(arr[:-1])
# return self.q
# 递归二 定义递归函数,使用局部变量 q
# def f(arr):
# if (n := len(arr)) <= 1: return
# if (k := arr.index(n) + 1) < n:
# arr = (arr[:k][::-1] + arr[k:])[::-1]
# q.extend([k, n])
# f(arr[:-1])
# q = []
# f(arr)
# return q
# 递归三 ★ 定义递归函数,使用 + 返回列表
# def f(arr):
# if (n := len(arr)) <= 1: return []
# if (k := arr.index(n) + 1) < n:
# arr = (arr[:k][::-1] + arr[k:])[::-1]
# return [k, n] + f(arr[:-1])
# return f(arr)
# 递归三
return [] if (n := len(arr)) <= 1 else [k, n] + self.pancakeSort((arr[:k][::-1] + arr[k:])[::-1]) if (k := arr.index(n) + 1) < n else self.pancakeSort(arr[:-1])
class Solution {
public List<Integer> pancakeSort(int[] arr) {
List<Integer> ret = new ArrayList<Integer>();
for (int n = arr.length; n > 1; n--) {
int index = 0;
for (int i = 1; i < n; i++) { // 找最大值 n 索引
// if (arr[i] >= arr[index]) index = i;
if (arr[i] == n){
index = i;
break;
}
}
if (index == n - 1) continue; // 最大值正好是最后一个,不用反转。
reverse(arr, index);
reverse(arr, n - 1);
ret.add(index + 1);
ret.add(n);
}
return ret;
}
public void reverse(int[] arr, int end) {
for (int i = 0, j = end; i < j; i++, j--) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
// 使用 List 的 indexOf,subList, Collections.reverse
class Solution {
public List<Integer> pancakeSort(int[] arr) {
ArrayList<Integer> res = new ArrayList<>();
ArrayList<Integer> list = new ArrayList<>(); // arr 转换成 ArrayList
for (int i = 0; i < arr.length; i++) list.add(arr[i]);
for (int i = arr.length; i > 1; i--){
int k = list.indexOf(i) + 1;
res.add(k);
Collections.reverse(list.subList(0, k)); // 反转
res.add(i);
Collections.reverse(list.subList(0, i));
}
return res;
}
}
dp(start, n) 表示骑士从数字 start 开始,跳了 n - 1 步得到不同的 n 位数字的个数。
f(start, n) 只和 f(x, n - 1) 有关,使用滚动数组。
class Solution:
def knightDialer(self, n: int) -> int:
MOD = 10**9 + 7
moves = [[4,6],[6,8],[7,9],[4,8],[3,9,0],[],[1,7,0],[2,6],[1,3],[2,4]]
dp = [1] * 10 # 初始状态
for _ in range(n - 1): # n - 1 次移动
tmp = [0] * 10
for pre, count in enumerate(dp): # dp 上一次的状态
for cur in moves[pre]:
tmp[cur] += count
tmp[cur] %= MOD
dp = tmp # 保留当前状态
return sum(dp) % MOD
0 只能跳向 46,1379 只能跳向 28 和 46,而 28 只能跳向 1379,46 只能跳向 0 和 1379。
1379、28、46 三组内部互相是完全对称的,分别把 0、1379、28、46 分组为 a、b、c、d,初始值分别为 1, 4, 2, 2。
class Solution:
def knightDialer(self, n: int) -> int:
if n==1: return 10
a, b, c, d, MOD = 1, 4, 2, 2, 1000000007
for i in range(n - 1):
a, b, c, d = d, (2*c + 2*d) % MOD, b, (2*a + b) % MOD
return (a + b + c + d) % MOD
class Solution {
public int knightDialer(int n) {
if (n == 1) return 10;
// a(0), b(1379), c(28), d(46)
long a = 1, b = 4, c = 2, d = 2, MOD = 1000000007;
while (--n > 0){
long u = a, v = b, w = c, x = d;
a = x; b = (2*w + 2*x) % MOD; c = v; d = (2*u + v) % MOD;
}
return (int)((a + b + c + d) % MOD);
}
}
定义 dp[step][i][j] 表示骑士从棋盘上的点 (i, j) 出发,走了 step 步时仍然留在棋盘上的概率。
特别地,当点 (i, j) 不在棋盘上时,dp[step][i][j] = 0;当点 (i, j) 在棋盘上且step=0 时,dp[step][i][j] = 1。对于其他情况, dp [ step ] [ i ] [ j ] = 1 8 × ∑ di , dj dp [ step − 1 ] [ i + d i ] [ j + d j ] \textit{dp}[\textit{step}][i][j] = \dfrac{1}{8} \times \sum\limits_{\textit{di}, \textit{dj}} \textit{dp}[\textit{step}-1][i+di][j+dj] dp[step][i][j]=81×di,dj∑dp[step−1][i+di][j+dj]。其中 (di,dj) 表示走法对坐标的偏移量,具体为 (-2, -1),(-2, 1),(2, -1),(2, 1),(-1, -2),(-1, 2),(1, -2),(1, 2) 共 8 种。
class Solution:
def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
dp = [[[0] * n for _ in range(n)] for _ in range(k + 1)]
for step in range(k + 1):
for i in range(n):
for j in range(n):
if step == 0: dp[step][i][j] = 1
else:
for a, b in ((-2, -1), (-2, 1), (2, -1), (2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2)):
x, y = i + a, j + b
if 0 <= x < n and 0 <= y < n:
dp[step][i][j] += dp[step - 1][x][y] / 8
return dp[k][row][column]
class Solution {
static int[][] dirs = {{-2, -1}, {-2, 1}, {2, -1}, {2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}};
public double knightProbability(int n, int k, int row, int column) {
double[][][] dp = new double[k + 1][n][n];
for (int step = 0; step <= k; step++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (step == 0) dp[step][i][j] = 1;
else {
for (int[] dir : dirs) {
int x = i + dir[0], y = j + dir[1];
if (x >= 0 && x < n && y >= 0 && y < n) {
dp[step][i][j] += dp[step - 1][x][y] / 8;
}}}}}}
return dp[k][row][column];
}
}
class Solution:
def singleNonDuplicate(self, nums: List[int]) -> int:
# # 1 O(n)
# for i in range(0, len(nums) - 1, 2):
# if nums[i] != nums[i + 1]:
# return nums[i]
# return nums[-1] # 最后一个元素
# # 2 O(n)
i, j = 0, len(nums) - 1
# while i < j:
# if nums[i] != nums[i+1]: return nums[i]
# if nums[j] != nums[j-1]: return nums[j]
# i += 2
# j -= 2
# return nums[i]
# # 3 符合题意 O(log n)
while i < j:
mid = (i + j) // 2
'''
# mid -= mid & 1 # even 不变,odd 减一,统一为偶数。
# if nums[mid] == nums[mid + 1]: i = mid + 2
'''
if nums[mid] == nums[mid ^ 1]: i = mid + 1 # even +1 odd -1 统一奇偶
else: j = mid
return nums[i]
class Solution {
public int singleNonDuplicate(int[] nums) {
int res = 0, n = nums.length;
int i = 0, j = n - 1;
while (i < j){
int mid = (i + j) / 2;
// 目标下标 x 一定是 even;
// even 和后一个比较, odd 和前一个比较。
// even:mid ^ 1 = mid + 1(后一个), odd:mid ^ 1 = mid - 1(前一个)
if (nums[mid] == nums[mid ^ 1]){
i = mid + 1; // x > mid
/*
mid -= mid & 1; // odd: 变前一个
if (nums[mid] == nums[mid + 1]){
i = mid + 2; // 下一个 even
*/
} else j = mid; // x <= mid
}
return nums[j]; // i = j
}
}
class Solution:
def numEnclaves(self, grid: List[List[int]]) -> int:
# m, n, q = len(grid), len(grid[0]), []
# for j in range(n): q.extend([j, (m-1)*1000 + j])
# for i in range(1, m-1): q.extend([i*1000, i*1000 + n-1])
# while q:
# i, j = divmod(q.pop(), 1000)
# if grid[i][j] == 0: continue # 其它地方都没有检查
# grid[i][j] = 0
# i > 0 and q.append((i-1)*1000 + j)
# i < m-1 and q.append((i+1)*1000 + j)
# j > 0 and q.append(i*1000 + j-1)
# j < n-1 and q.append(i*1000 + j+1)
def dfs(i, j): # 深度搜索
grid[i][j] = 0
for k in range(4):
x, y = i + dir[k], j + dir[k+1]
if 0 < x < m-1 and 0 < y < n-1 and grid[x][y]:
dfs(x, y)
m, n, dir = len(grid), len(grid[0]), (1, 0, -1, 0, 1)
for j in range(n):
if grid[0][j]: dfs(0, j) # 第一行
if grid[m-1][j]: dfs(m-1, j) # 最后一行
for i in range(1, m - 1): # 中间部分
if grid[i][0]: dfs(i, 0)
if grid[i][n-1]: dfs(i, n-1)
return sum(sum(row) for row in grid)
class Solution {
public int numEnclaves(int[][] grid) {
int m = grid.length, n = grid[0].length;
int result = 0;
for(int i = 0; i < m; i++){
dfs(grid, i, 0); // 没有检查 grid[i][j] = 1
dfs(grid, i, n - 1);
}
for(int j = 0; j < n; j++){
dfs(grid, 0, j);
dfs(grid, m - 1, j);
}
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
result += grid[i][j]; // 求和
}
}
return result;
}
public static void dfs(int[][] grid, int i, int j){
if (grid[i][j] == 0) return; // 其它地方没有检查
grid[i][j] = 0;
int[] dir = new int[]{1, 0, -1, 0, 1};
for (int k = 0; k < 4; k++){
int x = i + dir[k], y = j + dir[k+1];
if(x > 0 && y > 0 && x < grid.length-1 && y < grid[0].length-1){
dfs(grid, x, y);
}
}
}
}
class Solution:
def simplifiedFractions(self, n: int) -> List[str]:
res, vis = [], set()
for i in range(2, n + 1):
for j in range(1, i):
if j / i not in vis:
res.append(f"{j}/{i}")
vis.add(j/i)
return res
class Solution {
public List<String> simplifiedFractions(int n) {
Set<Float> vis = new HashSet<>();
List<String> res = new ArrayList<>();
for (int i = 2; i <= n; i++){
for (int j = 1; j < i; j++){
if (!vis.contains((float)j / i)){
res.add(j + "/" + i);
vis.add((float)j / i);
}
}
}
return res;
}
}
记录遍历过的最大的防御力(maxdef)的角色 A,如果当前的角色 B 的防御力小于 maxdef,那么 B 的攻击力一定也小于 A 的攻击力。
class Solution:
def numberOfWeakCharacters(self, properties: List[List[int]]) -> int:
res = 0
properties.sort(key=lambda x: (-x[0], x[1]))
maxdef = 0
for _, d in properties:
if maxdef > d: res += 1
else: maxdef = d
return res
class Solution {
public int numberOfWeakCharacters(int[][] properties) {
int maxdef = 0, res = 0;
Arrays.sort(properties, (o1, o2) -> o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0]);
for (int[] role : properties){
if (maxdef > role[1]) res ++;
else maxdef = role[1];
}
return res;
}
}
class Solution:
def getMaximumGold(self, grid: List[List[int]]) -> int:
def dfs(i: int, j: int, gold: int) -> None:
gold += grid[i][j]
nonlocal ans
ans = max(ans, gold)
grid[i][j] = -grid[i][j]
for x, y in ((i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)):
if 0 <= x < m and 0 <= y < n and grid[x][y] > 0:
dfs(x, y, gold)
grid[i][j] = -grid[i][j] # 回溯
m, n = len(grid), len(grid[0])
ans = 0
for i in range(m):
for j in range(n):
if grid[i][j] != 0:
dfs(i, j, 0)
return ans
成员变量
class Solution {
int[][] grid;
int m, n, ans = 0;
int[] dirs = new int[]{0, 1, 0, -1, 0};
public int getMaximumGold(int[][] grid) {
m = grid.length;
n = grid[0].length;
this.grid = grid;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(grid[i][j] != 0)
dfs(i, j, 0);
}
}
return ans;
}
private void dfs(int x, int y, int gold){
gold += grid[x][y];
ans = Math.max(ans, gold);
grid[x][y] = -grid[x][y];
for(int k = 0; k < 4; k++){ // {0, 1, 0, -1, 0}
int i = dirs[k] + x, j = dirs[k + 1] + y;
if(i >= 0 && i < m && j >= 0 && j < n && grid[i][j] > 0){
dfs(i, j, gold);
}
}
grid[x][y] = -grid[x][y];
}
}
返回值
class Solution {
int[][] grid;
int m, n = 0;
int[] dirs = new int[]{0, 1, 0, -1, 0};
public int getMaximumGold(int[][] grid) {
int ans = 0;
m = grid.length;
n = grid[0].length;
this.grid = grid;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(grid[i][j] != 0 )
ans = Math.max(ans, dfs(i, j));
}
}
return ans;
}
private int dfs(int x, int y){
int ans = 0;
grid[x][y] = -grid[x][y];
for(int k = 0; k < 4; k++){ // {0, 1, 0, -1, 0}
int i = dirs[k] + x, j = dirs[k + 1] + y;
if(i >= 0 && i < m && j >= 0 && j < n && grid[i][j] > 0){
ans = Math.max(ans, dfs(i, j));
}
}
grid[x][y] = -grid[x][y];
return ans + grid[x][y];
}
}
始终先用最多的两个后用次多的
class Solution:
def longestDiverseString(self, a: int, b: int, c: int) -> str:
d = {'a':a, 'b':b, 'c':c}
q = []
while (cnt := sorted([k for k, v in d.items() if v], key = lambda x : -d[x])):
for ch in cnt:
if q[-2:] != [ch, ch]:
q.append(ch)
d[ch] -= 1
break
if len(cnt) == 1 and q[-2:] == cnt * 2: break
return ''.join(q)
class Solution:
def gridGame(self, G: List[List[int]]) -> int:
T = [0] + list(accumulate(G[0]))
B = [0] + list(accumulate(G[1]))
return min(max(T[len(T) - 1] - T[i], B[i-1]) for i in range(1, len(T)))