劍指OFFER-JAVA題解總結-更新中

 

 原文個人博客地址

https://www.b2bchain.cn/5154.html

面試題03. 數組中重複的數字

class Solution {
    public int findRepeatNumber(int[] nums) {
         Set<Integer> set=new HashSet<>();
        for(int num:nums){
            if(!set.add(num)){
                  return num;
            }
        }
        return -1;
    }
}

 

面試題04. 二維數組中的查找

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        int i = matrix.length - 1, j = 0;
        while(i >= 0 && j < matrix[0].length)
        {
            if(matrix[i][j] > target) i--;
            else if(matrix[i][j] < target) j++;
            else return true;
        }
        return false;
    }
}

 

面試題05. 替換空格

class Solution {
    public String replaceSpace(String s) {
        StringBuilder  res=new StringBuilder ();
        for(Character c : s.toCharArray()){
              if(c==' '){
                  //加引號
                 res.append("%20");
              }
              else{
                  res.append(c);
              }
        }  
        return res.toString();
    }
}

 

 

面試題06. 從尾到頭打印鏈表

返回爲數組,直接用棧模擬即可

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] reversePrint(ListNode head) {
        //使用LinkedList 替代stack 性能好
        LinkedList<Integer> stack=new LinkedList<Integer>();

 
       while(head != null) {
            stack.addLast(head.val);
            head = head.next;
        }
        int[] res = new int[stack.size()];
        for(int i = 0; i < res.length; i++){
             res[i] = stack.removeLast();
        }

 
         return res;
    }
}

 

 

面試題07. 重建二叉樹

 

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    //key-value 中序 值-序號
    HashMap<Integer, Integer> dic = new HashMap<>();
    int[] po;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        po = preorder;
        for(int i = 0; i < inorder.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;
    }
}

 

 

面試題09. 用兩個棧實現隊列

 

class CQueue {

 
    LinkedList<Integer> A, B;

 
    public CQueue() {
        A = new LinkedList<Integer>();
        B = new LinkedList<Integer>();
    }

 
    public void appendTail(int value) {
        A.addLast(value);
    }

 
    public int deleteHead() {
        if(!B.isEmpty()) return B.removeLast();
        //空 
        if(A.isEmpty()) return -1;
        while(!A.isEmpty()){
             B.addLast(A.removeLast());
        }
        //最後B出棧    
        return B.removeLast();
    }
}

 
/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue obj = new CQueue();
 * obj.appendTail(value);
 * int param_2 = obj.deleteHead();
 */

 

 

面試題10- I. 斐波那契數列

class Solution {
    public int fib(int n) {

 
       if(n==0) return 0;
       int[] dp=new int[n+1];

 
       dp[1]=1;
       //dp[i]是i不是n
       for(int i=2;i<=n;i++){
        dp[i]=(dp[i-1]+dp[i-2])%1000000007;
       }
       return dp[n];
    }
}

 

 

面試題10- II. 青蛙跳臺階問題

 

class Solution {
    public int numWays(int n) {
        //特例
         if(n==0) return 1;
         //構建DP數組
         int[] dp=new int[n+1];
         //賦值幾個初始的值
        dp[0]=1; dp[1]=1;
        //遞歸循環
         for(int i=2;i<=n;i++){
             //每一步都需要取餘
          dp[i]=(dp[i-1]+dp[i-2])%1000000007;
         }
         return dp[n];
    }
}

 

 

面試題11. 旋轉數組的最小數字

 

和numbers數組最後一個數字比較 numbers[mid]==numbers[j]時候,需要J-- 縮小範圍

class Solution {
    public int minArray(int[] numbers) {

 
         int i=0;
         int j=numbers.length-1;
         while(i<j){
             int m=(i+j)/2;
              if(numbers[m]<numbers[j]){
                   j=m;
              }
              else if(numbers[m]>numbers[j]){
                    i=m+1;
              }
              else{
                  j--;
              }
         }
         return numbers[i];
    }
}

 

面試題12. 矩陣中的路徑

 

//DFS搜索

class Solution {
    public boolean exist(char[][] board, String word) {
       char[] words=word.toCharArray();
       //嘗試矩陣的全部點作爲出發點入口
       for(int i=0;i<board.length;i++){
           for(int j=0;j<board[0].length;j++){
               //有滿足條件返回TRUE
               if(dfs(board,words,i,j,0)) return true;
           }
       }
       return false;
    }
    private boolean dfs(char[][] board,char[] words,int i,int j,int k){
        // board[i][j] != words[k] 當前遍歷點與 目標值不相等
        if(i<0||i>=board.length||j<0||j>=board[0].length|| board[i][j] != words[k]){
            return false;
        }
        //遍歷到結尾了 成功
         if(k == words.length - 1) return true;

 
         //處理當前元素
        char tmp=board[i][j];
        //防止重複遍歷
        board[i][j]='/';
        //相當於k是一個索引判斷遍歷到了word的哪一位,相當於遍歷的層數
        boolean res = dfs(board, words, i + 1, j, k + 1) || dfs(board, words, i - 1, j, k + 1) || 
                      dfs(board, words, i, j + 1, k + 1) || dfs(board, words, i , j - 1, k + 1);
        board[i][j] = tmp;
        return res;
    }
}

 

 

面試題13. 機器人的運動範圍

 

方法一:DFS通用

class Solution {
    int ans=0;
    public int movingCount(int m, int n, int k) {
        //是否訪問
      boolean[][] used=new boolean[m][n];
      dfs(m,n,k,0,0,used);
      return ans;
    }

 
    //i,j爲當前訪問的座標
    private  void dfs(int m,int n,int k,int i,int j,boolean[][] used){

 
        //dfs先需要寫遞歸結束條件
        if(i>m-1 || j>n-1  || digitSum(i)+digitSum(j)>k || used[i][j]==true)  return;

 
            used[i][j] = true;
            ans++;
            //只向下和右遍歷即可
            dfs(m, n, k, i + 1, j, used);
            dfs(m, n, k, i, j + 1, used);
    }

 
    //求數位和
    private int digitSum(int num){
        int sum=0;
        while(num>0){
            sum+=num%10;
            num/=10;
        }
        return sum;
    }
} 

方法二:數學公式推導

class Solution {
    //全局變量的使用
        int m,n,k;
        boolean[][] visited;

 
    public int movingCount(int m, int n, int k) {
       this.m=m; this.n=n;this.k=k;
       this.visited=new boolean[m][n];

 
       return dfs(0,0,0,0);
    }
    //i,j 座標  si sj 數位和
    private int dfs(int i,int j,int si,int sj){
        if(i>=m||j>=n||k<si+sj|| visited[i][j]){
         return 0;
        }

 
        visited[i][j]=true;
        return 1+dfs(i+1,j,(i+1)%10==0?si-8:si+1,sj)+dfs(i,j+1,si,(j+1)%10==0?sj-8:sj+1);
    }
}

 

 

面試題14- I. 剪繩子

小數據DP問題 從最後剪得情況來反推

class Solution {
    public int cuttingRope(int n) {
        //DP算法
        //當繩子長度n>3時,最後一段繩子長度只有2,3兩種情況(證明參考高贊精選貼),因此:
         //dp[i] = max { 2 * dp[i-2], 3 * dp[i-3] }

 
       //推到得出
        if(n<=3) return n-1;
        int[] dp = new int[n+1];
        dp[2] = 2; dp[3] = 3;
        for(int i = 4; i <= n; i++){
            dp[i] = Math.max(2 * dp[i-2] , 3 * dp[i-3]) ;
        }
        return dp[n];

 
    }
}

 

面試題14- II. 剪繩子 II

大數貪心

class Solution {
    public int cuttingRope(int n) {
         //大數貪心 特殊情況2,3,4 
         if(n==2) return 1;//題目要求必須至少切一刀
         if(n==3) return 2;
         //定義long 防止溢出 大數用long
         long res=1;
         //儘可能取3結果最大,n爲繩子長度,每次結果乘3取餘,總長度對應減去3
         while(n>4){
              res*=3;
              res=res%1000000007;
              n-=3;
         }
         //乘上剩下繩子的長度
         return (int) (res*n%1000000007);
    } 
}

 

 

面試題15. 二進制中1的個數

方法一:不改變原數字

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int ans=0;
        int mask=1;

 
        for (int i = 0; i <32 ; i++) {
            //此時爲不等於0
            if((n & mask)!=0) ans++;
            //考慮到不改變原數字,移動掩碼
            mask<<=1;
        }
        return ans;
    }
}

 

 

方法二:

>>將二進制高位用1補上,而>>>將二進制高位用0補上,這就導致了>>>將負數的移位操作結果變成了正數,因爲高位用0補上了

 public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        //輸入二進制數
        //根據 與運算 定義,設二進制數字 nn ,則有:
//若 n  & 1 == 0 ,則二進制 最右一位 爲 0 ;
//若 n  & 1 == 1 ,則二進制 最右一位 爲 1 。
        int res=0;
        while(n!=0){
            res+=n&1;
            //右移JAVA》》》 記得是>>> 
            n>>>=1;
        }
        return res;
    }
}

 

 

面試題16. 數值的整數次方

 

快速冪

把指數 n 做“二進制分解”,在底數不斷自身乘以自身的過程中,將最終結果需要的部分保存下來。

class Solution {
    public double myPow(double x, int n) {
         //特殊情況
         if(x==0) return 0;
         long b=n;
         //指數爲負數
         if(b<0){
             x=1/x;
             b=-b;
         }
         double res=1.0;
         while(b>0){
             //當前位爲1,累乘到結果上
            if(b%2==1){
                res*=x;
            }
            //相當於每次底數
            x*=x;
            b=b/2;
         }
         return res;
    }
}

 

面試題17. 打印從1到最大的n位數

快速冪同16題,相當於用快速冪求需要打印的總數目

class Solution {
    private int mypow(int x,int k){
       if(x==0) return 0;
       int res=1;
       long b=k;
       while(b>0){
           if(b%2==1) res*=x;

 
           x*=x;
           b/=2;
       }
       return res;
    }
    public int[] printNumbers(int n) {
        int len=mypow(10,n);
         int[] ans=new int[len-1];
         for(int i=0;i<len-1;i++){
            ans[i]=i+1;
         }
         return ans;
    }

 
}

 

面試題18. 刪除鏈表的節點

方法一:單個指針操作

class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        //不加這句,這個地方會出空指針異常
      if(head.val==val) return head.next;
      ListNode dummy=head;
      while(head.next!=null && head.next.val!=val){
          head=head.next;
      } 
      head.next=head.next.next;
      return dummy;
    }
}

 

方法二:倆個指針操作

/**
 * 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) {
        //刪除節點爲開始節點,指向head.next而不是null
        //這個判斷有點坑的呀
        if(head.val==val) return head.next;
        ListNode cur=head;
        ListNode pre=head.next;
        while(pre!=null && pre.val!=val){
         pre=pre.next;
         cur=cur.next;
        }
        cur.next=pre.next;
        return head;
    }
}

 

 

面試題19. 正則表達式匹配

 

https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof/solution/zhu-xing-xiang-xi-jiang-jie-you-qian-ru-shen-by-je/

class Solution {
    public boolean isMatch(String s, String p) {
       int n=s.length();
       int m=p.length();

 
       boolean [][] ans=new boolean[n+1][m+1];
       for(int i=0;i<=n;i++){
          for(int j=0;j<=m;j++){
              //空正則
               if(j==0){
                     ans[i][j]= i==0;
               }else{
                   //不等 *
                   if(p.charAt(j-1)!='*'){
                       if(i>0&&(s.charAt(i-1)==p.charAt(j-1) || p.charAt(j-1)=='.')){
                           ans[i][j]=ans[i-1][j-1];
                       }
                   }else{
                       // * 對應爲0個  例如把c* 跳過,因此爲j-2
                       if(j>=2){
                          ans[i][j]|=ans[i][j-2];
                       }
                       //*爲 一個或多個
                       if(i>=1&&j>=2&&(s.charAt(i-1)==p.charAt(j-2) || p.charAt(j-2)=='.')){
                           ans[i][j] |=ans[i-1][j];
                       }
                   }

 
               }
          }

 
       }
       return ans[n][m];
    }
}

 

 

劍指 Offer 20. 表示數值的字符串

https://leetcode-cn.com/problems/valid-number/solution/java-luo-ji-chao-qing-xi-jie-fa-by-charlesgao/

class Solution {
    public boolean isNumber(String s) {
        if(s==null||s.length()==0) return false;
        boolean numSeen=false;
        boolean dotSeen=false;
        boolean eSeen=false;
        char arr[]=s.trim().toCharArray();
        for(int i=0; i<arr.length; i++){
            if(arr[i]>='0'&&arr[i]<='9'){
                numSeen=true;
            }else if(arr[i]=='.'){
                if(dotSeen||eSeen){
                    return false;
                }
                dotSeen=true;
            }else if(arr[i]=='E'||arr[i]=='e'){
                if(eSeen||!numSeen){
                    return false;
                }
                eSeen=true;
                numSeen=false;
            }else if(arr[i]=='+'||arr[i]=='-'){
                if(i!=0&&arr[i-1]!='e'&&arr[i-1]!='E'){
                    return false;
                }
            }else{
                return false;
            }
        }
        return numSeen;
    }
}

 

 

面試題21. 調整數組順序使奇數位於偶數前面

class Solution {
    public int[] exchange(int[] nums) {
       int i=0,j=nums.length-1,tmp;
       while(i<j){
          //找到偶數,跳出循環
          while(i<j && (nums[i]&1)==1) i++;
          //找到奇數,跳出循環
          while(i<j && (nums[j]&1)==0) j--;
          //交換
          tmp=nums[i];
          nums[i]=nums[j];
          nums[j]=tmp;
       }
       return nums;
    }
}

 

 

面試題22. 鏈表中倒數第k個節點

/**
 * 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) {
          ListNode fast=head;
          ListNode slow=head;
          for(int i=0;i<k;i++){
            //防止空指針
            if(fast==null) return null;
            fast=fast.next;   
          }
          //防止空指針,此時必須爲fast
          while(fast!=null){
            fast=fast.next;
            slow=slow.next;
          }
           return slow;
    }
}

 

 

面試題24. 反轉鏈表

/**
 * 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 cur=null;
        ListNode pre=head;
        while(pre!=null){
            ListNode t=pre.next;
            pre.next=cur;
            cur=pre;
            pre=t;
        }
        return cur;
    }
}

 

 

面試題25. 合併兩個排序的鏈表

/**
 * 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 dummy=new ListNode(-1);
         ListNode cur=dummy;

 
         while(l1!=null&&l2!=null){
            if(l1.val<l2.val){
              cur.next=l1;
              l1=l1.next;
            }
            else{
                cur.next=l2;
                l2=l2.next;
            }
            cur=cur.next;
         }
         cur.next= l1!=null?l1 :l2;
         return dummy.next;
    }
}

 

面試題26. 樹的子結構

/**
 * 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) {
        //倆樹均不爲空  A根節點樹包含B 或者 A左包含B 或者A右包含B 
          return (A != null && B != null) && (recur(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B));

 
    }
    //判斷樹A爲根節點的樹 包含樹B
    private boolean recur(TreeNode A,TreeNode B){
          if(B==null) return true;
          if(A==null||A.val!=B.val) return false;
          return recur(A.left,B.left) &&recur(A.right,B.right);
    }
}

 

面試題27. 二叉樹的鏡像

遞歸

/**
 * 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;
         TreeNode tmp=root.left;
         root.left=mirrorTree(root.right);
         root.right=mirrorTree(tmp);
         return root;
    }
}

非遞歸

/**
 * 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;
         Stack<TreeNode> stack=new Stack<>();
         stack.add(root);
         while(!stack.isEmpty()) {
            TreeNode node = stack.pop();
            if(node.left != null) stack.add(node.left);
            if(node.right != null) stack.add(node.right);
            TreeNode tmp = node.left;
            node.left = node.right;
            node.right = tmp;
        }
        return root;
    }
}

 

面試題28. 對稱的二叉樹

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
          if(root==null) return true;
          return helper(root.left,root.right);
    }
    private boolean helper(TreeNode left,TreeNode right){
        if(left==null&&right==null){
            return true;
        }
        if(left==null||right==null||left.val!=right.val){
            return false;
        }
        return helper(left.left,right.right) && helper(left.right,right.left);
    }
}

面試題29. 順時針打印矩陣

 

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        //特殊條件
        if(matrix.length == 0) return new int[0];

 
        int l=0, r=matrix[0].length-1, t=0, b=matrix.length-1, x=0;

 
        //返回一維數組
        int[] res=new int[(r + 1) * (b + 1)];
        while(true){
            //開始i=l
             for(int i=l;i<=r;i++) res[x++]=matrix[t][i];
             if(++t>b) break;
             for(int i=t;i<=b;i++) res[x++]=matrix[i][r];
             if(l>--r) break;
             for(int i=r;i>=l;i--) res[x++]=matrix[b][i];
             if(t>--b) break;
             for(int i=b;i>=t;i--) res[x++]=matrix[i][l];
             if(++l>r) break;

 
        }
        return res;
    }
}

 

 

面試題30. 包含min函數的棧

函數設計:
push(x) 函數: 重點爲保持棧 B 的元素是 非嚴格降序 的。
將 x 壓入棧 A (即 A.add(x) );
若 ① 棧 B 爲空 或 ② x 小於等於 棧 B 的棧頂元素,則將 x 壓入棧 B (即 B.add(x) )。
pop() 函數: 重點爲保持棧 A,B 的 元素一致性 。
執行棧 A 出棧(即 A.pop() ),將出棧元素記爲 y ;
若 y 等於棧 B 的棧頂元素,則執行棧 B 出棧(即 B.pop() )。
top() 函數: 直接返回棧 A 的棧頂元素即可,即返回 A.peek() 。
min() 函數: 直接返回棧 B 的棧頂元素即可,即返回 B.peek() 。
class MinStack {
    Stack<Integer> A;
    Stack<Integer> B;
    /** initialize your data structure here. */
    public MinStack() {
       A=new Stack<>();
       B=new Stack<>();
    }

 
    public void push(int x) {
        A.add(x);
        //b爲空或者..大於-等於--
        if(B.empty() ||x<=B.peek()) B.add(x);
    }

 
    public void pop() {
        if(A.pop().equals(B.peek())) B.pop();

 

 
    }

 
    public int top() {
       return A.peek();
    }

 
    public int min() {
         return B.peek();
    }
}

 
/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.min();
 */

 

 

面試題31. 棧的壓入、彈出序列

stack存pushed

當stack不爲空且棧頂等於poped時候

stack出棧

最後判斷是否棧空

考慮借用一個輔助棧 stackstack ,模擬 壓入 / 彈出操作的排列。
根據是否模擬成功,即可得到結果。

 
入棧操作: 按照壓棧序列的順序執行。
出棧操作: 每次入棧後,循環判斷 “棧頂元素 == 彈出序列的當前元素” 是否成立,
           將符合彈出序列順序的棧頂元素全部彈出。

 
由於題目規定 棧的所有數字均不相等 ,
因此在循環入棧中,
每個元素出棧的位置的可能性是唯一的(
若有重複數字,則具有多個可出棧的位置)。
因而,在遇到 “棧頂元素 == 彈出序列的當前元素” 就應立即執行出棧。

 
算法流程:
初始化: 輔助棧 stackstack ,彈出序列的索引 ii ;
遍歷壓棧序列: 各元素記爲 num ;
元素 num入棧;
循環出棧:若 stack 的棧頂元素 == 彈出序列元素 popped[i] ,則執行出棧與 i++ ;
返回值: 若 stack 爲空,則此彈出序列合法。

 

 

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

 

 

面試題32 - I. 從上到下打印二叉樹

輸出爲一維數組

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] levelOrder(TreeNode root) {
        //特殊條件判斷
       if(root == null) return new int[0]; 
       List<Integer> ans=new ArrayList<>();
        Queue<TreeNode> queue=new LinkedList<>();
       queue.add(root);
       while(!queue.isEmpty()){
           //需要新建一個節點,因爲後面需要左右子樹入棧 操作node不是root
           TreeNode node=queue.poll();
           ans.add(node.val);
           //不爲空纔可以入隊列
           if(node.left != null) queue.add(node.left);
           if(node.right != null)  queue.add(node.right);
       }
       int[] res=new int[ans.size()];
       for(int i=0;i<ans.size();i++){
           //get方法取值
            res[i]=ans.get(i);
       }
       return res;
    }
}

 

 

 

面試題32 - II. 從上到下打印二叉樹 II

輸出二維數組

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
       List<List<Integer>> ans=new ArrayList<>();
       Queue<TreeNode> queue=new LinkedList<>();
       if(root != null) queue.add(root);
       while(!queue.isEmpty()){
           //存放當前層的值
          List<Integer> tmp=new ArrayList<>();
          // 使用i--,讓size()只在循環開始使用一次,使循環次數不受隊列長度變化影響
          for(int i = queue.size(); i > 0; i--){
             TreeNode node=queue.poll();
             tmp.add(node.val);
             if(node.left!=null) queue.add(node.left);
             if(node.right!=null) queue.add(node.right);
          }
         ans.add(tmp);
       }
       return ans;
    }
}

 

 

面試題32 - III. 從上到下打印二叉樹 III

輸出二維數組帶奇偶

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
         List<List<Integer>> ans=new ArrayList<>();
         Queue<TreeNode> queue=new LinkedList<>();
         if(root!=null) queue.add(root);
         while(!queue.isEmpty()){
             //LinkedList
             LinkedList<Integer> tmp=new LinkedList<>();
             for(int i=queue.size();i>0;i--){
                TreeNode node=queue.poll();
                if(ans.size() % 2 == 1) tmp.addFirst(node.val);
                else tmp.addLast(node.val);

 
                if(node.left!=null) queue.add(node.left);
                if(node.right!=null) queue.add(node.right);
             }
             ans.add(tmp);
         }
         return ans;
    }
}

 

面試題33. 二叉搜索樹的後序遍歷序列

 

遞歸 時間複雜度o(n2)

class Solution {
    public boolean verifyPostorder(int[] postorder) {
      return helper(postorder,0, postorder.length - 1);
    }
    private boolean helper(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[p]>postorder[j]) p++;
       //m,j-1 記得去除最後根節點
       return j==p && helper(postorder,i,m-1) && helper(postorder,m,j-1);
    }
}

 

單調棧 o(n)

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        Stack<Integer> stack=new Stack<>();
        int root=Integer.MAX_VALUE;
        for(int i=postorder.length-1;i>=0;i--){
           if(postorder[i]>root) return false;
           //尋找大於且最接近postorder[i]的根節點
           while(!stack.isEmpty()&&stack.peek()>postorder[i]){
                root = stack.pop();
           }
             stack.add(postorder[i]);
        }
      return true;
    }
}

 

面試題34. 二叉樹中和爲某一值的路徑

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    //前面定義 LinkedList
     LinkedList<List<Integer>> ans=new LinkedList<>();
      LinkedList<Integer> path=new LinkedList<>();

 
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
     recur(root,sum);
      return ans;
    }
    private void recur(TreeNode root,int sum){
         if(root==null) return;
         path.add(root.val);
         sum-=root.val;
         if(sum==0 && root.left==null && root.right==null){
             //必須new  相當於複製一個path,防止後面修改影響
             //記錄路徑時若直接執行 res.append(path) ,則是將 path 對象加入了 res ;
             //後續 path 改變時, res 中的 path 對象也會隨之改變。

 
             ans.add(new LinkedList(path));
         }
         //遞歸左右節點
         recur(root.left,sum);
         recur(root.right,sum);
         //向上回溯,刪除當前節點
         path.removeLast();

 
    }
}

 

 

面試題35. 複雜鏈表的複製

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

 
    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
 //不需要輔助空間,需要額外將兩個鏈表進行拆分
    public Node copyRandomList(Node head) {
        if(head==null) return null;
        copy2(head);
        randomAdd2(head);
        return build2(head);
    }
    public void copy2(Node head){
         while(head!=null){
            Node copy = new Node(head.val);
            copy.next = head.next;
            head.next =copy;
            head = copy.next;
        }
    }
    public void randomAdd2(Node head){
        while(head!=null){
           if(head.random!=null) head.next.random = head.random.next;
           head=head.next.next; 
        }
    }
    public Node build2(Node head){
        //將鏈表拆成兩個,注意要恢復原有的鏈表
        Node res = head.next;
        Node tmp = res;
        //這一步不可缺少,保證第一個複製節點對N N'的分離操作
        head.next = head.next.next;
        head = head.next;
        while(head!=null){
            tmp.next = head.next;
            head.next = head.next.next;

 
            tmp=tmp.next;
            head = head.next;
         }
        return res;
    }

 

 
}

 

HASHMAP複製

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

 
    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
        // 使用哈希
        // 哈希表中<原表節點,新表節點>
        // 
        Map<Node,Node> map=new HashMap<>();
        Node p=head;
        while(p!=null){
            map.put(p,new Node(p.val));
            p=p.next;
        }
        p=head;
        while(p!=null){
            map.get(p).next=map.get(p.next);
            map.get(p).random=map.get(p.random);
            p=p.next;
        }
        return map.get(head);

 
    }
}

 

 

 

面試題36. 二叉搜索樹與雙向鏈表

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;

 
    public Node() {}

 
    public Node(int _val) {
        val = _val;
    }

 
    public Node(int _val,Node _left,Node _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/
class Solution {
    Node head,pre;
    public Node treeToDoublyList(Node root) {
        if(root==null) return null;
        dfs(root);
      head.left=pre;
      pre.right=head;
        return head;
    }
    private void dfs(Node cur){
        if(cur==null) return;
        dfs(cur.left);

 
            //pre 相當於先去探索回溯,比如左下角的葉子節點
            if(pre!=null) pre.right=cur;
            //設置返回鏈表頭節點
            else head=cur;

 
        cur.left=pre;
        pre=cur;

 
        dfs(cur.right);
    }
}

 

 

 

面試題37. 序列化二叉樹

 

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

 
    private void seHelper(TreeNode root,StringBuilder sb){
        //結束條件 返回
       if(root==null){
          sb.append("#,");
          return;
       } 
       sb.append(root.val);
       sb.append(",");
       seHelper(root.left,sb);
       seHelper(root.right,sb);
    }
    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuilder sb=new StringBuilder();
        seHelper(root,sb);
        return sb.toString();
    }

 
    private TreeNode deHelper(LinkedList<String> strlist){
         String first=strlist.removeFirst();
        if(first.equals("#")) return null;
        TreeNode root=new TreeNode(Integer.valueOf(first));
        root.left=deHelper(strlist);
        root.right=deHelper(strlist);
        return root;

 
    }

 
    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        LinkedList<String>  strlist=new LinkedList<>(Arrays.asList( data.split(",")));
        return deHelper(strlist);
    }
}

 
// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));

 

面試題38. 字符串的排列

class Solution {
    LinkedList<String> res=new LinkedList<>();
    char[] c;

 
    public String[] permutation(String s) {
     c=s.toCharArray();
     dfs(0);
     //返回類型
     return res.toArray(new String[res.size()]);
    }
    //遞歸函數
    //輸入遞歸第x層
    private void dfs(int x){
        //遞歸結束條件
        if(x==c.length-1){
            res.add(String.valueOf(c));
            return;
        }
        //處理防止有重複的數
      Set<Character> myset=new HashSet<>();
        //遞推第x層 for循環
        for(int i=x;i<c.length;i++){
            //集合contains
          if(myset.contains(c[i])) continue;
          myset.add(c[i]);
          //i=2.3.4.5.... 和2位置交換 相當於把i位置進行固定到c串裏,對應的位置爲x 等於2 
          swap(i,x);
          //遞歸下一層
          dfs(x+1);
          swap(i,x);

 
        }
    } 
    private void swap(int i,int x){
      char t=  c[i];
        c[i]= c[x];
        c[x]=t;
    }
}

面試題39. 數組中出現次數超過一半的數字

 

HASHmap

class Solution {
    public int majorityElement(int[] nums) {
       Map<Integer,Integer> map=new HashMap<>();
       int len=nums.length/2;
       for(int num :nums){
             if(map.containsKey(num)) {
                 map.put(num,map.get(num)+1);
             }
             else{
                 map.put(num,1);
             }
             if(map.get(num)>len) return num;
       }
       return -1;

 

 
    }
}

 

投票法

class Solution {
    public int majorityElement(int[] nums) {
       int votes=0,x=0;
       for(int num :nums){
           if(votes==0) {
              x=num;
           }
            if(num==x) votes++;
            else votes--;       
       }
       int count=0;
       for(int t :nums){
           if(x==t) count++; 
       }
       int len=nums.length/2;
       return count>len?x:0;
    }
}

 

 

面試題40. 最小的k個數

 

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
       if(k==0){
           return new int[0];
       }
       //最小K個數,需要一個大頂堆
       Queue<Integer> heap=new PriorityQueue<>(k,(i1,i2)->Integer.compare(i2,i1));
       for(int num :arr){
          if(heap.isEmpty()||heap.size()<k||heap.peek()>num){
               heap.offer(num);
          }
          if(heap.size()>k){
             heap.poll();
          }
       }

 
       int[] ans=new int[k];
       int j = 0;
       for (int e : heap) {
          ans[j++] = e;
       }
       return ans;
    }
}

TODO

快排

https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/tu-jie-top-k-wen-ti-de-liang-chong-jie-fa-you-lie-/

 

 

面試題41. 數據流中的中位數

 

class MedianFinder {
    Queue<Integer> A;
    Queue<Integer> B;
    /** initialize your data structure here. */
    public MedianFinder() {
      A=new PriorityQueue<>();//小頂堆
      B=new PriorityQueue<>((x,y)->(y-x));
    }

 
    public void addNum(int num) {
        if(A.size()!=B.size()){
            B.add(num);
            A.add(B.poll());
        }else{
              A.add(num);
            B.add(A.poll());
        }
    }

 
    public double findMedian() {
         return A.size()==B.size()? (A.peek()+B.peek())/2.0 :B.peek();
    }
}

 
/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

 

面試題42. 連續子數組的最大和

 

class Solution {
    public int maxSubArray(int[] nums) {
     // 用sum動態地記錄當前節點最大連續子數組和
        int sum = 0;

 
        // 用max 動態記錄最大值
        int max = nums[0];

 
        for(int i:nums){
            // 如果當前和小於0,只會連累後面的數組和,乾脆放棄!
            if(sum >=0) sum+= i;
            else sum = i;

 
            // 更新max
            max = Math.max(max, sum);
        }
        return max;

 

 
    }
}

面試題43. 1~n整數中1出現的次數

class Solution {
    public int countDigitOne(int n) {
        //找規律題。。
        int digit = 1, res = 0;
        int high = n / 10, cur = n % 10, low = 0;
        while(high != 0 || cur != 0) {
            //規律
            if(cur == 0) res += high * digit;
            else if(cur == 1) res += high * digit + low + 1;
            else res += (high + 1) * digit;

 
            low += cur * digit;
            cur = high % 10;
            high /= 10;
            digit *= 10;
        }
        return res;
    }
}

 

 

面試題44. 數字序列中某一位的數字

class Solution {
    public int findNthDigit(int n) {
      //注意特例
      if(n<10) return n;
      //當前位數數字 比如2位數10---99共90個數字
      int count=0;
      //位數
      int power=1;

 
      //求所在幾位數
      while(true){
         count=helper(power);
         if(n<count) break;
         n-=count;
         power++;
      }
      int resNum=(int)(Math.pow(10,power-1)+n/power);
      //答案對應的字符,再減去字符'0'就得到答案。
      return String.valueOf(resNum).charAt(n % power)- '0';

 
    }

 
    //求power位包含數字 位數而不是數目 如10-99 有90*power位 power = 2
      private int helper(int power){
          if(power==1) return 10;
          return (int)(Math.pow(10,(power-1))*9*power); 
      }
}

面試題45. 把數組排成最小的數

class Solution {
    public String minNumber(int[] nums) {
        //轉換成爲string數組
        String[] strs=new String[nums.length];
       for(int i = 0; i < nums.length; i++) 
            strs[i] = String.valueOf(nums[i]);

 
        Arrays.sort(strs,(x, y) -> (x + y).compareTo(y + x));

 
        StringBuilder sb=new StringBuilder();
        for(String s:strs){
          sb.append(s);
        }
        return sb.toString();
    }
}

 

 

面試題46. 把數字翻譯成字符串

 

class Solution {
    public int translateNum(int num) {
       //dp問題表示前i個數字,不包括i的翻譯數目
        //方便操作轉換爲string
        String s=String.valueOf(num);
        int len=s.length();
        if(len<2) return len;

 
        int[] dp=new int[len+1];
        dp[0]=1;
        dp[1]=1;
        for(int i=2;i<=len;i++){
            //依次取各位的值
            String t=s.substring(i-2,i);
            //翻譯倆位數到字母 有倆種情況
            if(t.compareTo("10")>=0 && t.compareTo("25")<=0){
                dp[i]=dp[i-1]+dp[i-2];
            } else{
                dp[i]=dp[i-1];
            }

 
        }
        return dp[len];
    }
}

 

面試題47. 禮物的最大價值

class Solution {
    public int maxValue(int[][] grid) {
       int m=grid.length;
       if(m==0) return 0;
       int n=grid[0].length;
       for(int i=1;i<m;i++){
            grid[i][0]+=grid[i-1][0];
       }
       for(int j=1;j<n;j++){
            grid[0][j]+=grid[0][j-1];
       }
        for(int i = 1; i < m; i++)
            for(int j = 1; j < n; j++) 
                grid[i][j] += Math.max(grid[i][j - 1], grid[i - 1][j]);
        return grid[m - 1][n - 1];

 
    }
}

 

面試題48. 最長不含重複字符的子字符串

左右邊界的維護

hashmap存儲 字符 更新左邊界

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character,Integer> map=new HashMap();
        //左邊界
        int i=-1;
        int res=0;
        for (int j = 0; j <s.length() ; j++) {
            char t=s.charAt(j);
            if(map.containsKey(t)) {
                //更新左邊界
                i=Math.max(i,map.get(t));
            }
            map.put(t,j);
            res=Math.max(res,j-i);
        }
        return res;
    }
}

面試題49. 醜數

https://leetcode-cn.com/problems/chou-shu-lcof/solution/chou-shu-ii-qing-xi-de-tui-dao-si-lu-by-mrsate/

class Solution {
    public int nthUglyNumber(int n) {
       //定義三個指針分別指向2,3,5的k次方數組
        int a=0,b=0,c=0;
        //存醜數,從小到大
        int[]dp=new int[n];
        dp[0]=1;
        for (int i = 1; i <n ; i++) {
            //指向2,3,5的k次方數組
            int n2=dp[a]*2,n3=dp[b]*3,n5=dp[c]*5;
            dp[i]=Math.min(Math.min(n2,n3),n5);
            if(dp[i]==n2) a++;
            if(dp[i]==n3) b++;
            if(dp[i]==n5) c++;

 
        }
        return dp[n-1];
    }
}

面試題50. 第一個只出現一次的字符

class Solution {
    public char firstUniqChar(String s) {
        Map<Character,Boolean> map=new HashMap<>();
       char[] str=s.toCharArray();
       //字符 是否出現
       for(char t:str){
         map.put(t,!map.containsKey(t));
       }
       //輸出第一個 出現字符
       for(char t:str){
          if(map.get(t)) return t;
       }
       return ' ';
    }
}

 

面試題51. 數組中的逆序對

public class Solution {

 
    public int reversePairs(int[] nums) {
        int len = nums.length;

 
        if (len < 2) {
            return 0;
        }
        //防止修改原數組 拷貝
        int[] copy = new int[len];
        for (int i = 0; i < len; i++) {
            copy[i] = nums[i];
        }

 
        //輔助數組,合併用
        int[] temp = new int[len];
        return reversePairs(copy, 0, len - 1, temp);
    }

 

 

 
 //nums[left..right] 計算逆序對個數並且排序 
    private int reversePairs(int[] nums, int left, int right, int[] temp) {
        if (left == right) {
            return 0;
        }

 
        int mid = left + (right - left) / 2;
        int leftPairs = reversePairs(nums, left, mid, temp);
        int rightPairs = reversePairs(nums, mid + 1, right, temp);

 
        //已經有序,提前結束遞歸
        if (nums[mid] <= nums[mid + 1]) {
            return leftPairs + rightPairs;
        }

 
        int crossPairs = mergeAndCount(nums, left, mid, right, temp);
        return leftPairs + rightPairs + crossPairs;
    }

 

 

 
//合併有序數組,nums[left..mid] 有序,nums[mid + 1..right] 有序
    private int mergeAndCount(int[] nums, int left, int mid, int right, int[] temp) {
        for (int i = left; i <= right; i++) {
            temp[i] = nums[i];
        }

 
        int i = left;
        int j = mid + 1;

 
        int count = 0;
        for (int k = left; k <= right; k++) {

 
            //左半部分遞歸完
            if (i == mid + 1) {
                nums[k] = temp[j];
                j++;
            }
            //右半部分遞歸完
             else if (j == right + 1) {
                nums[k] = temp[i];
                i++;
            } 

 
            else if (temp[i] <= temp[j]) {
                nums[k] = temp[i];
                i++;
            } 
            else {
                nums[k] = temp[j];
                j++;
                //只有這裏操作count++
                count += (mid - i + 1);
            }
        }
        return count;
    }
}

 

面試題52. 兩個鏈表的第一個公共節點

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode n1=headA;
        ListNode n2=headB;
        while(n1!=n2){
            n1= n1==null?headB:n1.next;
            n2= n2==null?headA:n2.next;    
        }
        return n1;
    }
}

 

面試題53 - I. 在排序數組中查找數字 I

分別求7和8的右邊界 相減 得出 8的長度

我不太懂爲什麼要減去helper(target-1), 這個target-1=7剛好在這個數組裏面,那如果target-1不在這個數組裏面呢?

哈嘍~ 實際上就是在查找 target - 1 在數組中的插入點,而“右邊界”代表存在和 target - 1 相等的數字時,插入到相等數字的最右邊~

class Solution {
    public int search(int[] nums, int target) {
        return helper(nums,target)-helper(nums,target-1);
    }
    //二分查找右邊界位置
    private int helper(int[] nums,int target){
        int i=0,j=nums.length-1;
        while(i<=j){
            int m=(i+j)/2;
            //小於等於
            if(nums[m]<=target) i=m+1;
            else j=m-1;
        }
        return i;
    }
}

 

 

面試題53 - II. 0~n-1中缺失的數字

 

排序數組中的搜索問題,首先想到 二分法 解決。

class Solution {
    public int missingNumber(int[] nums) {

 
        int i=0,j=nums.length-1;
        // 小於等於 形成閉區間 等於也可以表示位於同一位置
        while(i<=j){
            int m=(i+j)/2;
            //下標和對應值相等時候 說明缺失的數字在右半部分 
            if(nums[m]==m){
                i=m+1;
            }
            else{
                j=m-1;
            }
        }
        return i;
    }
}

 

面試題54. 二叉搜索樹的第k大節點

倒數第K個節點

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int kthLargest(TreeNode root, int k) {
        List<Integer> ans=new ArrayList<>();
         helper(root,ans);
         return ans.get(ans.size()-k);
    }
    private void helper(TreeNode node,List<Integer> ans){
        if(node==null) return ;
        helper(node.left,ans);
        ans.add(node.val);
        helper(node.right,ans);
    }
}

 

 

面試題55 - II. 平衡二叉樹

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
       if(root==null) return true;
       return Math.abs(depth(root.left)-depth(root.right))<=1 && isBalanced(root.left) && isBalanced(root.right);
    }
    private int depth(TreeNode root){
        if(root==null) return 0;
         return Math.max(depth(root.left), depth(root.right)) + 1;
    }
}

 

面試題56 - I. 數組中數字出現的次數

異或,時間O(N)空間O(1) 滿足要求

class Solution {
    public int[] singleNumbers(int[] nums) {
        //用於將所有的數異或起來
        int k = 0;

 
        for(int num: nums) {
            k ^= num;
        }

 
        //獲得k中最低位的1
        int mask = 1;

 
        //因爲倆個數字,二進制,必然有一位不同
        //找到不相同的那一位,爲了方便直接找最右面的不相同那位
        while((k & mask) == 0) {
            mask <<= 1;
        }
        //定義返回結果值
        int a = 0;
        int b = 0;

 
        for(int num: nums) {
            //和不同那位異或,得到0的放一組,另外的一組,必然可以得出倆個不同的數。因爲相同的倆倆數都會異或爲0
            if((num & mask) == 0) {
                a ^= num;
            } else {
                b ^= num;
            }
        }

 
        return new int[]{a, b};
    }
}

 

HASHSET 時間O(N)空間複雜度爲O(N)不滿足題意

class Solution {
    public int[] singleNumbers(int[] nums) {
        HashSet<Integer> set = new HashSet<>();
        for (int num : nums)
            if (!set.add(num))
                set.remove(num);

 
        return set.stream().mapToInt(Integer::intValue).toArray();
    }
}

 

 

 

面試題56 - II. 數組中數字出現的次數 II

 

HASH表,不滿足空間複雜度

class Solution {
    public int singleNumber(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>();
        for(int i:nums){
            if(map.containsKey(i)){
                int temp = map.get(i);
                map.put(i, temp+1);
            }
            else
                map.put(i, 1);
        }
        for(int i : map.keySet()){
            if(map.get(i) == 1)
                return i;
        }
        return 0;
    }
}

面試題57. 和爲s的兩個數字

 

有序序列,使用雙指針

class Solution {
    public int[] twoSum(int[] nums, int target) {
       int i=0,j=nums.length-1;
       while(i<j){
           int s = nums[i] + nums[j];
           if(s==target) return new int[]{nums[i],nums[j]};
           if(s<target) i++;
           if(s>=target) j--;
       }
       //沒有找到結果
       return new int[0];
    }
}

 

 

面試題57 - II. 和爲s的連續正數序列

class Solution {
    public int[][] findContinuousSequence(int target) {
      //滑動窗口題 常左閉右開

 
      List<int[]> ans=new ArrayList<>();
      //從1開始 保證下標和數值一致
      int i=1,j=1,sum=0;
      while(i<=target/2){
         if(sum<target){
             sum+=j;
             j++;
         }
         else if(sum>target){
             sum-=i;
             i++;
         }
         else{
             int[] tmp=new int[j-i];
             //左閉右開
             for(int k=i;k<j;k++){
                tmp[k-i]=k;
             }
             ans.add(tmp);
             //處理邊界,先減去當前值!再左邊界右移!

 
             sum-=i;
              i++;
         }
      }
      return ans.toArray(new int[ans.size()][] );
    }
}

 

 

面試題58 - I. 翻轉單詞順序

class Solution {
    public String reverseWords(String s) {
        String[] strs = s.trim().split(" "); // 刪除首尾空格,分割字符串
        StringBuilder res = new StringBuilder();
        for(int i = strs.length - 1; i >= 0; i--) { // 倒序遍歷單詞列表
            if(strs[i].equals("")) continue; // 遇到空單詞則跳過
            res.append(strs[i] + " "); // 將單詞拼接至 StringBuilder
        }
        return res.toString().trim(); // 轉化爲字符串,刪除尾部空格,並返回
    }
}

 

面試題59 - I. 滑動窗口的最大值

//給定一個數組 nums 和滑動窗口的大小 k,請找出所有滑動窗口裏的最大值。 
//
// 示例: 
//
// 輸入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
//輸出: [3,3,5,5,6,7] 
//解釋: 
//
//  滑動窗口的位置                最大值
//---------------               -----
//[1  3  -1] -3  5  3  6  7       3
// 1 [3  -1  -3] 5  3  6  7       3
// 1  3 [-1  -3  5] 3  6  7       5
// 1  3  -1 [-3  5  3] 6  7       5
// 1  3  -1  -3 [5  3  6] 7       6
// 1  3  -1  -3  5 [3  6  7]      7 
//
// 
//
// 提示: 
//
// 你可以假設 k 總是有效的,在輸入數組不爲空的情況下,1 ≤ k ≤ 輸入數組的大小。 
//
// 注意:本題與主站 239 題相同:https://leetcode-cn.com/problems/sliding-window-maximum/ 
// Related Topics 棧 Sliding Window

 

 
import sun.misc.Queue;

 
import java.util.LinkedList;

 
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
       if(nums==null|| k < 1 || nums.length < k){
           return new int[0];
       }

 
        //滑動窗口
        LinkedList<Integer> queue=new LinkedList<>();
        //結果數組
        int[]res=new int[nums.length-k+1];
         int index=0;
        for (int i = 0; i <nums.length ; i++) {
            //while循環保證小等於 的全部出隊列  進行值的比較而不是下標
           while(!queue.isEmpty()&&nums[queue.peekLast()]<=nums[i]){
               queue.pollLast();
            }
            //存下標
            queue.addLast(i);
           //多餘隊頭元素處理
            if(queue.peekFirst()==i-k){
                queue.poll();
            }
            //結果輸出返回值而不是下標,保證形成窗口
            if(i+1>=k){
               res[index++]=nums[queue.peek()];
            }

 
        }
        return res;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

 

面試題59 - II. 隊列的最大值

class MaxQueue {
    Queue<Integer> queue;
    Deque<Integer> deque;
    public MaxQueue() {
       queue=new LinkedList<>();
       deque=new LinkedList<>();
    }

 
    //求最大值,只需返回deuque的隊首
    public int max_value() {
      return deque.size()>0?deque.peek():-1;
    }

 
    //入queue,之後deque更新最大值
    public void push_back(int value) {
        queue.offer(value);
        //防止deque空指針
        while(deque.size()>0 && deque.peekLast()<value){
            deque.pollLast();//將deq隊尾小於value的元素刪掉
        }
        deque.addLast(value);
    }

 
    //出queue的首元素不一定是最大的
    public int pop_front() {
        int tmp=queue.size()>0?queue.poll():-1;  //獲得隊首元素保證隊首不爲空
        //如果出queue的時候,是最大需要把deque的值也彈出
        if(deque.size()>0 && deque.peek().equals(tmp)){
             deque.poll();
        }
        return tmp;
    }
}

 

面試題60. n個骰子的點數

class Solution {
    public double[] twoSum(int n) {
        //整體思路:各個點數出現的次數/總共點數出現的次數
         //i個骰子出現s點的次數
         int[][] dp=new int[n+1][6*n+1];
         //表示一個骰子擲出i點的次數爲1
         for(int i=1;i<=6;i++){
                dp[1][i]=1;
         }

 
         //遍歷n個骰子
         for(int i=2;i<=n;i++){
             //可能的總點數和
             for(int s=i;s<=6*i;s++){
                   //當前可投出的點數
                   for(int j=1;j<=6;j++){

 
                         //i個骰子的總點數爲s
                         //如果s比最後一個骰子的點數j和之前(i-1)個骰子的最小點數之和(i-1)的和(即j+(i-1))還要小
                         //那麼這種情況不存在。
                         if(s<j+(i-1)) break;
                         dp[i][s] += dp[i-1][s-j];
                    }
             }          
         }

 
       double total = Math.pow((double)6,(double)n);//擲出n次點數出現的所有情況
       double[] ans = new double[5*n+1];//因爲最大點數6n-最小點數n:--》出現6*n - n +1中點數
        for(int i=n;i<=6*n;i++){
            ans[i-n]=((double)dp[n][i])/total;//第i小的點數出現的概率
        }
        return ans;

 
    }
}

 

面試題61. 撲克牌中的順子

class Solution {
    public boolean isStraight(int[] nums) {
      //構成順子     ---   max-min<5 且 無重複值
      Set<Integer> set=new HashSet<>();
      int max=0;
      int min=14;
      for(int num:nums){
          //大小王時候跳過
        if(num==0) continue;
        //判斷重複 :加入集合失敗->表示已經重複有這個元素,返回false
         if(!set.add(num)) return false;

 
         //求最大,最小值賦值給max和min
         max=Math.max(max,num);
         min=Math.min(min,num);

 
      }
      return max-min<5;
    }
}

 

 

面試題62. 圓圈中最後剩下的數字

class Solution {
    public int lastRemaining(int n, int m) {
        int ans = 0;
        // 最後一輪剩下2個人,所以從2開始反推
        // i代表此時輪次
        for (int i = 2; i <= n; i++) {
            ans = (ans + m) % i;
        }
        return ans;
    }
}

 

 

 

面試題63. 股票的最大利潤

class Solution {
    public int maxProfit(int[] prices) {
      //數組當中最低的價格
      int cost=Integer.MAX_VALUE;
      int ans=0;
      for(int price :prices){
         cost=Math.min(cost,price);
         ans=Math.max(ans,price-cost);
      }
      return ans;
    }
}

 

面試題65. 不用加減乘除做加法

class Solution {
    public int add(int a, int b) {
        //進位爲0出口
        if (b == 0) {
            return a;
        }

 
        // 轉換成非進位和 + 進位
        return add(a ^ b, (a & b) << 1);
    }
}

 

 

面試題66. 構建乘積數組

 

規律

https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof/solution/mian-shi-ti-66-gou-jian-cheng-ji-shu-zu-biao-ge-fe/

class Solution {
    public int[] constructArr(int[] a) {
        if(a.length == 0) return new int[0];
        int[] b = new int[a.length];
        b[0] = 1;
        int tmp = 1;
        for(int i = 1; i < a.length; i++) {
            b[i] = b[i - 1] * a[i - 1];
        }
        for(int i = a.length - 2; i >= 0; i--) {
            tmp *= a[i + 1];
            b[i] *= tmp;
        }
        return b;
    }
}

 

面試題67. 把字符串轉換成整數

 

class Solution {
    public int strToInt(String str) {
       char[] c=str.trim().toCharArray();
       if(c.length==0)  return 0;
       int sign=1;//符號位
       int i=1;//數字起始位,必須給符號位空一個
       int bndry = Integer.MAX_VALUE / 10;//定義邊界
       int res=0;//數字結果值

 
       if(c[0]=='-') sign=-1;
       // else if 符號位只處理一次   :符號位不爲 +號 此時遍歷i從0開始  
       else if(c[0]!='+') i=0;
       //遍歷處理數字
       for(int j=i;j<c.length;j++){
           //讀取到字符
          if(c[j]<'0'||c[j]>'9') break;
          //邊界處理 根據符號位正負返回對應的值
           if(res > bndry || res == bndry && c[j] > '7') return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;

 
          res=res*10+ (c[j]-'0');
       }
       //res需要進行Int強制轉換(int)res
       return sign * (int)res;
    }
}

 

面試題68 - I. 二叉搜索樹的最近公共祖先

 

迭代

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
       //交換保證p小q大 節省後面的比較
        if(p.val>q.val){
          TreeNode t=p;
          p=q;
          q=t;
        }

 
        while(root!=null){
            //p.q均在當前root的右子樹
           if(root.val<p.val){
              root = root.right; // 遍歷至右 子節點 
           }
           //p.q均在當前root的左子樹
           else if(root.val>q.val){
               root=root.left;//遍歷至左 子節點
           }
           //p.q在當前root的不同側 子樹
           else{
               break;
           }
        }
        return root;
    }
}

 

面試題68 - II. 二叉樹的最近公共祖先

遞歸

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //結束條件 
        if(root==null||root==p||root==q) return root;

 
        TreeNode left=lowestCommonAncestor(root.left,p,q);
        TreeNode right=lowestCommonAncestor(root.right,p,q);

 
        //針對left和right
        //左空 
        if(left==null) return right;
        //右空
        if(right==null) return left;
        //左右均爲空 說明 rootroot 的左 / 右子樹中都不包含pq-返回null; 
        //或者表示 均不空 分別在左右子樹,返回根節點
        return root;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章