目录
第一题
题目来源
题目内容
解决方法
方法一:位运算
第二题
题目来源
题目内容
解决方法
方法一:贪心算法
第三题
题目来源
题目内容
解决方法
方法一:二分查找
方法二:牛顿迭代法
方法三:位操作
67. 二进制求和 - 力扣(LeetCode)
class Solution {
public String addBinary(String a, String b) {
StringBuilder result = new StringBuilder();
int carry = 0;
int i = a.length() - 1;
int j = b.length() - 1;
while (i >= 0 || j >= 0) {
int sum = carry;
if (i >= 0) {
sum += a.charAt(i--) - '0';
}
if (j >= 0) {
sum += b.charAt(j--) - '0';
}
result.append(sum % 2);
carry = sum / 2;
}
if (carry > 0) {
result.append(carry);
}
return result.reverse().toString();
}
}
在这个方法中,我们使用 StringBuilder 来保存计算结果。然后,通过两个指针 i 和 j 分别从两个输入字符串的末尾开始遍历。在每一位上,我们将对应位置上的字符转换为数值,并加上上一位的进位值。然后,根据和的奇偶性确定当前位的值,并更新进位值。最后,如果还有进位值剩余,则添加到结果的最前面。最后将结果翻转并转换为字符串返回。
复杂度分析:
时间复杂度:
空间复杂度:
需要注意的是,这里使用了StringBuilder来构建字符串,而不是直接拼接字符串。这是因为字符串的拼接操作会生成新的字符串对象,并且每次拼接都需要将原字符串复制到新的对象中。而StringBuilder则是基于可变数组实现的,可以高效地进行字符串拼接操作。因此,使用StringBuilder可以提高性能。
LeetCode运行结果:
68. 文本左右对齐 - 力扣(LeetCode)
这道题可以采用贪心的思路,每次尽可能选取更多的单词,同时尽量均匀分配单词之间的空格数量。
具体实现可以按行来处理,每次选取一些单词使得它们加起来不超过给定的 maxWidth,然后根据单词数量和剩余空格数量来决定如何分配单词之间的空格。如果当前行只有一个单词,那么左对齐;如果是最后一行,则左对齐且单词之间只加一个空格;否则就尽可能均匀分配单词之间的空格数量即可。
具体实现可以使用两个指针 i 和 j 分别表示当前行的第一个和最后一个单词,每次从 i 开始向后扫描单词,直到扫描到一个单词会导致当前行的长度超过 maxWidth 为止。此时,i 到 j-1 这些单词就组成了当前行,可以根据上述规则来对它们进行排版。最后将结果添加到答案中并继续扫描下一行。
class Solution {
public List fullJustify(String[] words, int maxWidth) {
List res = new ArrayList<>();
int n = words.length;
int i = 0;
while (i < n) {
int len = 0; // 当前行已选单词的长度
int wordsNum = 0; // 当前行已选单词的数量
StringBuilder sb = new StringBuilder();
while (i < n && len + words[i].length() + wordsNum <= maxWidth) {
// 选取单词
len += words[i].length();
wordsNum++;
i++;
}
if (wordsNum == 1) { // 如果当前行只有一个单词,左对齐
sb.append(words[i - wordsNum]);
for (int j = 0; j < maxWidth - len; j++) {
sb.append(" ");
}
} else if (i == n) { // 如果是最后一行,左对齐且单词之间只加一个空格
for (int j = i - wordsNum; j < i; j++) {
sb.append(words[j]);
if (j < i - 1) {
sb.append(" ");
}
}
for (int j = 0; j < maxWidth - len - (wordsNum - 1); j++) {
sb.append(" ");
}
} else { // 否则,尽可能均匀分配单词间的空格数量
int spaces = maxWidth - len;
int slots = wordsNum - 1;
int spaceWidth = spaces / slots;
int remain = spaces % slots;
for (int j = i - wordsNum; j < i; j++) {
sb.append(words[j]);
if (j == i - 1) {
break;
}
for (int k = 0; k < spaceWidth; k++) {
sb.append(" ");
}
if (remain > 0) {
sb.append(" ");
remain--;
}
}
}
res.add(sb.toString());
}
return res;
}
}
复杂度分析:
时间复杂度分析:
假设单词数量为 n,最大长度为 L。
扫描一遍单词数组找出每一行的单词需要 O(n) 的时间复杂度,对于每一行,排版时需要根据单词数量和剩余空格数量来决定如何分配单词之间的空格,这一步需要 O(L) 的时间复杂度。因此总时间复杂度为 O(nL)。
空间复杂度分析:
算法中使用了一个 StringBuilder 对象来存储当前行的字符串,以及一个 List
LeetCode运行结果:
69. x 的平方根 - 力扣(LeetCode)
题目要求计算一个非负整数x的算术平方根,并返回整数部分。
可以使用二分查找的方法来逼近平方根的整数部分。假设平方根的整数部分为r,那么可以将问题转化为在区间[0, x]中查找一个数r,使得rr<=x且(r+1)(r+1)>x。可以通过二分查找在有序区间中查找满足条件的数。
class Solution {
public int mySqrt(int x) {
if (x == 0) {
return 0;
}
long left = 1;
long right = x;
while (left <= right) {
long mid = left + (right - left) / 2;
if (mid * mid == x) {
return (int)mid;
} else if (mid * mid < x) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return (int)right;
}
}
复杂度分析:
LeetCode运行结果:
除了二分查找,还可以使用牛顿迭代法来求解平方根。
牛顿迭代法的思想是通过不断逼近函数的零点来求解方程的根。对于求解平方根的问题,可以将其转化为求解方程 f(r) = r^2 - x = 0 的根。根据牛顿迭代法的迭代公式,可以得到如下的迭代过程:
r_{n+1} = r_n - f(r_n) / f'(r_n)
其中,r_n 是第 n 次迭代得到的近似解,f'(r_n) 是 f(r_n) 的导数。
对于平方根的问题,迭代公式可以简化为:
r_{n+1} = (r_n + x / r_n) / 2
class Solution {
public int mySqrt(int x) {
if (x == 0) {
return 0;
}
double r = x;
while (Math.abs(r * r - x) > 0.0001) {
r = (r + x / r) / 2;
}
return (int)r;
}
}
复杂度分析:
LeetCode运行结果:
除了二分查找和牛顿迭代法,还可以使用位操作的方法来求解平方根。
我们可以从二进制的角度思考,一个非负整数 x 的平方根的整数部分最大不会超过 x 的一半。因此,我们可以从 0 到 x/2 这个范围内进行搜索。
具体思路如下:
class Solution {
public int mySqrt(int x) {
if (x == 0 || x == 1) {
return x;
}
int left = 0;
int right = x / 2;
int ans = 0;
while (left <= right) {
int mid = (left + right) / 2;
long square = (long)mid * mid;
if (square == x) {
return mid;
} else if (square < x) {
ans = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return ans;
}
}
复杂度分析:
LeetCode运行结果: