【Day14】每天三算法
题目
NC16 对称的二叉树
描述
思考
咱们考虑用递归的思想解决这道题
如果要满足题目给出的要求,不难发现我们需要满足的条件如下:
left.val == right.val
left.left.val == right.right.val
left.right.val == right.left.val
了解这些条件后,我们的递归代码就不难给出了
题解
这里要注意所有可能的递归终止调价
public class Solution {
public boolean isSymmetrical(TreeNode pRoot) {
if (pRoot==null) return true;
return dfs(pRoot.left,pRoot.right);
}
public boolean dfs(TreeNode left,TreeNode right) {
if (left==null && right==null) return true;
if (left==null || right==null) return false;
if (left.val!=right.val) return false;
return dfs(left.left,right.right) && dfs(left.right,right.left);
}
}
NC26 括号生成
描述
思考
这道题我们可以用回溯的思路来解决
当 n=3 时,观察所有的括号生成式
((())), (()()), (())(), ()(()), ()()()
可以发现,每个位置,一定是保证左括号个数大于或等于右括号的
但是最后,左括号个数一定要和右括号个数相等
题解
public class NC26_generateParenthesis {
public ArrayList<String> generateParenthesis (int n) {
ArrayList<String> res = new ArrayList<>();
backTrack(n,n,new StringBuilder(),res);
return res;
}
public void backTrack(int ls,int rs,StringBuilder track,ArrayList<String> res) {
// 递归终止条件
if (ls==0 && rs==0) {
res.add(track.toString());
return;
}
if (ls==rs) {
track.append("(");
backTrack(ls-1,rs,track,res);
track.replace(track.length()-1,track.length(),"");
} else {
if (ls>0) {
track.append("(");
backTrack(ls-1,rs,track,res);
track.replace(track.length()-1,track.length(),"");
}
track.append(")");
backTrack(ls,rs-1,track,res);
track.replace(track.length()-1,track.length(),"");
}
}
}
小结
这道题虽然在牛客上标榜中等难度题目,但其实只要借助回溯算法,就可以很轻松的解出
这里还要提醒各位一句,80% 的题,如果没有思路,借助回溯或者利用回溯的思想,肯定能写出来
所以遇到回溯的题希望各位重视起来
NC18 顺时针旋转矩阵
描述
示例:
输入:
[[1,2,3],
[4,5,6],
[7,8,9]],3
返回:
[[7,4,1],
[8,5,2],
[9,6,3]]
思考
方法1:
对于阶为3的矩阵,我们可以观察一下不同坐标旋转以后的规律
(0,0) -> (0,2)
(0,1) -> (1,2)
(0,2) -> (2,2)
(1,0) -> (0,1)
可以发现有如下规律:
(i,j) -> (j,n-i-1)
那么思路就比较明显了,我们可以再开辟一个新的矩阵空间,然后遍历原矩阵,重新计算每个坐标在新矩阵的新坐标,然后进行赋值
方法2:
还有一个,就是矩阵旋转的标准做法了
对于顺时针旋转90度,我们可以让它先沿主对角线翻转,然后在左右翻转
借助初中几何,我们可以计算出用这种方法,转换后的坐标是多少
这里要注意,因为我们的坐标是从0开始的,所以最后我们那个n 要-1,也就算出了纵坐标是 n-1-i
题解
方法1:
创建新的空间,然后用公式计算每个坐标的新坐标进行替换
public class Solution {
public int[][] rotateMatrix(int[][] mat, int n) {
if (mat==null || mat.length==0) return null;
int[][] res = new int[mat.length][mat[0].length];
for (int i = 0; i < mat.length; i++) {
for (int j = 0; j < mat[0].length; j++) {
res[j][n-i-1] = mat[i][j];
}
}
return res;
}
}
方法2:
使用矩阵转换的坐标性质
public class Solution {
public int[][] rotateMatrix(int[][] mat, int n) {
// 主对角线反转
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
swap(mat,i,j,j,i);
}
}
// 左右反转
for (int i = 0; i < n; i++) {
for (int j = 0; j < n / 2; j++) {
swap(mat,i,j,i,n-j-1);
}
}
return mat;
}
private void swap(int[][]mat,int x1,int y1,int x2,int y2) {
int tmp = mat[x1][y1];
mat[x1][y1]=mat[x2][y2];
mat[x2][y2]=tmp;
}
}
小结
这道题的代码不难,其实只涉及基础的循环分支语句
主要是想到合理的矩阵旋转的算法比较麻烦