301. 删除无效的括号
java
static List<String> res;
public List<String> removeInvalidParentheses(String s) {
res = new ArrayList<>();
char[] charArray = s.toCharArray();
int lR = 0, rR = 0; // 待删除的左括号数量和右括号数量
int n = charArray.length;
// 统计一下要删除的左括号数量和右括号数量
for (int i = 0; i < n; i++) {
if (charArray[i] == '(') {
lR ++;
} else if (charArray[i] == ')') {
if (lR == 0) rR ++;
else lR --;
}
}
helper(s, 0, lR, rR);
return res;
}
static void helper(String s, int start, int lR, int rR) {
if (lR == 0 && rR == 0) {
if (isValid(s)) {
res.add(s);
}
return;
}
int n = s.length();
for (int i = start; i < n; i++) {
// 去重
if (i != start && s.charAt(i) == s.charAt(i-1)) continue;
// 剩下的元素不够删除,说明失败了
if (lR + rR > n - i) return;
// 尝试删除掉一个 (
if (lR > 0 && s.charAt(i) == '(') helper(s.substring(0, i) + s.substring(i+1), i, lR - 1, rR);
// 尝试删除掉一个 )
if (rR > 0 && s.charAt(i) == ')') helper(s.substring(0, i) + s.substring(i+1), i, lR, rR - 1);
}
}
static boolean isValid(String s) {
int n = s.length();
int cnt = 0;
for (int i = 0; i < n; i++) {
char ch = s.charAt(i);
if (ch == '(') cnt ++;
else if (ch == ')') cnt --;
if (cnt < 0) return false;
}
return cnt == 0;
}
解题思路:这道题的解题思路就是统计出总共需要进行删除的左括号数量和右括号数量,然后进行不断地尝试,直到字符串合法就直接加入返回的集合中
300. 最长递增子序列
java
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
int res = 0;
for (int i = 0; i < n; i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
res = Math.max(res, dp[i]);
}
return res;
}
}
解题思路:这道题的解法就是直接=用动规,我们需要假设每一个位置为最后一个位置,求从0到这个位置的最长递增子序列的长度,所以我们会额外用一个 j 的循环枚举 i 前面部分,并不断的更新 dp[i] ,最后就能得到这部分序列的答案
297. 二叉树的序列化与反序列化
java
public class Codec {
static final String INF = "null";
static final String SPLIT = ",";
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
serializeHelper(root, sb);
return new String(sb.deleteCharAt(sb.length() - 1));
}
static void serializeHelper(TreeNode node, StringBuilder sb) {
if (node == null) {
sb.append(INF).append(SPLIT);
return;
}
// 前序遍历
sb.append(node.val).append(SPLIT);
serializeHelper(node.left, sb);
serializeHelper(node.right, sb);
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
String[] stk = data.split(SPLIT);
Deque<String> deque = new LinkedList<>();
for (int i = 0; i < stk.length; i++) {
deque.offer(stk[i]);
}
return deserializeHelper(deque);
}
static TreeNode deserializeHelper(Deque<String> deque) {
if (deque.isEmpty()) return null;
String s = deque.pop();
if (s.equals(INF)) return null;
// 构建当前节点
TreeNode node = new TreeNode(Integer.parseInt(s));
node.left = deserializeHelper(deque);
node.right = deserializeHelper(deque);
return node;
}
}
解题思路:这里需要记录每一层的节点,所以使用前序遍历的方式,如果节点是null的话就使用标记
恢复的时候同样是使用前序遍历的方式进行恢复
287. 寻找重复数
https://leetcode.cn/problems/find-the-duplicate-number/?envType=problem-list-v2&envId=2cktkvj
java
class Solution {
public int findDuplicate(int[] nums) {
int slow, fast;
slow = fast = 0;
while(true) {
slow = nums[slow];
fast = nums[nums[fast]];
if (slow == fast) break;
}
fast = 0;
while(true) {
slow = nums[slow];
fast = nums[fast];
if (slow == fast) return fast;
}
}
}

解题思路:这道题可以转换成链表,并且可以发现重复的元素就是链表的入环点,那么就要可以转换成求链表的入环点,使用弗洛伊德龟兔赛跑算法
具体的步骤就是一快一慢,第一次相遇之后,其中一个回到起点,再以相同速率走,下一次相遇点就是入环点(之前我有证明过,这里不再证明)