LeetCode 376 Wiggle Subsequence
方法:DP
时间复杂度:O(n) 空间复杂度:O(n),滚动数组优化为O(1) 想法:用DP。参考了www.acwing.com/solution/co… up[i]代表以nums[i]为结尾的,最后一个状态是上升的最长wiggle subsequence长度,down[i]代表以nums[i]为结尾的,最后一个状态是下降的最长wiggle subsequence长度。当往后遍历的时候,如果这个值大于之前那个值,说明往上拐了一下,up[i] = down[i - 1] + 1。如果这个值小于之前那个值,说明往下拐了一下,down[i] = up[i - 1] + 1。写完会发现i处的状态只与i-1的状态有关,因此很容易用两个变量up和down代替数组。 代码:
class Solution {
public int wiggleMaxLength(int[] nums) {
int n = nums.length;
int[] up = new int[n];
int[] down = new int[n];
up[0] = 1;
down[0] = 1;
for (int i = 1; i < n; i++) {
if (nums[i] > nums[i - 1]) {
up[i] = down[i - 1] + 1;
down[i] = down[i - 1];
}
else if (nums[i] < nums[i - 1]) {
down[i] = up[i - 1] + 1;
up[i] = up[i - 1];
}
else {
up[i] = up[i - 1];
down[i] = down[i - 1];
}
}
return Math.max(up[n - 1], down[n - 1]);
}
}
LeetCode 329 Longest Increasing Path in a Matrix
方法:DFS+memo
时间复杂度:O(mn) 空间复杂度:O(mn) 想法:比较好想的DFS,然后仔细再想想就会发现有重复调用,因此是DFS+memo。不是很清楚为什么标的hard。dfs为int型,返回的就是在matrix的[x,y]这个坐标,最长的increasing path的长度。因为假设说我要求从[x,y]这个地方开始,它有一些increasing path,这些path的第二个节点一定是围着[x,y]的那一圈、并且值比matrix[x][y]大的元素,并且length(x,y) = length(newX, newY + 1)。最后求的最长的长度就是里面的最大值。 代码:
class Solution {
private int[][] memo;
private int m, n;
private int[] dx = new int[] {0, -1, 0, 1};
private int[] dy = new int[] {-1, 0, 1, 0};
public int longestIncreasingPath(int[][] matrix) {
m = matrix.length;
n = matrix[0].length;
memo = new int[m][n];
int res = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
res = Math.max(res, dfs(matrix, i, j));
}
}
return res;
}
private int dfs(int[][] matrix, int x, int y) {
if (memo[x][y] != 0) {
return memo[x][y];
}
int ans = 1;
for (int i = 0; i < 4; i++) {
int newX = x + dx[i];
int newY = y + dy[i];
if (!isValid(newX, newY) || matrix[newX][newY] <= matrix[x][y]) {
continue;
}
ans = Math.max(ans, dfs(matrix, newX, newY) + 1);
}
memo[x][y] = ans;
return ans;
}
private boolean isValid(int x, int y) {
return x >= 0 && x < m && y >= 0 && y < n;
}
}
LeetCode 301 Remove Invalid Parentheses
方法:DFS
时间复杂度:O(2l+r),其中l和r分别为字符串中多余的左、右括号 空间复杂度:O(n2) 想法:数据规模比较小,可以用DFS做。解法是看的zxi.mytechroad.com/blog/search… 。我一开始做这道题的时候觉得应该会有更好的做法,但确实也没想到。那这种做法就比较直接,就是先统计多余的左括号有多少个,多余的右括号有多少个,然后以这两个数,和遍历到字符串的index来做dfs,每次如果还有多余的左括号,并且目前搜到的这个地方对应的是左括号,就试图删它。有右括号同理。删完括号判定是不是valid就可以了。 代码:
class Pair {
public int left, right;
public Pair(int left, int right) {
this.left = left;
this.right = right;
}
}
class Solution {
public List<String> removeInvalidParentheses(String s) {
Pair p = getLeftRight(s);
int l = p.left, r = p.right;
List<String> res = new ArrayList<>();
dfs(s, l, r, 0, res);
return res;
}
private void dfs(String s, int left, int right, int index, List<String> res) {
if (left == 0 && right == 0) {
if (isValid(s)) {
res.add(s);
}
return;
}
for (int i = index; i < s.length(); i++) {
if (i != index && s.charAt(i) == s.charAt(i - 1)) {
continue;
}
char c = s.charAt(i);
String tmp = s.substring(0, i) + s.substring(i + 1, s.length());
if (c == '(' && left > 0) {
dfs(tmp, left - 1, right, i, res);
}
else if (c == ')' && right > 0) {
dfs(tmp, left, right - 1, i, res);
}
}
}
private boolean isValid(String s) {
Pair p = getLeftRight(s);
return p.left == 0 && p.right == 0;
}
private Pair getLeftRight(String s) {
int left = 0, right = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') {
left++;
}
else if (c == ')') {
if (left > 0) {
left--;
}
else {
right++;
}
}
}
return new Pair(left, right);
}
}