2019.1.18 leetcode 刷题总结
题号:342
给定一个整数 (32 位有符号整数),请编写一个函数来判断它是否是 4 的幂次方。
示例 1:
输入: 16
输出: true
示例 2:
输入: 5
输出: false
我的想法:
- 一个数若是4的幂,一定是2的幂,且幂次是偶数
- 幂次是偶数在二进制的体现就是,二进制数的长度是奇数,且出除最高位为1外,其余全为0
对应程序:
// java
class Solution {
public boolean isPowerOfFour(int num) {
if(num == 0) {
return false;
}
int length = Integer.toBinaryString(num).length();
if((num & (num-1)) != 0 || length % 2 == 0) {
return false;
}
return true;
}
}
题号:509
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定 N,计算 F(N)。
示例 1:
输入:2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1.
示例 2:
输入:3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2.
我的想法:
- 递归求解
对应程序:
// java
class Solution {
public int fib(int N) {
if(N == 0) {
return 0;
}else if(N == 1) {
return 1;
}else {
return fib(N - 1) + fib(N - 2);
}
}
}
优化:
- 在递归算法中存在着重复计算:例如在计算F(4)时,F(2)就被重复计算了2次;计算F(5)时,F(2)被重复计算3次,F(3)被重复计算了2次。随着N的增大,重复计算会越来越多,因此比较耗时
- 用迭代法
程序:
// java
class Solution {
public int fib(int N) {
if(N == 0) {
return 0;
}
if(N == 1) {
return 1;
}
int topTwo = 0;
int topOne = 1;
int res = 0;
for(int i = 2; i <= N; ++i) {
res = topOne + topTwo;
topTwo = topOne;
topOne = res;
}
return res;
}
}
速度要快非常多
题号:482
给定一个密钥字符串S,只包含字母,数字以及 ‘-’(破折号)。N 个 ‘-’ 将字符串分成了 N+1 组。给定一个数字 K,重新格式化字符串,除了第一个分组以外,每个分组要包含 K 个字符,第一个分组至少要包含 1 个字符。两个分组之间用 ‘-’(破折号)隔开,并且将所有的小写字母转换为大写字母。
给定非空字符串 S 和数字 K,按照上面描述的规则进行格式化。
示例 1:
输入:S = “5F3Z-2e-9-w”, K = 4
输出:“5F3Z-2E9W”
解释:字符串 S 被分成了两个部分,每部分 4 个字符;
注意,两个额外的破折号需要删掉。
示例 2:
输入:S = “2-5g-3-J”, K = 2
输出:“2-5G-3J”
解释:字符串 S 被分成了 3 个部分,按照前面的规则描述,第一部分的字符可以少于给定的数量,其余部分皆为 2 个字符。
我的想法:
- 题目不要理解错,我开始的时候就理解错了:题目说的 “除了第一个分组以外,每个分组要包含 K 个字符”的意思是,第一个组中的元素个数要小于等于K,以保证后面每个分组都是K个字符
- 将源字符串中的所有“-”去掉,所有字母转大写,根据K重新分组,每组中间拼接“-”
- 在循环体中拼接字符串要使用StringBuilder,不要使用“+”进行拼解,因为会产生大量的垃圾对象
对应程序:
// java
class Solution {
public String licenseKeyFormatting(String S, int K) {
String str = S.replaceAll("-", "").toUpperCase();
int length = str.length();
if(length == 0) {
return "";
}
// 计算得到第一组有多少个字符
int firstGroupNum = length % K == 0?K:length % K;
StringBuilder res = new StringBuilder(str.substring(0, firstGroupNum));
for(int i = firstGroupNum; i < str.length(); ++i) {
if((i - firstGroupNum) % K == 0) {
// 每组中间拼解"-"
res.append("-");
}
res.append(str.charAt(i));
}
return res.toString();
}
}
题号:796
给定两个字符串, A 和 B。
A 的旋转操作就是将 A 最左边的字符移动到最右边。 例如, 若 A = ‘abcde’,在移动一次之后结果就是’bcdea’ 。如果在若干次旋转操作之后,A 能变成B,那么返回True。
示例 1:
输入: A = ‘abcde’, B = ‘cdeab’
输出: true
示例 2:
输入: A = ‘abcde’, B = ‘abced’
输出: false
我的想法:
- 找出A中所有B的首个字符的位置索引,若不存在,返回false;
- 以找到的位置索引断开字符串A,重新拼接:将索引前面的字符串拼接到索引后面的字符串,比较新字符串和B是否相同,若相同,返回true;若不同,去操作下一个索引
对应程序:
// java
class Solution {
public boolean rotateString(String A, String B) {
if(A.length() != B.length()) {
return false;
}
if(A.equals(B)) {
return true;
}
char bFirstChar = B.charAt(0);
int upIndex = A.indexOf(bFirstChar, 0);
if(upIndex == -1) {
return false;
}
while(upIndex != -1) {
String str1 = A.substring(0, upIndex);
String str2 = A.substring(upIndex);
String tempStr = str2 + str1;
if(B.equals(tempStr)) {
return true;
}else {
upIndex = A.indexOf(bFirstChar, upIndex+1);
}
}
return false;
}
}
看到提交结果中有人直接将两个字符串A拼接,判断新的字符串中是否含有B。这种想法还是很厉害的。