更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验
C++
中的 next_permutation
函数,生成指定序列的下一个全排列nums[i] < nums[i + 1]
的元素 nums[i]
nums[i]
:说明当前序列是最后一个排列,函数将序列重排为第一个排列,并返回 false
nums[i]
:继续从最右端开始,找到第一个满足 nums[i] < nums[j]
的元素 nums[j]
。nums[i]
和 nums[j]
,然后从 i + 1
开始将序列反转,使得它们按照升序排列。class Solution {
public void nextPermutation(int[] nums) {
int n = nums.length;
int i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i --;
if (i >= 0) {
int j = n - 1;
while (nums[j] <= nums[i]) j --;
swap(nums, i, j);
}
reverse(nums, i + 1, n - 1);
}
private void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
private void reverse(int[] nums, int l, int r) {
while (l < r) {
this.swap(nums, l, r);
l ++; r --;
}
}
}
Stack
存储所有 (
的下标class Solution {
public int longestValidParentheses(String s) {
Stack<Integer> stack = new Stack<>();
int ans = 0;
int start = -1; // 有效括号序列的起始位置
for (int i = 0; i < s.length(); i++) {
// 将左括号的位置压入栈中
if (s.charAt(i) == '(') stack.push(i);
else {
if (stack.isEmpty()) {
start = i; // 当前右括号无法匹配,更新起始位置
}
else {
stack.pop();
// 栈为空,表示当前右括号匹配到有效括号序列的末尾
if (stack.isEmpty()) ans = Math.max(ans, i - start);
else ans = Math.max(ans, i - stack.peek()); // 栈不为空,计算当前有效括号序列的长度
}
}
}
return ans;
}
}
优化:
res
,第一次扫代表 (
,起始位置 l = 0
,第二次扫代表 )
,起始位置 r = n - 1
(
,res ++
;)
时:
res == 0
,则更新最长有效括号的长度 ans
,并更新起始位置 l
res --
,若此时 res == 0
,则匹配了全部左括号,更新 ans
ans
已经大于等于剩余未匹配左括号的长度(n - l),则直接返回 ans
。ans
。class Solution {
public int longestValidParentheses(String s) {
int res = 0;
int n = s.length();
int ans = 0, l = 0;
// 从左扫第一遍
for (int i = 0; i < n; i ++) {
if (s.charAt(i) == '(') {
res ++; continue;
}
// 遇到右括号,且当前没有匹配的左括号
if (res == 0) {
ans = Math.max(ans, i - l); // 更新最长有效括号的长度
l = i + 1; // 更新起始位置
}
else {
res --; // 遇到右括号,且有匹配的左括号,res --
if (res == 0) ans = Math.max(ans, i - l + 1);
}
}
// 如果遍历完字符串后,仍有未匹配的左括号
if (res == 0 || ans >= n - l) return ans;
int r = n - 1; res = 0;
// 从右扫第二遍
for (int i = n - 1; i > l; i --) {
if (s.charAt(i) == ')') {
res ++; continue;
}
if (res == 0) {
ans = Math.max(ans, r - i);
r = i - 1;
}
else
res --;
if (res == 0) ans = Math.max(ans, r - i + 1);
}
}
return ans;
}
}
nums[i] >= nums[0]
,而右侧 nums[i] < nums[0]
target
在旋转点的左半部分还是右半部分target >= nums[0]
时在左半部分l, r
为新的目标区间继续查找class Solution {
public int search(int[] nums, int target) {
int n = nums.length;
if (n == 1) return nums[0] == target ? 0 : -1;
int l = 0, r = n - 1;
// 寻找旋转点,查找第一个不满足 >= nums[0] 的元素下标
while (l <= r) {
int mid = (l + r) >> 1;
if (nums[mid] == target) return mid;
if (nums[mid] >= nums[0]) l = mid + 1;
else r = mid - 1;
}
if (l < n && nums[l] == target) return l;
// 判断 target 在左半区间还是右半区间
if (target >= nums[0]) {
r = l - 1; l = 0; // 更新边界为左半区间
}
else {
l ++; r = n - 1; // 更新边界为右半区间
}
// 在剩下半个区间查找 == target 的元素下标
while (l <= r) {
int mid = (l + r) >> 1;
if (nums[mid] == target) return mid;
if (nums[mid] < target) l = mid + 1;
else r = mid - 1;
}
return l < n && nums[l] == target ? l : -1;
}
}
target
的数,期间更新 nums[mid] == target
的下标,即为第一个位置target
的数,期间更新 nums[mid] == target
的下标,即为第二个位置class Solution {
public int[] searchRange(int[] nums, int target) {
int n = nums.length;
int l = 0, r = n - 1;
int res = -1;
while (l <= r) {
int mid = (l + r) >> 1;
if (nums[mid] == target) res = mid;
if (nums[mid] < target) l = mid + 1;
else r = mid - 1;
}
if (res == -1) return new int[]{-1, -1};
l = res; r = n - 1; // l 从 res 开始或 0 开始都行
int cnt = -1;
while (l <= r) {
int mid = (l + r) >> 1;
if (nums[mid] == target) cnt = mid;
if (nums[mid] > target) r = mid - 1;
else l = mid + 1;
}
return new int[]{res, cnt};
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int l = 0, r = nums.length - 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (nums[mid] == target) return mid;
if (nums[mid] < target) l = mid + 1;
else r = mid - 1;
}
return l;
}
}
boolean[][]
维护每组格子的状态board[i][j]
,所在的组编号 u
映射为 u = i / 3 * 3 + j / 3
boolean[][] vis[u][num]
表示第 u
组数字 num
是否已经存在class Solution {
public boolean isValidSudoku(char[][] board) {
boolean[][] vis = new boolean[10][10]; // 记录小方块的填数状态
boolean[][] row = new boolean[10][10]; // 记录每一行的填数状态
boolean[][] col = new boolean[10][10]; // 记录每一列的填数状态
for (int i = 0; i < 9; i ++) {
for (int j = 0; j < 9; j ++) {
char t = board[i][j];
if (t == '.') continue; // '.' 无所谓,直接跳过
int num = t - '0';
// 组编号映射
int u = i / 3 * 3 + j / 3;
// 只要有一个已经存放过都不成立
if (vis[u][num] || row[i][num] || col[j][num]) return false;
vis[u][num] = row[i][num] = col[j][num] = true;
}
}
return true;
}
}
board[i][j]
从 1 ∼ 9 1 \sim 9 1∼9 暴力搜索每一个可能的值class Solution {
public void solveSudoku(char[][] board) {
boolean[][] vis = new boolean[10][10]; // 记录每个数字在每一行的填数状态
boolean[][] row = new boolean[10][10]; // 记录每个数字在每一列的填数状态
boolean[][] col = new boolean[10][10]; // 记录每个数字在每个小方块的填数状态
init(board, vis, row, col); // 初始化状态数组
dfs(board, 0, 0, vis, row, col);
}
private boolean dfs(char[][] board, int i, int j, boolean[][] vis,
boolean[][] row, boolean[][] col) {
if (i == 9) return true; // 数独已经填满,返回 true
if (j == 9) return dfs(board, i + 1, 0, vis, row, col); // 当前行已经填完,转到下一行
if (board[i][j] != '.') return dfs(board, i, j + 1, vis, row, col); // 当前位置已经有数字,转到下一个位置
// 从 1 开始枚举可能的值
for (int num = 1; num <= 9; num ++) {
int idx = i / 3 * 3 + j / 3; // 小方块的索引
if (!vis[idx][num] && !row[i][num] && !col[j][num]) {
vis[idx][num] = row[i][num] = col[j][num] = true;
board[i][j] = (char)(num + '0'); // 填入值
if (dfs(board, i, j + 1, vis, row, col)) return true; // 递归填下一个位置
// 恢复现场
vis[idx][num] = row[i][num] = col[j][num] = false;
board[i][j] = '.';
}
}
return false; // 无法填入任何数字,返回false
}
private void init(char[][] board, boolean[][] vis,
boolean[][] row, boolean[][] col) {
for (int i = 0; i < 9; i ++) {
for (int j = 0; j < 9; j ++) {
if (board[i][j] != '.') {
int num = board[i][j] - '0';
int idx = i / 3 * 3 + j / 3;
vis[idx][num] = row[i][num] = col[j][num] = true;
}
}
}
}
}
s
进行遍历char flag
记录当前的字符,cnt
记录当前字符的数量StringBuilder sb
来接收对 s
的描述并且继续搜索class Solution {
public String countAndSay(int n) {
return dfs(n, 1, "1");
}
private String dfs(int n, int u, String s) {
if (u == n) return s;
StringBuilder sb = new StringBuilder();
int cnt = 0;
char flag = s.charAt(0);
for (int i = 0; i < s.length(); i ++) {
if (s.charAt(i) == flag) cnt ++;
else {
// 当前字符和 flag 不同,说明发生改变
sb.append(cnt); sb.append(flag); // 将 flag 字符及其数量 cnt 描述加入 sb
flag = s.charAt(i); cnt = 1; // 更新 flag 和 cnt
}
}
// 添加最后一个字符的计数
sb.append(cnt); sb.append(flag);
return dfs(n, u + 1, sb.toString());
}
}
candidates
从小到大排序candidates[i]
的选择cnt + candidates[i] > target
即可不用在向后遍历class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
List<List<Integer>> ans = new ArrayList<>(); // 存储答案
List<Integer> res = new ArrayList<>(); // 存储递归每一层的结果
dfs(candidates, target, 0, 0, res, ans);
return ans;
}
private void dfs(int[] candidates, int target, int u, int cnt,
List<Integer> res, List<List<Integer>> ans) {
if (cnt == target) { // 找到答案
ans.add(new ArrayList<>(res)); // 将当前结果加入答案
return ;
}
// 从 u 开始选择(因为可以重复)
for (int i = u; i < candidates.length; i ++) {
if (cnt + candidates[i] <= target) { // 满足条件才能递归到下一层
res.add(candidates[i]);
dfs(candidates, target, i, cnt + candidates[i], res, ans);
res.remove(res.size() - 1); // 恢复现场
}
else break;
}
}
}
HashSet vis
标记使用过的数candidates[i] == candidates[i - 1]
时跳过class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
List<List<Integer>> ans = new ArrayList<>(); // 存储答案
List<Integer> res = new ArrayList<>(); // 存储递归每一层的结果
dfs(candidates, target, 0, 0, res, ans);
return ans;
}
private void dfs(int[] candidates, int target, int u, int cnt,
List<Integer> res, List<List<Integer>> ans) {
if (cnt == target) { // 找到答案
ans.add(new ArrayList<>(res)); // 将当前结果加入答案
return ;
}
for (int i = u; i < candidates.length; i ++) {
if (i > u && candidates[i] == candidates[i - 1]) continue;
if (cnt + candidates[i] <= target) { // 满足条件才能递归到下一层
res.add(candidates[i]);
dfs(candidates, target, i + 1, cnt + candidates[i], res, ans);
res.remove(res.size() - 1); // 恢复现场
}
else break;
}
}
}
<<<<<<< HEAD
nums[i] <= 0 || nums[i] > n
的值为 n + 1
,表示不存在class Solution {
public int firstMissingPositive(int[] nums) {
int n = nums.length;
// 第一次遍历,将所有负数和大于 n 的数置为 n + 1
for (int i = 0; i < n; i ++) {
if (nums[i] <= 0 || nums[i] > n) nums[i] = n + 1;
}
// 第二次遍历,将出现的正数对应的位置标记为负数
for (int i = 0; i < n; i ++) {
int num = Math.abs(nums[i]);
if (num <= n) nums[num - 1] = -Math.abs(nums[num - 1]);
}
// 第三次遍历,找到第一个正数的位置,即为缺失的最小正整数
for (int i = 0; i < n; i ++) {
if (nums[i] > 0) return i + 1;
}
// 如果数组中的所有数都出现了,返回 n + 1
return n + 1;
}
}
height[i]
之前出现过的最高的挡板height[i] < height[st.peek()]
说明后面可能存在更高的挡板class Solution {
public int trap(int[] height) {
Stack<Integer> st = new Stack<>();
int ans = 0;
for (int i = 0; i < height.length; i++) {
if (!st.isEmpty() && height[i] > height[st.peek()]) {
int t = st.pop();
if (st.isEmpty()) break;
int l = i - st.peek() - 1;
int r = Math.min(height[i], height[st.peek()]) - height[t];
ans += l * r;
}
st.push(i);
}
return ans;
}
}
class Solution {
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) return "0";
int m = num1.length();
int n = num2.length();
int[] res = new int[m + n]; // 维护每一层乘法的结果
for (int i = m - 1; i >= 0; i--) {
int x = num1.charAt(i) - '0';
for (int j = n - 1; j >= 0; j--) {
int y = num2.charAt(j) - '0';
res[i + j + 1] += x * y; // 记录结果
}
}
int base = 0;
for (int i = m + n - 1; i >= 0; i--) {
int sum = res[i] + base;
res[i] = sum % 10;
base = sum / 10;
}
StringBuilder sb = new StringBuilder();
for (int num : res) sb.append(num);
while (sb.length() > 0 && sb.charAt(0) == '0') sb.deleteCharAt(0);
return sb.toString();
}
}
dp
第二题青春版
状态表示:
dp[i][j]
表示字符串 s
的前 i
个字符和字符串 p
的前 j
个字符是否匹配。dp[0][0]
为 true
,表示空字符串和空模式是匹配的。*
之前的状态为 true
,因为 *
可以匹配空字符串。状态计算:
p
的当前字符是 *
,则可以选择匹配空字符串 dp[i][j-1]
或者匹配多个字符 dp[i-1][j]
,只要有一个为 true
,则 dp[i][j]
也为 true
。p
的当前字符是 ?
,或者 p
的当前字符和 s
的当前字符相等,则将 dp[i][j] = dp[i-1][j-1]
,表示当前位置的匹配状态与前一个位置的匹配状态相同。dp[i][j]
为 false
,表示当前位置的字符不匹配。class Solution {
public boolean isMatch(String s, String p) {
int n = s.length(), m = p.length();
boolean[][] dp = new boolean[n + 1][m + 1];
dp[0][0] = true;
// 初始化所有 * 之前的状态都为 true
for (int i = 1; i <= m; i ++) {
if (p.charAt(i - 1) == '*') dp[0][i] = true;
else break;
}
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
if (p.charAt(j - 1) == '*') dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
else if (p.charAt(j - 1) == '?' || s.charAt(i - 1) == p.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1];
}
}
return dp[n][m];
}
}
i
,当 i + nums[i] >= n - 1
时可以直接返回结果j = i
遍历到 j = i + nums[i]
,设下一步的位置为 res
,以 res
能到达的最远位置为 idx
j + nums[j]
即为下一步可以到达的最远位置 idx
j + nums[j]
的最大值,并用 res
维护下一步的坐标 j
即可class Solution {
public int jump(int[] nums) {
int ans = 0, n = nums.length;
if(n <= 1) return 0; // 当长度只有 1 时无需操作
for(int i = 0; i < n; i ++){
int res = 0, idx = 0;
if(i + nums[i] >= n - 1) return ans + 1; // 下一步的最远距离正好到达终点
for(int j = i + 1; j <= i + nums[i]; j ++){ // 遍历找到能到达最远距离的方案
if(j + nums[j] >= idx){
idx = j + nums[j];
res = j;
}
}
i = res - 1; ans ++; // 更新 i 和 ans
}
return ans;
}
}
class Solution {
public List<List<Integer>> permute(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
ans.add(this.asList(nums));
while (nextPermutation(nums)) ans.add(this.asList(nums));
return ans;
}
public boolean nextPermutation(int[] nums) {
int n = nums.length, i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i --;
if (i >= 0) {
int j = n - 1;
while (nums[j] <= nums[i]) j --;
swap(nums, i, j);
this.reverse(nums, i + 1, n - 1);
return true;
}
else return false; // 找不到直接返回
}
private void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j]; nums[j] = t;
}
private void reverse(int[] nums, int l, int r) {
while (l < r) {
this.swap(nums, l, r);
l ++; r --;
}
}
private List<Integer> asList(int[] nums) {
List<Integer> res = new ArrayList<>();
for (int num : nums) res.add(num);
return res;
}
}
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
ans.add(this.asList(nums));
while (nextPermutation(nums)) ans.add(this.asList(nums));
return ans;
}
public boolean nextPermutation(int[] nums) {
int n = nums.length, i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i --;
if (i >= 0) {
int j = n - 1;
while (nums[j] <= nums[i]) j --;
swap(nums, i, j);
this.reverse(nums, i + 1, n - 1);
return true;
}
else return false; // 找不到直接返回
}
private void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j]; nums[j] = t;
}
private void reverse(int[] nums, int l, int r) {
while (l < r) {
this.swap(nums, l, r);
l ++; r --;
}
}
private List<Integer> asList(int[] nums) {
List<Integer> res = new ArrayList<>();
for (int num : nums) res.add(num);
return res;
}
}
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
// 先进行矩阵的转置操作
for (int i = 0; i < n; i ++) {
for (int j = i; j < n; j ++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 再进行每行的翻转操作
for (int i = 0; i < n; i ++) {
for (int j = 0; j < n / 2; j ++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[i][n - 1 - j];
matrix[i][n - 1 - j] = temp;
}
}
}
}
strs[i]
将其按照字典序排序并映射下标,保存到 HashMap
中List[i]
后面即可class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
List<List<String>> ans = new ArrayList<>();
HashMap<String, Integer> vis = new HashMap<>();
int idx = 0;
for (String s : strs) {
char[] t = s.toCharArray();
Arrays.sort(t); // 得到字典序
String st = new String(t);
// 根据字典序 st 查找是否存在该映射
if (vis.containsKey(st)) ans.get(vis.get(st)).add(s); // 存在则对应索引的 list add(s)
else {
// 不存在 创建新的 list
List<String> newList = new ArrayList<>();
newList.add(s); ans.add(newList);
vis.put(st, idx ++); // 记录映射
}
}
return ans;
}
}
class Solution {
public double myPow(double x, int n) {
if (x == 0.0d) return 0.0d;
long k = n;
double res = 1.0d;
if (k < 0) {
x = 1 / x;
k = -k;
}
while (k > 0) {
if ((k & 1) == 1) res *= x;
x *= x;
k >>= 1;
}
return res;
}
}
[i][j]
在斜率为 1 1 1 和 − 1 -1 −1 时判断其截距是否已经存在即可,且要求 j
列不存在相同的棋子class Solution {
public List<List<String>> solveNQueens(int n) {
boolean[] col = new boolean[n];
boolean[] l = new boolean[n * 2 + 1];
boolean[] r = new boolean[n * 2 + 1];
List<String> res = new ArrayList<>();
List<List<String>> ans = new ArrayList<>();
dfs(0, n, col, l, r, res, ans);
return ans;
}
void dfs(int u, int n, boolean[] col, boolean[] l, boolean[] r,
List<String> res, List<List<String>> ans) {
if (u == n) {
ans.add(new ArrayList<>(res));
return ;
}
char[] s = new char[n];
for (int i = 0; i < n; i ++) s[i] = '.';
for (int i = 0; i < n; i ++) {
// 判断是否冲突
if (!col[i] && !l[u - i + n] && !r[u + i]) {
col[i] = l[u - i + n] = r[u + i] = true; // u - i + n 防止 u - i < 0 越界
s[i] = 'Q';
res.add(new String(s));
dfs (u + 1, n, col, l, r, res, ans);
// 恢复现场
res.remove(res.size() - 1);
s[i] = '.';
col[i] = l[u - i + n] = r[u + i] = false;
}
}
}
}
class Solution {
private int ans;
public int totalNQueens(int n) {
boolean[] col = new boolean[n];
boolean[] l = new boolean[n * 2 + 1];
boolean[] r = new boolean[n * 2 + 1];
return dfs (0, n, col, l, r);
}
int dfs(int u, int n, boolean[] col, boolean[] l, boolean[] r) {
if (u == n) return 1;
int res = 0;
for (int i = 0; i < n; i ++) {
// 判断是否冲突
if (!col[i] && !l[u - i + n] && !r[u + i]) {
col[i] = l[u - i + n] = r[u + i] = true; // u - i + n 防止 u - i < 0 越界
res += dfs (u + 1, n, col, l, r);
col[i] = l[u - i + n] = r[u + i] = false; // 恢复现场
}
}
return res;
}
}
dp[i]
表示以 nums[i]
结尾的数组中,最大的连续子数组的值dp[i] <= 0
说明前面的数组没有继续扩展的需要,以 dp[i]
结尾的最大值为 Math.max(dp[i - 1], nums[i])
dp[i - 1] + nums[i]
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
dp[0] = nums[0]; // 初始化
int ans = nums[0]; // ans 维护 dp 的最大值结果
for (int i = 1; i < n; i ++) {
if (dp[i - 1] > 0) dp[i] = dp[i - 1] + nums[i];
else dp[i] = Math.max(dp[i - 1], nums[i]);
ans = Math.max(ans, dp[i]);
}
return ans;
}
}
l, r
为当前遍历位置的坐标:
l < 0 || r < 0 || l >= n || r >= m
说明越界,此时要按照顺时针方向转向vis[l][r]
已经被标记过,说明之前已经走过这个位置,显然也是越界行为,也要转向n * m
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
int n = matrix.length, m = matrix[0].length;
boolean[][] vis = new boolean[n][m]; // 作为标记数组判断是否走过该点
List<Integer> ans = new ArrayList<>(); // 记录答案
int x = 0, y = 0, d = 0;
int[] dx = {0, 1, 0, -1}, dy = {1, 0, -1, 0}; // 构建偏移量数组,d = 0 表示向 -> 走的偏移量
for (int i = 0; i < n * m; i ++) {
ans.add(matrix[x][y]); vis[x][y] = true; // 将走过的点标记
int l = x + dx[d], r = y + dy[d]; // l 和 r 为下一步要走的点,此时进行判断
if (l < 0 || r < 0 || r >= m || l >= n || vis[l][r]) {
d = (d + 1) % 4; // 得到下一个偏移量
l = x + dx[d]; r = y + dy[d]; // 重新更新 l, r
}
x = l; y = r; // 更新 x, y
}
return ans;
}
}
idx
记录可以到达的最大位置的下标i > idx
说明当前位置 i
无法到达,直接 false
idx = Math.max(idx, i + nums[i])
idx >= nums.length - 1
说明已经可以到达尾部,直接 true
class Solution {
public boolean canJump(int[] nums) {
int idx = 0;
for (int i = 0; i < nums.length; i++) {
if (i > idx) return false; // 当前位置无法到达
idx = Math.max(idx, i + nums[i]);
if (idx >= nums.length - 1) {
return true; // 已经可以到达最后一个位置
}
}
return false;
}
}
class Solution {
public int[][] merge(int[][] intervals) {
int n = intervals.length;
Arrays.sort(intervals, (o1, o2) -> o1[0] - o2[0]); // 按照左端点从小到大排序
List<int[]> ans = new ArrayList<>();
int l = intervals[0][0], r = intervals[0][1];
for (int i = 1; i < n; i ++) {
// 合并操作
if (intervals[i][0] <= r) r = Math.max(intervals[i][1], r);
else {
ans.add(new int[]{l, r});
l = intervals[i][0]; r = intervals[i][1];
}
}
ans.add(new int[]{l, r}); // 将最后一组区间加入答案
return ans.toArray(new int[ans.size()][]);
}
}
class Solution {
public int[][] insert(int[][] intervals, int[] newInterval) {
int[][] res = new int[intervals.length + 1][2];
for (int i = 0; i < intervals.length; i ++) res[i] = intervals[i];
res[intervals.length] = newInterval;
intervals = res;
Arrays.sort(intervals, (o1, o2) -> o1[0] - o2[0]);
List<int[]> ans = new ArrayList<>();
int l = intervals[0][0], r = intervals[0][1];
for (int i = 1; i < intervals.length; i ++) {
// 合并操作
if (intervals[i][0] <= r) r = Math.max(intervals[i][1], r);
else {
ans.add(new int[]{l, r});
l = intervals[i][0]; r = intervals[i][1];
}
}
ans.add(new int[]{l, r}); // 将最后一组区间加入答案
return ans.toArray(new int[ans.size()][]);
}
}
的位置,然后统计即可class Solution {
public int lengthOfLastWord(String s) {
int cnt = 0;
char op = 'a';
int idx = s.length() - 1;
while (idx >= 0 && s.charAt(idx) == ' ') idx --;
while (idx >= 0) {
op = s.charAt(idx);
if ((op >= 'a' && op <= 'z') || (op >= 'A' && op <= 'Z')) cnt ++;
else return cnt;
idx --;
}
return cnt;
}
}
vis
class Solution {
public int[][] generateMatrix(int n) {
int[] dx = {0, 1, 0, -1}, dy = {1, 0, -1, 0};
int l = 0, r = 0, d = 0;
int[][] ans = new int[n][n];
for (int i = 1; i <= n * n; i ++) {
ans[l][r] = i;
int x = l + dx[d], y = r + dy[d];
if (x < 0 || y < 0 || x >= n || y >= n || ans[x][y] != 0) {
d = (d + 1) % 4;
x = l + dx[d]; y = r + dy[d];
}
l = x; r = y;
}
return ans;
}
}
class Solution {
public String getPermutation(int n, int k) {
char[] nums = new char[n];
for (int i = 0; i < n; i ++) nums[i] = (char)(i + 1 + '0');
while (k -- > 1) nextPermutation(nums);
return String.valueOf(nums);
}
public void nextPermutation(char[] nums) {
int n = nums.length;
int i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i --;
if (i >= 0) {
int j = n - 1;
while (nums[j] <= nums[i]) j --;
swap(nums, i, j);
}
reverse(nums, i + 1, n - 1);
}
private void swap(char[] nums, int i, int j) {
char t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
private void reverse(char[] nums, int l, int r) {
while (l < r) {
this.swap(nums, l, r);
l ++; r --;
}
}
}