剑指offer第三周

剑指Offer第三周

35.反转链表

定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

思考题:

  • 请同时实现迭代版本和递归版本。

样例

输入:1->2->3->4->5->NULL

输出:5->4->3->2->1->NULL

pre,cur,next,暴力翻转

pre = null,cur = pre, pre = cur,cur = next; 翻转 模板

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null, cur = head;
        while(cur != null){
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }
}

36.合并两个排序的链表

输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。

样例

输入:1->3->5 , 2->4->5

输出:1->2->3->4->5->5

没什么好说的,归并排序的思想

class Solution {
    public ListNode merge(ListNode l1, ListNode l2) {
        ListNode dump = new ListNode(-1);
        ListNode head = dump;
        while(l1 != null && l2 != null){
            if(l1.val <= l2.val){
                dump.next = l1;
                dump = dump.next;
                l1 = l1.next;
            }else{
                dump.next = l2;
                dump = dump.next;
                l2 = l2.next;
            }
        }
        if(l1 != null) dump.next = l1;
        else dump.next = l2;
        return head.next;
    }
}

37.树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。

我们规定空树不是任何树的子结构。

样例

树A:

     8
    / \
   8   7
  / \
 9   2
    / \
   4   7

树B:

   8
  / \
 9   2

返回 true ,因为B是A的子结构。

写一个helper函数,判断两棵树是否相等。递归判断每一个节点

class Solution {
    public boolean hasSubtree(TreeNode p, TreeNode q) {
        if(p == null || q == null)return false;
        return helper(p,q) || hasSubtree(p.left,q) || hasSubtree(p.right,q);
    }
    public boolean helper(TreeNode p, TreeNode q){
        if(p == null && q == null)return true;
        if(p == null)return false;
        if(q == null)return true;
        if(p.val != q.val)return false;
        return helper(p.left,q.left) && helper(p.right,q.right);
    }
}

38.二叉树的镜像

输入一个二叉树,将它变换为它的镜像。

样例

输入树:
      8
     / \
    6  10
   / \ / \
  5  7 9 11

 [8,6,10,5,7,9,11,null,null,null,null,null,null,null,null] 
输出树:
      8
     / \
    10  6
   / \ / \
  11 9 7  5

 [8,10,6,11,9,7,5,null,null,null,null,null,null,null,null]

对每一个节点的左右子树进行交换

class Solution {
    public void mirror(TreeNode root) {
        if(root == null)return ;
        mirror(root.left);
        mirror(root.right);
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
    }
}

39.对称的二叉树

请实现一个函数,用来判断一棵二叉树是不是对称的。

如果一棵二叉树和它的镜像一样,那么它是对称的。

样例

如下图所示二叉树[1,2,2,3,4,4,3,null,null,null,null,null,null,null,null]为对称二叉树:
    1
   / \
  2   2
 / \ / \
3  4 4  3

如下图所示二叉树[1,2,2,null,4,4,3,null,null,null,null,null,null]不是对称二叉树:
    1
   / \
  2   2
   \ / \
   4 4  3

拿树的左边和右边比,右边和左边比

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null)return true;
        return helper(root.left,root.right);
    }
    public boolean helper(TreeNode p,TreeNode q){
        if(p == null && q == null)return true;
        if(p == null || q == null)return false;
        if(p.val == q.val) return helper(p.left,q.right) && helper(p.right,q.left);
        return false;
    }
}

40.顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

样例

输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]

输出:[1,2,3,4,8,12,11,10,9,5,6,7]

直接模拟

class Solution {
    public int[] printMatrix(int[][] matrix) {
        int r = matrix.length;
        if(r <= 0)return new int[0];
        int c = matrix[0].length,i = 0, j = 0,cnt = 0;
        boolean[][] vis = new boolean[r][c];
        int total = r * c;
        int[] res = new int[total];
        
        while(cnt < total){
            // 右
            while(j < c && !vis[i][j]){
                res[cnt++] = matrix[i][j];
                vis[i][j] = true;
                j++;
            }
            j--;i++;
            // 下
            while(i < r && !vis[i][j]){
                res[cnt++] = matrix[i][j];
                vis[i][j] = true;
                i++;
            }
            i--;j--;
            // 左
            while(j >= 0 && !vis[i][j]){
                res[cnt++] = matrix[i][j];
                vis[i][j] = true;
                j--;
            }
            j++;i--;
            // 上
            while(i >= 0 && !vis[i][j]){
                res[cnt++] = matrix[i][j];
                vis[i][j] = true;
                i--;
            }
            i++;j++;
        }
        return res;
        
    }
}

d 为方向,下一个点不能走则换方向

class Solution {
    public int[] printMatrix(int[][] matrix) {
        int r = matrix.length;
        if(r <= 0)return new int[0];
        int c = matrix[0].length,cnt = 0,d = 0;
        boolean[][] vis = new boolean[r][c];
        int[] res = new int[r * c],dx = {0,1,0,-1}, dy = {1,0,-1,0};
        int x = 0,y = 0;
        
        for(int i = 0; i < r * c; i ++){
            res[cnt++] = matrix[x][y];
            vis[x][y] = true;
            int a = x + dx[d], b = y + dy[d];
            if(a < 0 || a >= r || b < 0 || b >= c || vis[a][b]){
                d = (d + 1) % 4;
                a = x + dx[d]; b = y + dy[d];
            }
            x = a; y = b;
        }
        
        return res;
        
    }
}

41.包含min函数的栈

设计一个支持push,pop,top等操作并且可以在O(1)时间内检索出最小元素的堆栈。

  • push(x)–将元素x插入栈中
  • pop()–移除栈顶元素
  • top()–得到栈顶元素
  • getMin()–得到栈中最小元素

样例

MinStack minStack = new MinStack();
minStack.push(-1);
minStack.push(3);
minStack.push(-4);
minStack.getMin();   --> Returns -4.
minStack.pop();
minStack.top();      --> Returns 3.
minStack.getMin();   --> Returns -1.

设置一个min,存储最小的值,当min要发生改变时,将这个min存入stack,方便min被pop时,取出前一个min;

class MinStack {
    Stack<Integer> stack;
    Integer min;
    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack<>();
        min = Integer.MAX_VALUE;
    }
    
    public void push(int x) {
        if(x <= min){
            stack.push(min);
            min = x;
            stack.push(x);
        }else stack.push(x);
        
    }
    
    public void pop() {
        Integer cur = stack.pop();
        if(cur == min){
            min = stack.pop();
        }
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return min;
    }
}

42. 栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。

假设压入栈的所有数字均不相等。

例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

注意:若两个序列长度不等则视为并不是一个栈的压入、弹出序列。若两个序列都为空,则视为是一个栈的压入、弹出序列。

样例

输入:[1,2,3,4,5]
      [4,5,3,2,1]

输出:true

当前只有两个操作:

  1. 当栈顶元素与其相等时,pop
  2. 佛则入栈

如果栈顶不相等也Pop,的话,序列就不对了;

class Solution {
    public boolean isPopOrder(int[] push,int[] pop) {
        if(push.length != pop.length)return false;
        Stack<Integer> stack = new Stack<>();
        int i = 0;
        for(Integer num : push){
            stack.push(num);
            while(!stack.isEmpty() && stack.peek() == pop[i]){
                stack.pop();
                i ++;
            }
        }
        return stack.isEmpty();
    }
}

43.不分行从上往下打印二叉树

从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。

样例

输入如下图所示二叉树[8, 12, 2, null, null, 6, null, 4, null, null, null]
    8
   / \
  12  2
     /
    6
   /
  4

输出:[8, 12, 2, 6, 4]

简单层次遍历

class Solution {
    public List<Integer> printFromTopToBottom(TreeNode root) {
        if(root == null) return new ArrayList<Integer>();
        List<Integer> list = new ArrayList<Integer>();
        ArrayDeque<TreeNode> q = new ArrayDeque<TreeNode>();
        q.offer(root);
        list.add(root.val);
        
        while(!q.isEmpty()){
            int count = q.size();
            for(int i = 0; i < count; i ++){
                TreeNode cur = q.poll();
                if(cur.left != null){
                    list.add(cur.left.val);
                    q.offer(cur.left);
                }
                if(cur.right != null){
                    list.add(cur.right.val);
                    q.offer(cur.right);
                }
            }
        }
        
        return list;
    }
}

44.分行从上往下打印二叉树

从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行。

样例

输入如下图所示二叉树[8, 12, 2, null, null, 6, null, 4, null, null, null]
    8
   / \
  12  2
     /
    6
   /
  4

输出:[[8], [12, 2], [6], [4]]

跟上一题一模一样,宽搜即可,每个cout代表每一层的个数

class Solution {
    public List<List<Integer>> printFromTopToBottom(TreeNode root) {
        if(root == null) return new ArrayList<>();
        List<List<Integer>> list = new ArrayList<>();
        ArrayDeque<TreeNode> q = new ArrayDeque<TreeNode>();
        q.offer(root);
        ArrayList<Integer> pp = new ArrayList<Integer>();pp.add(root.val);
        list.add(pp);
        
        while(!q.isEmpty()){
            int count = q.size();
            ArrayList<Integer> temp = new ArrayList<Integer>();
            for(int i = 0; i < count; i ++){
                TreeNode cur = q.poll();
                if(cur.left != null){
                    temp.add(cur.left.val);
                    q.offer(cur.left);
                }
                if(cur.right != null){
                    temp.add(cur.right.val);
                    q.offer(cur.right);
                }
            }
            if(temp.size() > 0)list.add(temp);
        }
        
        return list;
    }
}

45.之字形打印二叉树

请实现一个函数按照之字形顺序从上向下打印二叉树。

即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

样例

输入如下图所示二叉树[8, 12, 2, null, null, 6, 4, null, null, null, null]
    8
   / \
  12  2
     / \
    6   4
输出:[[8], [2, 12], [6, 4]]

同理,在上一题的基础上,加一个flag标志位,代表当前从左往右,还是从右往左;

class Solution {
    public List<List<Integer>> printFromTopToBottom(TreeNode root) {
        if(root == null) return new ArrayList<>();
        List<List<Integer>> list = new ArrayList<>();
        ArrayDeque<TreeNode> q = new ArrayDeque<TreeNode>();
        q.offer(root);
        ArrayList<Integer> pp = new ArrayList<Integer>();pp.add(root.val);
        list.add(pp);
        boolean f = false;
        
        
        while(!q.isEmpty()){
            int count = q.size();
            ArrayList<Integer> temp = new ArrayList<Integer>();
            for(int i = 0; i < count; i ++){
                if(f){
                    TreeNode cur = q.pollFirst();
                    if(cur.left != null){
                        temp.add(cur.left.val);
                        q.offerLast(cur.left);
                    }
                    if(cur.right != null){
                        temp.add(cur.right.val);
                        q.offerLast(cur.right);
                    }
                }else{
                    TreeNode cur = q.pollLast();
                    if(cur.right != null){
                        temp.add(cur.right.val);
                        q.offerFirst(cur.right);
                    }
                    if(cur.left != null){
                        temp.add(cur.left.val);
                        q.offerFirst(cur.left);
                    }
                }
            }
            f = !f;
            if(temp.size() > 0)list.add(temp);
        }
        return list;
    }
}
class Solution {
    public List<List<Integer>> printFromTopToBottom(TreeNode root) {
        List res = new ArrayList();
        List<TreeNode> q = new ArrayList<>();
        if(root != null)q.add(root);
        boolean reverse = false;
        
        while(q.size() > 0){
            List cur_v = new ArrayList();
            List cur_q = new ArrayList();
            for(TreeNode t : q){
                cur_v.add(t.val);
                if(t.left != null)cur_q.add(t.left);
                if(t.right != null)cur_q.add(t.right);
            }
            q = cur_q;
            if(reverse)Collections.reverse(cur_v);
            reverse = !reverse;
            res.add(cur_v);
        }
        
        return res;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章