2018.12.26 leetcode 刷题总结
题号:784
给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串。返回所有可能得到的字符串集合
示例:
输入: S = “a1b2”
输出: [“a1b2”, “a1B2”, “A1b2”, “A1B2”]
输入: S = “3z4”
输出: [“3z4”, “3Z4”]
输入: S = “12345”
输出: [“12345”]
注意:
S 的长度不超过12。
S 仅由数字和字母组成。
我的想法:
我只想到了穷举法,每个字母都有两种可能,在针对这两种可能,分别对应下一个字母的两种可能,以此类推,但是我没有写出程序
下面贴一下答案中大部分都在用的解法:
参考程序:
//java
class Solution {
public List<String> letterCasePermutation(String S) {
List<String> result = new ArrayList<>();
getAllCombo(S.toCharArray(), 0, new StringBuilder(), result);
return result;
}
// @params sChar: 所给字符串的字符数组
// @params i: 字符数组的下标
// @params sb: 用于存放新生成的字符串
// @params result: 用于存放字符串的集合
private void getAllCombo(char[] sChar, int i, StringBuilder sb, List<String> result) {
// 递归出口
if(i == sChar.length) {
result.add(sb.toString());
return;
}
char s = sChar[i];
// 是字母分两种情况
if((s >= 65 && s <= 90) || (s >= 97 && s <= 122)) {
sb.append(String.valueOf(s).toLowerCase());
getAllCombo(sChar, i+1, sb, result);
sb.deleteCharAt(sb.length() - 1);
sb.append(String.valueOf(s).toUpperCase());
getAllCombo(sChar, i+1, sb, result);
sb.deleteCharAt(sb.length() - 1);
// 非字母直接append
}else {
sb.append(s);
getAllCombo(sChar, i+1, sb, result);
sb.deleteCharAt(sb.length() - 1);
}
}
}
上述程序中最重要的一步就是 sb.deleteCharAt(sb.length() - 1); 也就是在从递归函数出来之后,要删掉拼好的字符串的最后一位。为什么要这么做,首先考虑所给字符串中是含字母的情况,首先将字母转小写,由于递归函数的一个出口是拼接出了一种组合的情况,然后跳出当前函数,当跳出来的时候,StringBuilder已经是“满”的了,而跳出到上一层的时候,字符s还是StringBuilder的最后一位,因此我们要去掉拼接的最后一位,让这个字符s去变成大写(如果s是字母,若s是数字,执行完去掉最后一位的操作,会跳到上一层),继续拼出新的字符串,写入结果集合。总结一下上面的过程,就是先获得一个字母全小写的组合,然后从后至前,找出所有组合。
e.g. 字符串S = "a1b2"的遍历过程:
获得a转小写,跳入,获得1,跳入,获得b转小写,跳入,获得2,跳入,得到a1b2,写入结果,跳出,删除最后一位,变成a1b,跳出,删除最后一位,变成a1(当前字符s=‘b’),向下执行转大写,变成a1B,跳入,获得2,变成a1B2,写入结果,跳出,删除最后一位,变成a1B,跳出,删除最后一位,变成a1,跳出,删除最后一位,变成a,跳出,删除最后一位,变成空,向下执行转大写,过程和上述过程相同。
当跳出函数时,当前的字符s始终是未删除最后一位的StringBuilder的最后一位
以上就是我自己的理解,大家可以自己debug一下看看执行过程,如果看完我写的东西之后更模糊了,(我自己都有点晕了)就忘了我写的这些吧(逃
题号:371
不使用运算符 + 和 - ,计算两整数 a 、b 之和。
我的想法:
位运算,直接看答案
参考程序:
// java
class Solution {
public int getSum(int a, int b) {
while (b!=0) {
int tmp = a ^ b;
b = (a & b) << 1;
a = tmp;
}
return a;
}
}
题号:953
某种外星语也使用英文小写字母,但可能顺序 order 不同。字母表的顺序(order)是一些小写字母的排列。
给定一组用外星语书写的单词 words,以及其字母表的顺序 order,只有当给定的单词在这种外星语中按字典序排列时,返回 true;否则,返回 false。
示例 1:
输入:words = [“hello”,“leetcode”], order = “hlabcdefgijkmnopqrstuvwxyz”
输出:true
解释:在该语言的字母表中,‘h’ 位于 ‘l’ 之前,所以单词序列是按字典序排列的。
示例 2:
输入:words = [“word”,“world”,“row”], order = “worldabcefghijkmnpqstuvxyz”
输出:false
解释:在该语言的字母表中,‘d’ 位于 ‘l’ 之后,那么 words[0] > words[1],因此单词序列不是按字典序排列的。
示例 3:
输入:words = [“apple”,“app”], order = “abcdefghijklmnopqrstuvwxyz”
输出:false
解释:当前三个字符 “app” 匹配时,第二个字符串相对短一些,然后根据词典编纂规则 “apple” > “app”,因为 ‘l’ > ‘∅’,其中 ‘∅’ 是空白字符,定义为比任何其他字符都小(更多信息)。
我的想法:
- 将给定的字母表中字母按顺序映射到正整数上,却靠前的值越大
- 遍历words数组,设立标志字符串,与下一个字符串相比较,将字符串变成字符数组,比较每一个字符,不满足直接返回false;若相同比较下一个字符;若满足,将与标志字符串相比较的字符串赋给标志字符串,与下一个字符串相比较
- 若遍历结束都没返回false,那么就返回true
对应程序:
// java
// 优化过的逻辑
class Solution {
public boolean isAlienSorted(String[] words, String order) {
// 拿到字典
Map<Character, Integer> dictionary = getDictionary(order);
// 将第一个字符串设为标志位
String flag = words[0];
for(int i = 1; i < words.length; ++i) {
char[] fChars = flag.toCharArray();
char[] iChars = words[i].toCharArray();
int fLength = fChars.length;
int iLength = iChars.length;
// 跳转标志
boolean jump = false;
for(int j = 0; j < (fLength > iLength?iLength:fLength); ++j) {
int fNum = dictionary.get(fChars[j]);
int iNum = dictionary.get(iChars[j]);
if(fNum > iNum) {
// 跳转,去比较下一组
jump = true;
break;
}
if(fNum < iNum) {
return false;
}
}
if(jump) {
jump = false;
flag = words[i];
}else {
return false;
}
}
return true;
}
// 映射字典
private Map<Character, Integer> getDictionary(String order) {
Map<Character, Integer> dictionary = new HashMap<>();
int index = 26;
for(char o : order.toCharArray()) {
dictionary.put(o, index);
index--;
}
return dictionary;
}
}
提交记录里用时12ms和6ms的方法一模一样,连变量名都一样,emmmm
题号:917
给定一个字符串 S,返回 “反转后的” 字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转。
示例 1:
输入:“ab-cd”
输出:“dc-ba”
示例 2:
输入:“a-bC-dEf-ghIj”
输出:“j-Ih-gfE-dCba”
我的想法:
- 读取源字符串的每个字符,若是英文字母,倒序存放;若是其他字符,将其下标和字符关系存到哈希表中
- 重组新的字符串,添加字母字符,当遇到下标为其他字符时,添加其他字符
对应程序:
// java
class Solution {
public String reverseOnlyLetters(String S) {
// other<字符在字符数组中的索引值,字符>
Map<Integer, Character> other = new HashMap<>();
// 存放字母
LinkedList<Character> letterList = new LinkedList<>();
char[] SChar = S.toCharArray();
for(int i = 0; i < SChar.length; ++i) {
// 若是字母,倒序放入
if((SChar[i] >= 'a' && SChar[i] <= 'z') ||
(SChar[i] >= 'A' && SChar[i] <= 'Z')) {
letterList.addFirst(SChar[i]);
}else {
// 其他字符,添加映射
other.put(i, SChar[i]);
}
}
StringBuilder sb = new StringBuilder();
// letterList的索引
int index = 0;
for(int i = 0; i < S.length(); ++i) {
if(other.containsKey(i)) {
sb.append(other.get(i));
}else {
// 注意:不是letterList.get(i)
sb.append(letterList.get(index));
index++;
}
}
return sb.toString();
}
}