27.二叉树的镜像
思路:左右子节点交换
class Solution {
public void mirror(TreeNode root) {
if(root == null) return;
if(root.left!=null || root.right!=null){
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
mirror(root.left);
mirror(root.right);
}
}
}
28.对称的二叉树
思路:根左右=根右左
class Solution {
public boolean isSymmetric(TreeNode root) {
return isSymmetric(root, root);//镜像左==右
}
public boolean isSymmetric(TreeNode root1, TreeNode root2){
if(root1 == null && root2 == null) return true; //都空相等
if(root1 == null || root2 == null) return false; //存在一个空,不相等
if(root1.val == root2.val){//根节点相等,判断左右节点是否镜像
return isSymmetric(root1.left, root2.right) && isSymmetric(root1.right, root2.left);
}
return false;
}
}
29.顺时针打印链表
思路:定义四个方向对应的矩阵行列的加减,每次碰壁转弯90度。
class Solution {
public int[] printMatrix(int[][] matrix) {
if(matrix.length == 0 || matrix[0].length == 0) return new int[0];
int m = matrix.length;
int n = matrix[0].length;
int[] printArray = new int[m*n];//注意写法
boolean[][] visited = new boolean[m][n];
for(int i=0; i<m; i++)
for(int j=0; j<n; j++)
visited[i][j]=false;
int[] dx = {0, 1, 0, -1}, dy= {1, 0, -1, 0};//注意方向,与坐标轴无关,判断矩阵!!!
int x=0, y=0, d=0;
for(int i=0; i<m*n; i++){
printArray[i] = matrix[x][y];
visited[x][y] = true;
int a = x+dx[d], b = y+dy[d];
if(a<0 || a>=m || b<0 || b>=n || visited[a][b]==true){
d = (d+1)%4;
a = x+dx[d];
b = y+dy[d];
}
x=a;
y=b;
}
return printArray;
}
}
30.包含min函数的栈
思路:最小值栈
class MinStack {
Stack<Integer> numStack = new Stack<Integer>();
Stack<Integer> min = new Stack<Integer>();
/** initialize your data structure here. */
public MinStack() {
}
public void push(int x) {
numStack.push(x);
if(min.isEmpty()) min.push(x);
else{
if(x<min.peek()) min.push(x);
else min.push(min.peek());
}
}
public void pop() {
if(!numStack.isEmpty()){
numStack.pop();
min.pop();
}
}
public int top() {
if(!numStack.isEmpty()) return numStack.peek();
return -1;
}
public int getMin() {
if(!numStack.isEmpty()) return min.peek();
return -1;
}
}
31.栈的压入弹出序列
思路:按照压入序列入栈,如果弹出序列当前值相等则弹出,判断最后栈是否为空。
class Solution {
public boolean isPopOrder(int [] pushV,int [] popV) {
Stack<Integer> stack = new Stack<Integer>();
if(popV.length>pushV.length) return false;//弹出一定比压入短
for(int pushId=0, popId=0; pushId<pushV.length; pushId++){
stack.push(pushV[pushId]);//入栈
while(popId<popV.length && !stack.isEmpty() && stack.peek()==popV[popId] ){//如果相等,并且可以弹出,一直弹出
stack.pop();
popId++;//下一个弹出的值得索引
}
}
if(stack.isEmpty()) return true;
return false;
}
}
32.从上到下打印二叉树
32-1 不分行打印
思路:利用队列存储树节点
class Solution {
public List<Integer> printFromTopToBottom(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<TreeNode>();//存储节点的队列
List<Integer> printArray = new ArrayList<Integer>();//存储输出的list
if(root==null) return printArray;
queue.add(root);
while(!queue.isEmpty()){//不空
TreeNode cur = queue.poll();
if(cur!=null){
queue.add(cur.left);//左右放到队列里,先进先出
queue.add(cur.right);
printArray.add(cur.val);
}
}
return printArray;
}
}
32-2 分行打印
思路:记录当前栈中节点的个数,bfs
public List<List<Integer>> printFromTopToBottom(TreeNode root) {
List<List<Integer>> printList = new ArrayList<>();
if(root==null) return printList;//空
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
int k = queue.size();//每次都把队列排空,类似bfs的思想,所以记录当前队列个数。
while(!queue.isEmpty()){
List<Integer> tmp = new ArrayList<>();
while(k>0){
TreeNode cur = queue.poll();
if(cur!=null){
tmp.add(cur.val);
if(cur.left!=null) queue.add(cur.left);
if(cur.right!=null) queue.add(cur.right);
}
k--;
}
printList.add(tmp);
k = queue.size();
}
return printList;
}
32-3 之字形打印二叉树:
思路:reverse
class Solution {
public List<List<Integer>> printFromTopToBottom(TreeNode root) {
List<List<Integer>> printList = new ArrayList<>();
if(root==null) return printList;//空
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
int k = queue.size();//每次都把队列排空,类似bfs的思想,所以记录当前队列个数。
int level = 1;
while(!queue.isEmpty()){
List<Integer> tmp = new ArrayList<>();
while(k>0){
TreeNode cur = queue.poll();
if(cur!=null){
tmp.add(cur.val);
if(cur.left!=null) queue.add(cur.left);
if(cur.right!=null) queue.add(cur.right);
}
k--;
}
if((level&1)==0) Collections.reverse(tmp);//reverse
printList.add(tmp);
k = queue.size();
level++;
}
return printList;
}
}
34.二叉树中何为某一值的路径
思路:开list记录path,dfs左子节点,dfs右子节点。
class Solution {
public List<List<Integer>> ans= new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> findPath(TreeNode root, int sum) {
dfs(root,sum);
return ans;
}
public void dfs(TreeNode root, int sum){
if(root==null) return;
path.add(root.val);
sum = sum-root.val;
if(root.left==null && root.right==null && sum==0) ans.add(new ArrayList<>(path));//如果相等,ans里面加上path答案(new一个)
dfs(root.left, sum);//左子树
dfs(root.right, sum);//右子树
path.remove(path.size()-1);//算完当前节点移除
}
}
35.复杂链表的复刻
思路:原链表的下一个节点为复制节点。注意new复制的节点。并在最后,复原原链表。
class Solution {
public ListNode copyRandomList(ListNode head) {
ListNode p = head;
while(p!=null){//插入
ListNode tmp = p.next;
ListNode copyNode = new ListNode(p.val);
p.next = copyNode;
copyNode.next = tmp;
p = tmp;
}
p=head;
while(p!=null){//random域
if(p.random!=null){
p.next.random = p.random.next;
}
p = p.next.next;
}
ListNode dummy = new ListNode(-1);//虚拟头结点
ListNode cur = dummy;
p = head;
while(p!=null){//拆出复制的链表,复原原来的链表
cur.next = p.next;
p.next = p.next.next;
cur = cur.next;
p = p.next;
}
return dummy.next;
}
}
36.二叉搜索树与双向链表
思路:在中序递归的基础上改,用一个pre指针保存中序遍历的前一个结点。因为是中序遍历,遍历顺序就是双线链表的建立顺序;每一个结点访问时它的左子树肯定被访问过了,所以放心大胆的改它的left指针,不怕树断掉;同理,pre指向的结点保存的数肯定小于当前结点,所以其左右子树肯定都访问过了,所以其right指针也可以直接改。最后需要一直向左找到双向链表的头结点。
class Solution {
TreeNode pre = null;
public TreeNode convert(TreeNode root) {
dfs(root);
while(root!=null && root.left!=null) root = root.left;//返回root最左边
return root;
}
public void dfs(TreeNode root){
while(root==null) return;
dfs(root.left);//递归左侧
root.left=pre;//root的上一个为pre
if(pre!=null) pre.right = root;//pre的下一个为root
pre = root;
dfs(root.right);//递归右边
}
}
38. 字符串的排列
思路: