劍指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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章