重复的子字符串
- 题目。给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
- 思路。O(N*N) 的解法比较好想。O(N)的解法是将两个 s连在一起得到ss,并移除第一个和最后一个字符。如果 ss 是该字符串的子串,那么 ss 就满足题目要求。
- 代码。
public boolean repeatedSubstringPattern(String s) {
if (s == null || s.length() == 0) {
return true;
}
return (s + s).indexOf(s, 1) != s.length();
// char[] ch = s.toCharArray();
// for (int i = 1; i * 2 <= ch.length; i++) {
// if (ch.length % i != 0) {
// continue;
// }
// boolean match = true;
// for (int j = i; j < ch.length; j++) {
// if (ch[j] != ch[j - i]) {
// match = false;
// break;
// }
// }
// if (match) {
// return true;
// }
// }
// return false;
}
递增子序列
-
题目。给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。示例:
输入: [4, 6, 7, 7]
输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/increasing-subsequences -
思路。枚举所有结果。对于当前的位置,我们可以选也可以不选。如果选择当前元素,则必须满足当前元素大于前一个元素;如果不选择当前元素,那么前提是当前元素不等于前一个元素。
-
代码。
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> tmp = new ArrayList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
if (nums == null || nums.length == 0 || nums.length == 1) {
return new ArrayList<>();
}
dfs(0, Integer.MIN_VALUE, nums);
return res;
}
private void dfs(int curIndex, int preValue, int[] nums) {
if (curIndex == nums.length) {
if (tmp.size() >= 2) {
res.add(new ArrayList<>(tmp));
}
return;
}
if (nums[curIndex] >= preValue) {
tmp.add(nums[curIndex]);
dfs(curIndex + 1, nums[curIndex], nums);
tmp.remove(tmp.size() - 1);
}
if (nums[curIndex] != preValue) {
dfs(curIndex + 1, preValue, nums);
}
}
}
电话号码的字母组合
-
题目。给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number -
思路。基于深度优先遍历,使用i表示当前遍历到的位置,如果i等于digits.length则得到了一个结果。
-
代码。
class Solution {
public List<String> letterCombinations(String digits) {
if (digits == null || digits.length() == 0) {
return new ArrayList<>();
}
char[] ch = digits.toCharArray();
List<String> res = new ArrayList<>();
search(ch, 0, "", res);
return res;
}
/**
* 表示从i位置开始,已有的字符串是s,能够得到的结果
*/
private void search(char[] ch, int i, String s, List<String> res) {
if (i == ch.length) {
res.add(s);
return;
}
char[] letters = letters(ch[i]);
for (char c : letters) {
search(ch, i + 1, s + c, res);
}
}
private char[] letters(char ch) {
List<Character> res = new ArrayList<>();
if (ch == '2') {
return new char[] {'a', 'b', 'c'};
}
if (ch == '3') {
return new char[] {'d', 'e', 'f'};
}
if (ch == '4') {
return new char[] {'g', 'h', 'i'};
}
if (ch == '5') {
return new char[] {'j', 'k', 'l'};
}
if (ch == '6') {
return new char[] {'m', 'n', 'o'};
}
if (ch == '7') {
return new char[] {'p', 'q', 'r', 's'};
}
if (ch == '8') {
return new char[] {'t', 'u', 'v'};
}
return new char[] {'w', 'x', 'y', 'z'};
}
}
重新安排行程
- 题目。给定一个机票的字符串二维数组 [from, to],子数组中的两个成员分别表示飞机出发和降落的机场地点,对该行程进行重新规划排序。所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。
提示:
如果存在多种有效的行程,请你按字符自然排序返回最小的行程组合。例如,行程 [“JFK”, “LGA”] 与 [“JFK”, “LGB”] 相比就更小,排序更靠前
所有的机场都用三个大写字母表示(机场代码)。
假定所有机票至少存在一种合理的行程。
所有的机票必须都用一次 且 只能用一次。
示例 1:
输入:[[“MUC”, “LHR”], [“JFK”, “MUC”], [“SFO”, “SJC”], [“LHR”, “SFO”]]
输出:[“JFK”, “MUC”, “LHR”, “SFO”, “SJC”]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reconstruct-itinerary - 思路。一道欧拉图相关的题。
- 代码。
class Solution {
public List<String> findItinerary(List<List<String>> tickets) {
if (tickets == null || tickets.size() == 0) {
return new ArrayList<>();
}
LinkedList<String> res = new LinkedList<>();
// 构造图
Map<String, PriorityQueue<String>> graph = new HashMap<>();
for (List<String> ticket : tickets) {
PriorityQueue<String> edges = graph.computeIfAbsent(ticket.get(0), k -> new PriorityQueue<>());
edges.add(ticket.get(1));
}
visit(graph, "JFK", res);
return res;
}
private void visit(Map<String, PriorityQueue<String>> graph, String cur, LinkedList<String> res) {
PriorityQueue<String> edges = graph.get(cur);
while (edges != null && edges.size() > 0) {
String neighbor = edges.poll();
visit(graph, neighbor, res);
}
res.addFirst(cur);
}
}
机器人能否返回原点
-
题目。在二维平面上,有一个机器人从原点 (0, 0) 开始。给出它的移动顺序,判断这个机器人在完成移动后是否在 (0, 0) 处结束。
移动顺序由字符串表示。字符 move[i] 表示其第 i 次移动。机器人的有效动作有 R(右),L(左),U(上)和 D(下)。如果机器人在完成所有动作后返回原点,则返回 true。否则,返回 false。
注意:机器人“面朝”的方向无关紧要。 “R” 将始终使机器人向右移动一次,“L” 将始终向左移动等。此外,假设每次移动机器人的移动幅度相同。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/robot-return-to-origin -
思路。简单的题。
-
代码。
class Solution {
public boolean judgeCircle(String moves) {
int l = 0;
int r = 0;
int u = 0;
int d = 0;
char[] ch = moves.toCharArray();
for (char c : ch) {
if (c == 'L') {
l++;
} else if (c == 'R') {
r++;
} else if (c == 'U') {
u++;
} else {
d++;
}
}
return l == r && u == d;
}
}
最短回文串
- 题目。给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入: “aacecaaa”
输出: “aaacecaaa”
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shortest-palindrome - 思路。Manacher的变种。找到必须包含第一个字符的最长回文子串,将后面的部分反转填到原始字符串前面即可。
- 代码。
class Solution {
public String shortestPalindrome(String s) {
if (s == null || s.length() == 0) {
return s;
}
// 找到必须包含第一个字符的最长回文子串,将后面的部分反转填到原始字符串前面即可
char[] ch = convert(s);
// pArr[i]表示以i位置的字符为中心,向左右两边可以扩出去的最大回文半径
int[] pArr = new int[ch.length];
// 最右即将到达的位置
int pR = -1;
// 最近一次pR更新时,回文中心的位置
int index = -1;
// 包含第一个字符的最长回文半径长度
int maxContainsStart = -1;
for (int i = 0; i < ch.length; i++) {
pArr[i] = i < pR ? Math.min(pArr[2 * index - i], pR - i) : 1;
// 向两边扩
while (i + pArr[i] < ch.length && i - pArr[i] > -1) {
if (ch[i + pArr[i]] == ch[i - pArr[i]]) {
pArr[i]++;
} else {
break;
}
}
if (i + pArr[i] > pR) {
pR = i + pArr[i];
index = i;
}
if (i + 1 == pArr[i]) {
maxContainsStart = Math.max(maxContainsStart, pArr[i]);
}
}
int resIndex = (maxContainsStart - 1) * 2;
if (ch.length - 1 == resIndex) {
return s;
}
char[] prefix = new char[ch.length - 1 - resIndex];
int j = 0;
for (int i = ch.length - 1; i > resIndex; i--) {
prefix[j++] = ch[i];
}
String s1 = String.valueOf(prefix) + String.valueOf(ch);
StringBuilder res = new StringBuilder();
for (int i = 0; i < s1.length(); i++) {
if ((i & 1) == 1) {
res.append(s1.charAt(i));
}
}
return res.toString();
}
private char[] convert(String s) {
char[] ch = s.toCharArray();
char[] res = new char[2 * ch.length + 1];
int index = 0;
for (int i = 0; i < res.length; i++) {
res[i] = (i & 1) == 0 ? '#' : ch[index++];
}
return res;
}
}