java的集合类使用方法

  1. Stack<ListNode> stack = new Stack<ListNode>();
  2. stack.push(temp);
  3. stack.pop()
  4. stack.size()

哈希表

HashMap<Integer,Integer> dic = new HashMap<>();
dic.put(inorder[i],i);
int i = dic.get(po[pre_root]);

常见模板

快速幂模板

快速幂用于求解a^b的大量数据的时候

int x // 是底数
int exp // exp是指数
int res // 结果
while(exp>0){

        if((exp&1) == 1){ // 位运算判断奇偶
            res*=x;
        }
        x *=x;
        exp>>=1; // 位运算 /2
        }

GCD

private int gcd(int a, int b) {
        return b == 0? a: gcd(b, a % b);
    }

数组

数组中重复的数字

剑指offer刷题笔记 - 图1 思路1: 利用自身的特性,一共是n个数字,包含(1-n-1)= = 懒得解释了。剑指offer刷题笔记 - 图2

public class Solution {
    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(length ==0 || numbers== null)return  false;
        for(int i=0;i<length-1;i++)
        {
            while (i != numbers[i]){
                if(numbers[i] == numbers[numbers[i]]){
                    duplication[0]= numbers[i];
                    return true;
                }
                int tmp = numbers[i];
                numbers[i] = numbers[tmp];
                numbers[tmp] = tmp;
            }
        }return false;

    }
}

思路2: 直接排序,遍历一下。复杂度nlogn+n

public boolean duplicate(int numbers[],int length,int [] duplication) {
         if(length==0|| numbers == null) return  false;
        Arrays.sort(numbers);
        for(int i =1;i<length;i++){
            if(numbers[i] ==numbers[i-1]){
                duplication[0] = numbers[i];
                return true;
            }

        }
        return false;

思路3: 哈希表,把数据放在哈希表里面,要是不在里面就放进去,在里面就返回结果。

public boolean duplicate(int numbers[],int length,int [] duplication) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < length; i++){
            if(map.containsKey(numbers[i])){
                duplication[0] = numbers[i];
                return true;
            }
            map.put(numbers[i],i);
        }
        return false;

    }
}

2020年1月10日


不修改数组找出重复的数字

在一个长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但是不能修改输入的数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者3。
思路1: 使用哈希表,或者一个数组来已经有的数字。遇到已经有的就跳出。

public int find_dup_num(int[] nums){
        int len = nums.length;
        Map<Integer,Integer> tmp = new HashMap<>();
        for(int i=0;i<len;i++){
            if(tmp.containsKey(nums[i])){
                return  nums[i];
            }
            else {
                tmp.put(nums[i],i);
            }
        }
        return -1;

思路2: 利用题目的特性,1-n的范围,我们把从1n的数字从中间的数字m分为两部分,前面一半为1m,后面一半为m+1n。如果1m的数字的数目等于m,则不能直接判断这一半区间是否包含重复的数字,反之,如果大于m,那么这一半的区间一定包含重复的数字;如果小于m,另一半m+1~n的区间里一定包含重复的数字。接下来,我们可以继续把包含重复的数字的区间一分为二,直到找到一个重复的数字。
由于如果1~m的数字的数目等于m,则不能直接判断这一半区间是否包含重复的数字,我们可以逐步减少m,然后判断1~m之间是否有重复的数,即,我们可以令m=m-1,然后再计算1~m的数字的数目是否等于m,如果等于m,再令m=m-1,如果大于m,则说明1~m的区间有重复的数,如果小于m,则说明m+1~n有重复的数,不断重复此过程。 代码

public int getDuplication(int[] nums,int length){
        if(nums.length<=0 || nums == null) return -1;
        int start = 1;
        int end = length -1;
        while (end>=start){
            int mid = start+(end -start)/2;
            int count = countRange(nums,length,start,mid);
            if(end == start){
                if(count >1){
                    return start;
                }else break;
            }
            if(count> (mid-start+1)){
                end = mid;
            }else {
                start = mid+1;
            }
        }
        return -1;
    }
    public int countRange(int[] nums,int length,int start,int end){
        int count = 0;
        for(int i:nums){
            if(i>=start&& i<= end){
                ++count;
            }
        }
        return count;
    }

04-二维数组中的查找

剑指offer刷题笔记 - 图3
思路1: 暴力枚举
思路2: 剑指offer刷题笔记 - 图4

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return false;
        }
        boolean found = false;
        int cows = matrix.length;
        int columns  =  matrix[0].length;

        int cow = 0;
        int column = columns-1;
        while(cow<cows&&column>=0){
            if(matrix[cow][column] == target){
                found = true;
                break;
            } 
            else if(matrix[cow][column]<target){
                ++cow ;
            }else if(matrix[cow][column]>target){
                --column;
            }

        }

    return found;
    }
}

011-旋转数组的最小数字

剑指offer刷题笔记 - 图5
思路: 二分的方法,假如mid 大于index1的话,说明在后半段。不然就是在前半段,index2 = mid。
两种例外的情况

  1. 是排序好的数组,返回第一个
  2. mid index1 index2 指向的对象是一样的。逐个遍历。 剑指offer刷题笔记 - 图6

    class Solution {
     public int minArray(int[] numbers) {
         if(numbers==null) return -1;
         int index1 = 0;
         int index2 = numbers.length-1;
         while(index2-index1!=1){
             int mid = (index2+index1)/2;
             if(numbers[index1]==numbers[index2]&&numbers[mid]==numbers[index2]){
                 int result = numbers[index1];
                 for(int i=0;i<numbers.length;i++){
                     result = result>numbers[i]?numbers[i]:result;
                 }
                 return result;
             }
             if(numbers[mid]>=numbers[index1]){
                 index1 = mid;
             }else{
                 index2 = mid;
             }
         }
         if(numbers[index2]>=numbers[index1]){
             return numbers[0];
         }
         return numbers[index2];
     }
    }
    

    021-调整数组顺序使奇数位于偶数前面

    剑指offer刷题笔记 - 图7 思路: 使用两个指针,一个在前一个在后。 假如前面的遇到了偶数,后面的遇到了奇数,swap一下。

    2020年3月10日
    class Solution {
     public int[] exchange(int[] nums) {
         if(nums == null || nums.length<1) return nums;
         int head = 0;
         int end = nums.length-1;
         while(head<end){
             while(head<end && (nums[head]&1)!=0){
                 ++head;
             }
             while(head<end && (nums[end]&1)!=1){
                 --end;
             }
             int tmp = nums[head];
             nums[head] = nums[end];
             nums[end] = tmp;
         }
         return nums;
     }
    }
    

    面试题29. 顺时针打印矩阵

    image.png
    算法流程:

  3. 空值处理: 当 matrix 为空时,直接返回空列表 [] 即可。

  4. 初始化: 矩阵 左、右、上、下 四个边界 l , r , t , b ,用于打印的结果列表 res 。
  5. 循环打印: “从左向右、从上向下、从右向左、从下向上” 四个方向循环,每个方向打印中做以下三件事 (各方向的具体信息见下表) ;
    1. 根据边界打印,即将元素按顺序添加至列表 res 尾部;
    2. 边界向内收缩 11 (代表已被打印);
    3. 判断是否打印完毕(边界是否相遇),若打印完毕则跳出。
  6. 返回值: 返回 res 即可。

image.png

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if(matrix.length == 0) return new int[0];
        int left = 0, right = matrix[0].length-1;
        int top = 0, bottom = matrix.length-1;
        int[] res = new int[(bottom+1)*(right+1)];
        int x = 0;
        while (true){
            for(int i=left;i<=right;i++) res[x++] = matrix[left][i];
            if(++top>bottom) break;
            for(int i=top;i<=bottom;i++) res[x++] = matrix[i][right];
            if(--right<left) break;
            for(int i=right;i>=left;i--) res[x++] = matrix[bottom][i];
            if(--bottom<top) break;
            for(int i=bottom;i>=top;i--) res[x++] = matrix[i][left];
            if(++left>right) break;
        }
        return res;

    }
}

链表

006 从尾到头打印链表

剑指offer刷题笔记 - 图10 思路:从头到尾打印说明是先进后出,可以使用一个栈的结构来辅助。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] reversePrint(ListNode head) {
        Stack<ListNode> stack = new Stack<>();
        if(head == null) return new int[0];
        while(head!=null){
            stack.push(head);
            head = head.next;
        }
        int count = stack.size();
        int[] result = new int[count];
        for(int i=0;i<count;i++){
            result[i] = stack.pop().val;
        }
        return result;

    }
}

018-删除链表的节点

剑指offer刷题笔记 - 图11
思路: 使用双指针,处理一下,第一个是target的情况。cur指向head,pre指向null。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        if(head == null) return null;
        ListNode cur = head;
        ListNode pre = null;
        if(head.val == val){
            return head.next;
        }
        while(cur.val!=val){
            pre = cur;
            cur = cur.next;

        } 
        pre.next = cur.next;
        return head;
    }
}

022 链表中倒数第k个节点

剑指offer刷题笔记 - 图12剑指offer刷题笔记 - 图13 思路: 使用双指针,前面的指针先走k-1步,之后p1 = head。注意,k==0,和head ==null 的情况。
还要注意k可能取不到,要在for里面做一个判断。
版本1:

/*
public class ListNode {
    int val;
    ListNode next = null;
    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {

        ListNode fast = head;
        ListNode low = head;
        if(k==0)return null;
        if(head ==null) return null;

        while(k>1){
            fast = fast.next;
            if(fast == null)
                return null;
            k--;
        }
        while(fast.next != null){
            fast = fast.next;
            low = low.next;
        }
        return low;
    }
}

版本2:

/** 2020年3月10日
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        if(k==0|| head ==null) return null;
        ListNode p1;
        ListNode p2 = head;
        for(int i=0;i<k-1;i++){
            if(p2.next != null){
                p2 = p2.next;
            }else{
                return null;
            }
        }
        p1 = head;
        while(p2.next!=null){
            p2 = p2.next;
            p1 = p1.next;
        }
        return p1;
    }
}

023 链表中环的入口节点

剑指offer刷题笔记 - 图14
思路: 在倒数k个元素有点像,是这个的前步骤。 剑指offer刷题笔记 - 图15

/*
 public class ListNode {
    int val;
    ListNode next = null;
    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {    
        if(pHead ==null || pHead.next == null) return null;
        ListNode fast = pHead.next;
        ListNode low = pHead;

        while(fast != low){
            if(fast == null || fast.next == null){
                return null;
            }
            fast = fast.next.next;
            low = low.next;
        }
        ListNode meeting = fast;
        int count = 1;
        low = low.next;
        while(meeting != low){
            low = low.next;
            count++;
        }

        fast = pHead;
        low = pHead;
        while(count>0){
            fast = fast.next;
            count--;
        }
        while(fast!=low){
            fast = fast.next;
            low = low.next;
        }
        return low;



    }
}

024 反转链表

剑指offer刷题笔记 - 图16 容易出错的点

  1. 输入的链表头指针为null 或者只有一个节点。
  2. 链表出现断裂
  3. 返回之后的头节点不是尾节点

在提交以前,早点准备测试用例。

  • 链表只有一个,两个,多个。
  • 链表为空

    /**
    * Definition for singly-linked list.
    * public class ListNode {
    *     int val;
    *     ListNode next;
    *     ListNode(int x) { val = x; }
    * }
    */
    class Solution {
      public ListNode reverseList(ListNode head) {
          ListNode prev = null;
          ListNode node = head;
          ListNode reverseHead = null;
          while(node != null){
              ListNode p_next = node.next;
              if(p_next ==null) reverseHead = node;
              node.next = prev;
              prev = node;
              node = p_next;
          }
          return reverseHead;
    
      }
    }
    

    思路2: 使用两个指针,pre指向head,cur指向null。 开始的时候我们先获得pre的next,将pre的next指向cur,cur=pre,pre = next
    最后pre.next = cur 返回这个结果。

    /**
    * Definition for singly-linked list.
    * public class ListNode {
    *     int val;
    *     ListNode next;
    *     ListNode(int x) { val = x; }
    * }
    */
    class Solution {
      public ListNode reverseList(ListNode head) {
          if(head ==null) return null;
          ListNode cur = null;
          ListNode pre = head;
          ListNode reverseHead = null;
          while(pre.next!=null){
              ListNode next = pre.next;
              pre.next = cur;
              cur = pre;
              pre = next;
          }
          pre.next = cur;
          reverseHead = pre;
          return reverseHead;
      }
    }
    

    025-合并两个有序的链表

    剑指offer刷题笔记 - 图17
    思路 使用一个哨兵节点,如果l1大于l2,将ret的下一个指向l2,l2向后挪一位。ret也向后挪一位。最后剩余的东西判断一下,接上去就可以了。

    /**
    * Definition for singly-linked list.
    * public class ListNode {
    *     int val;
    *     ListNode next;
    *     ListNode(int x) { val = x; }
    * }
    */
    class Solution {
      public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
          ListNode flag = new ListNode(1);
          ListNode ret = flag;
          ListNode p1 = l1;
          ListNode p2 = l2;
          if(l1==null) return l2;
          if(l2 == null) return l1;
          while(l1!=null && l2!=null){
              if(l1.val>l2.val){
                  ret.next = l2;
                  l2 = l2.next;
                  ret = ret.next;
              }else{
                  ret.next = l1;
                  l1 = l1.next;
                  ret = ret.next;
              }
          }
          ret.next = l1==null?l2:l1;
          return flag.next;
    
      }
    }
    

    栈,队列

    09-用两个栈实现队列

    剑指offer刷题笔记 - 图18
    思路: stack1 只放进去, pop方法时,假如stack2中有东西,pop,没有的话吧stack1 的倒到stack2中去。再pop一下。

    class CQueue {
      Stack<Integer> stack1;
      Stack<Integer> stack2;
      public CQueue() {
          stack1 = new Stack<>();
          stack2 = new Stack<>();
      }
    
      public void appendTail(int value) {
          stack1.push(value);
      }
    
      public int deleteHead() {
          if(stack1.empty()&& stack2.empty()){
              return -1;
          }
          if(stack2.empty()){
              putsome();
    
          }
          return stack2.pop();
      }
      private void putsome(){
          if(stack2.empty()){
              while(!stack1.empty()){
                  stack2.push(stack1.pop());
              }
          }
      }
    }
    /**
    * Your CQueue object will be instantiated and called as such:
    * CQueue obj = new CQueue();
    * obj.appendTail(value);
    * int param_2 = obj.deleteHead();
    */
    

    面试题31. 栈的压入、弹出序列

模拟一下这个操作。 我们首先向栈里面加入push的值,并且开始做判断,栈顶的元素是不是和pop的第一个元素相同,如果相同的话,那就popindex++ 而且push栈弹出,继续进行一个对比。所以这里我们是使用while来做这个循环。

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        int m = pushed.length;
        int n = popped.length;

        Stack<Integer> stack = new Stack<>();
        int j=0;
        for(int i=0;i<m;i++){
            stack.push(pushed[i]);

            while (!stack.isEmpty()&& j<n&& stack.peek() == popped[j]){
                stack.pop();
                j++;
            }
        }
        return stack.isEmpty();

    }
}

07-重建二叉树

剑指offer刷题笔记 - 图19
思路: https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/mian-shi-ti-07-zhong-jian-er-cha-shu-di-gui-fa-qin/
根据前序遍历可以确定根的数值,中序遍历可以确定下标。获得左右的位置之后,递归进行。 剑指offer刷题笔记 - 图20

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    HashMap<Integer,Integer> dic = new HashMap<>();
    int po[];
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        po = preorder;
        for(int i=0;i<preorder.length;i++){
            dic.put(inorder[i],i);
        }
        return recur(0,0,inorder.length-1);
    }
    TreeNode recur(int pre_root,int in_left,int in_right){
        if(in_left>in_right) return null;
        TreeNode root = new TreeNode(po[pre_root]);
        int i = dic.get(po[pre_root]);
        root.left = recur(pre_root+1,in_left,i-1);
        root.right = recur(pre_root+i-in_left+1, i+1, in_right);
        return root;
    }
}

08-二叉树的下一个节点

剑指offer刷题笔记 - 图21
思路:有两种情况

  1. 节点有右子树, 下一个节点就是右子树的最左节点 例如b》h
  2. 节点无右子树
    1. 是父节点的左节点 d-b
    2. 是父节点的右节点 i-a。向上找节点,找到一个父节点是他父节点的左节点为止

剑指offer刷题笔记 - 图22

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;
    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        if(pNode == null)return null;
        TreeLinkNode pNext = null;
        if(pNode.right != null){
            TreeLinkNode pRight = pNode.right;
            while(pRight.left != null){
                pRight = pRight.left;
            }
            pNext = pRight;
        }else if(pNode.next != null){
            TreeLinkNode cur = pNode;
            TreeLinkNode par = pNode.next;

            while(par!= null&&cur == par.right){
                cur  = par;
                par = par.next;
            }
            pNext = par;
        }
        return pNext;
    }
}

026-树的子结构

剑指offer刷题笔记 - 图23
思路: 首先需要需要找到根节点一致的地方。找到之后开始判断是不是同一个结构。
如何找根节点一致?
其实是将A的节点和B不断进行对比,看看又没有重合。 找到之后判断一下是不是子结构。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSubStructure(TreeNode A, TreeNode B) {
        boolean res = false;
        if(A!=null && B!=null){
            if(A.val == B.val){
                res = doesTreeHavaTree2(A,B);// 假如一致的话,判断是不是子结构
            }
            if(!res){
                res = isSubStructure(A.left,B);// 递归判断左右子树。
            }
            if(!res){
                res = isSubStructure(A.right,B);
            }
        }
        return res;
    }
    private boolean doesTreeHavaTree2(TreeNode a,TreeNode b){
        if(b ==null) return true; // 假如b 遍历完了,说明数据匹配
        if(a ==null) return false;// a先空了,说明不匹配
        if(a.val !=b.val) return false;//数值不对,返回false
        return doesTreeHavaTree2(a.left,b.left)&&doesTreeHavaTree2(a.right,b.right);//一定要左右子树都一样
    }
}

027-二叉树的镜像

剑指offer刷题笔记 - 图24
思路: 交换节点的左右节点,递归下去他的左节点和右节点。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root == null) return null;
        if(root.left == null&& root.right ==null) return root;
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        if(root.right!= null){
            mirrorTree(root.right);
        }
        if(root.left != null){
            mirrorTree(root.left);
        }
        return root;
    }
}

面试题28. 对称的二叉树

思路: 使用递归的方法来进行一个对比。 可以定义一个根-后-前的遍历方法来进行一个对比。

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return isSymmetric(root,root);

    }
    private boolean isSymmetric(TreeNode root1, TreeNode root2){
        if(root1==null&&root2==null){
            return true;
        }else if(root1==null||root2==null){
            return false;
        }else if(root1.val!=root2.val){
            return false;
        }

        return isSymmetric(root1.left,root2.right)&&isSymmetric(root1.right,root2.left);
    }
}

面试题32 - I. 从上到下打印二叉树

其实这道题就是一个层序的遍历,看到这样的题目第一个想到的就是队列这种数据结构。或者说是BFS吧,借助一个队列,首先把里面的root放到里面去。每次把他的左右孩子再放进去。

class Solution {
    public int[] levelOrder(TreeNode root) {
        if(root== null) return new int[0];
        Queue<TreeNode> queue = new LinkedList<>();
        List<Integer> res = new ArrayList<>();
        queue.add(root);

        while (!queue.isEmpty()){
            TreeNode tmp = queue.poll();
            res.add(tmp.val);
            if(tmp.left!=null){
                queue.add(tmp.left);
            }
            if(tmp.right!=null){
                queue.add(tmp.right);
            }
        }
        int[] ans = new int[res.size()];
        for(int i=0;i<res.size();i++){
            ans[i] = res.get(i);
        }
        return ans;


    }
}

面试题32 - II. 从上到下打印二叉树 II

这道题和原来的那道题有一点像。需要改的是,这次是一层放一个list里面。再放入一个大的list中。
所以我们再每次的循环的时候,建立一个list,每次遍历一下队列里面的数据,放到里面。

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root==null) return new ArrayList<>();

        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        queue.add(root);

        while (!queue.isEmpty()){
                ArrayList<Integer> node = new ArrayList<>();
                for(int i=queue.size();i>0;i--){
                    TreeNode tmp = queue.poll();
                    node.add(tmp.val);
                    if(tmp.left!=null){
                        queue.add(tmp.left);
                    }
                    if(tmp.right!=null){
                        queue.add(tmp.right);
                    }

                }
            res.add(node);
        }
        return res;

    }
}

面试题32 - III. 从上到下打印二叉树 III

这个就是需要根据层数,奇偶性遍历,奇数是前往后,偶数是后往前来计算。所以我们需要一个标识符来记录一下是基础还是偶数。如何倒着打印呢?可以使用双向队列的一个方法,每一次都把元素插入到最前面。

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root==null) return new ArrayList<>();

        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        queue.add(root);
        boolean flag= true;

        while (!queue.isEmpty()){
                ArrayList<Integer> node = new ArrayList<>();
                for(int i=queue.size();i>0;i--){
                    TreeNode tmp = queue.poll();
                    if(flag) node.add(tmp.val);
                    else node.add(0,tmp.val);

                    if(tmp.left!=null){
                        queue.add(tmp.left);
                    }
                    if(tmp.right!=null){
                        queue.add(tmp.right);
                    }

                }
            flag=!flag;
            res.add(node);
        }
        return res;

    }
}

面试题33. 二叉搜索树的后序遍历序列

image.png
主要就是要吧数组分成好几部分,左子树,右子树,根节点。对其中的数做一个比较。以及递归的终止条件是啥需要搞清楚。

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        if(postorder.length<1|| postorder== null) return true;
         return recur(postorder,0,postorder.length-1);
    }
    private boolean recur(int[] postorder,int i,int j){
        if(i>=j)return true;

        int p = i;
        while (postorder[p]<postorder[j])p++;

        int m = p;

        while (postorder[m]>postorder[j])m++;
        return m==j&&recur(postorder,i,p-1)&&recur(postorder,p,j-1);
    } 
}

回溯

012-矩阵中的路径(未做)

013-机器人的运动路径(未做)

动态规划

014-1-剪绳子

剑指offer刷题笔记 - 图26 思路: 动态规划的四个特点

  1. 问题能够分解成多了子问题
  2. 整体依赖局部最优解
  3. 小问题之间有重叠
  4. 从上到下分析问题

从下往上解决这个问题。先算出n=3的,把之前的最优解都存储到一个数组里面。不断增加n的数值。最后得到结果。

class Solution {
    public int cuttingRope(int n) {
        if(n <2)return 0;
        else if(n==2)return 1;
        else if(n==3)return 2;
        int[] res = new int[n+1];
        res[0] = 0;
        res[1] = 1;
        res[2] = 2;
        res[3] = 3;
        int max = 0;
        for(int i=4;i<=n;++i){
            max=0;
            for(int j=1;j<=i/2;++j){
                int rope = res[j]*res[i-j];
                if(max<rope){
                    max = rope;
                }
                res[i] = max;
            }
        }
        return res[n];
    }
}

贪心

014-2-剪绳子

剑指offer刷题笔记 - 图27 将可能多的剪3的绳子,去幂的话,诗快速幂来进行加速。

class Solution {
    public int cuttingRope(int n) {
        if(n<2)return 0;
        else if(n==2)return 1;
        else if(n==3) return 2;
        int p = 1000000007;
        int timeOf3 = n/3;
        if(n%3 ==1){
            timeOf3-=1;
        }
        int timeOf2 = (n-timeOf3*3)/2;
        long ans =1;
        long a = 3;
        while(timeOf3!=0){     
            if(timeOf3%2==1){
                ans = (ans*a)%p;
            }
            timeOf3/=2;
            a = (a*a)%p;
        }
        if(timeOf2 ==0)return (int)ans;
        else if(timeOf2 ==1) return (int) (ans*2%p);
        else  return (int)(ans*4%p) ;
    }
}

滑动窗口

位运算

015-二进制中1的个数

剑指offer刷题笔记 - 图28
思路:

  1. 用1来按位与过去,每一次都将1左移一位。
  2. 将n-1和n进行与运算。每次可以去掉一个二进制中的1。这个思路挺有用的。

    public class Solution {
     // you need to treat n as an unsigned value
     public int hammingWeight(int n) {
         int count =0;
         while(n!=0){
             ++count;
             n = (n-1)&n;
         }
         return count;
    
     }
    }
    

    其他

    10-1 斐波那契数列

    剑指offer刷题笔记 - 图29 思路: 从底而上,一个一个加过来。

    class Solution {
     public int fib(int n) {
         int[] res = new int[]{0,1};
         if(n<2) return res[n];
         int fibMinusOne = 1;
         int fibMinusTwo = 0;
         int fibN = 0;
         for(int i=2;i<=n;i++){
             fibN = (fibMinusOne+fibMinusTwo)% 1000000007;
             fibMinusTwo = fibMinusOne;
             fibMinusOne = fibN;
         }
         return fibN;
    
     }
    }
    

    10-2青蛙跳台阶问题

    剑指offer刷题笔记 - 图30
    思路: 分解问题 f(n) = f(n-1)+f(n-2)
    f(1) = 1
    f(2) = 2 其实就是斐波那契数列

    class Solution {
     public int numWays(int n) {
         int[] res = new int[]{1,1,2};
         if(n<3)return res[n];
         int a = 1;
         int b = 2;
         int sum = 0;
         for(int i=2;i<n;i++){
             sum = (a+b)%1000000007;
             a = b;
             b = sum;
         }
         return sum;
     }
    }
    

    016-数值的整数次方

    剑指offer刷题笔记 - 图31 思路:
    需要注意 0的时候底数是负数的情况。需要作处理。
    指数为负数的时候,需要取绝对值。将x = 1/x 。int的最小值为[−2147483648,2147483647] 所以需要一个long才能将最小值转换为正数。 ``` class Solution { boolean vaildInput = false; public double myPow(double x, int n) {

     if(x==0.0&& x<0){
         vaildInput = true;
         return 0.0;
     }
     long exp = n;
     if(n<0) {
         exp = -exp;
         x = 1/x;
     }
     double res=1.0;
     while(exp>0){
    
         if((exp&1) == 1){
             res*=x;
         }
         x *=x;
         exp>>=1;
     }       
    return res;
    

    }

}

<a name="ot1qM"></a>
### 017-打印从1到最大的n位数
![](https://note.youdao.com/yws/public/resource/114897fc63291a00ddcb2ae4b78f86cd/BA131688EA304B9497C82ABABF5D0C46?ynotemdtimestamp=1586700368188#crop=0&crop=0&crop=1&crop=1&height=406&id=sNpBC&originHeight=406&originWidth=481&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=481) 思路:<br />使用快速幂,来获取最大值数值。建立一个数组,遍历完里面塞东西。

class Solution { public int[] printNumbers(int n) { int len =1; int base = 10; while(n>0){ if((n&1)==1){ len = base; } base =base; n>>=1; } int[] res = new int[len-1]; for(int i=0;i<res.length;++i){ res[i] = i+1; } return res; } } ```