添加链接描述
给你两个整数 num1 和 num2,返回这两个整数的和。
示例 1:
输入:num1 = 12, num2 = 5
输出:17
解释:num1 是 12,num2 是 5 ,它们的和是 12 + 5 = 17 ,因此返回 17 。
示例 2:
输入:num1 = -10, num2 = 4
输出:-6
解释:num1 + num2 = -6 ,因此返回 -6 。
class Solution {
// 不使用加法运算符
public int sum(int num1, int num2) {
while (num2 != 0) {
int carry = (num1 & num2) << 1; // 进位
num1 ^= num2; // 不进位的和
num2 = carry;
}
return num1;
}
public int sum1(int num1, int num2) {
return num1 + num2;
}
}
添加链接描述
你会得到一个字符串 s (索引从 0 开始),你必须对它执行 k 个替换操作。替换操作以三个长度均为 k 的并行数组给出:indices, sources, targets。
要完成第 i 个替换操作:
检查 子字符串 sources[i] 是否出现在 原字符串 s 的索引 indices[i] 处。
如果没有出现, 什么也不做 。
如果出现,则用 targets[i] 替换 该子字符串。
例如,如果 s = “abcd” , indices[i] = 0 , sources[i] = “ab”, targets[i] = “eee” ,那么替换的结果将是 “eeecd” 。
所有替换操作必须 同时 发生,这意味着替换操作不应该影响彼此的索引。测试用例保证元素间不会重叠 。
例如,一个 s = “abc” , indices = [0,1] , sources = [“ab”,“bc”] 的测试用例将不会生成,因为 “ab” 和 “bc” 替换重叠。
在对 s 执行所有替换操作后返回 结果字符串 。
子字符串 是字符串中连续的字符序列。
示例 1:
输入:s = “abcd”, indices = [0,2], sources = [“a”,“cd”], targets = [“eee”,“ffff”]
输出:“eeebffff”
解释:
“a” 从 s 中的索引 0 开始,所以它被替换为 “eee”。
“cd” 从 s 中的索引 2 开始,所以它被替换为 “ffff”。
示例 2:
输入:s = “abcd”, indices = [0,2], sources = [“ab”,“ec”], targets = [“eee”,“ffff”]
输出:“eeecd”
解释:
“ab” 从 s 中的索引 0 开始,所以它被替换为 “eee”。
“ec” 没有从原始的 S 中的索引 2 开始,所以它没有被替换。
class Solution {
public String findReplaceString(String s, int[] indices, String[] sources, String[] targets) {
int n = s.length();
int[] replace = new int[n]; // 保存哪个位置需要替换
Arrays.fill(replace, -1);
for (int k = 0; k < indices.length; k++) {
// startsWith 判断指定偏移量开头是否以指定字符串开头
if (s.startsWith(sources[k], indices[k])) {
replace[indices[k]] = k; // 记录需要替换的位置
}
}
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < n;) {
if (replace[i] >= 0) {
stringBuilder.append(targets[replace[i]]); // 替换成 targets,位置是 replace[i]
// i 替换成功,向后跳原来替换的字符串长度
// a b c d e f
// 替换 cd 为 ffff,a b ffff e f
// 替换成功,i 下一个从 e 比较,而不是 d
int index = replace[i];
i += sources[index].length();
} else {
stringBuilder.append(s.charAt(i));
i++;
}
}
return stringBuilder.toString();
}
}
添加链接描述
给你一个 rows x cols 大小的矩形披萨和一个整数 k ,矩形包含两种字符: ‘A’ (表示苹果)和 ‘.’ (表示空白格子)。你需要切披萨 k-1 次,得到 k 块披萨并送给别人。
切披萨的每一刀,先要选择是向垂直还是水平方向切,再在矩形的边界上选一个切的位置,将披萨一分为二。如果垂直地切披萨,那么需要把左边的部分送给一个人,如果水平地切,那么需要把上面的部分送给一个人。在切完最后一刀后,需要把剩下来的一块送给最后一个人。
请你返回确保每一块披萨包含 至少 一个苹果的切披萨方案数。由于答案可能是个很大的数字,请你返回它对 10^9 + 7 取余的结果。
示例 1:
输入:pizza = [“A…”,“AAA”,“…”], k = 3
输出:3
解释:上图展示了三种切披萨的方案。注意每一块披萨都至少包含一个苹果。
示例 2:
输入:pizza = [“A…”,“AA.”,“…”], k = 3
输出:1
示例 3:
输入:pizza = [“A…”,“A…”,“…”], k = 1
输出:1
class Solution {
public int ways(String[] pizza, int k) {
int mod = 1_000_000_007;
int rows = pizza.length;
int cols = pizza[0].length();
int[][] apples = new int[rows + 1][cols + 1];
// 统计苹果分布数量
for (int i = rows - 1; i >= 0; i--) {
for (int j = cols - 1; j >= 0; j--) {
apples[i][j] = apples[i][j + 1] + apples[i + 1][j] - apples[i + 1][j + 1] +
(pizza[i].charAt(j) == 'A' ? 1 : 0); // 容斥原理
}
}
// 切披萨数
// 从右下角开始
// dp[i,j,k]的含义是披萨仅剩从坐标i,j开始的右下角部分,并且可以切k刀的方案数
int[][][] dp = new int[rows + 1][cols + 1][k + 1];
for (int kk = 1; kk <= k; kk++) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (kk == 1) {
if (apples[i][j] > 0) {
dp[i][j][kk] = 1;
}
} else {
// 水平方向切
for (int ii = i + 1; ii < rows; ii++) {
if (apples[i][j] > apples[ii][j]) { // 切出去上面的披萨的至少有一个苹果
dp[i][j][kk] = (dp[i][j][kk] + dp[ii][j][kk - 1]) % mod;
}
}
// 垂直方向切
for (int jj = j + 1; jj < cols; jj++) {
if (apples[i][j] > apples[i][jj]) {
dp[i][j][kk] = (dp[i][j][kk] + dp[i][jj][kk - 1]) % mod;
}
}
}
}
}
}
return dp[0][0][k];
}
}