原文個人博客地址
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;
}
}
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();
}
}
返回爲數組,直接用棧模擬即可
/**
* 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;
}
}
/**
* 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;
}
}
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();
*/
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];
}
}
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];
}
}
和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];
}
}
//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;
}
}
方法一: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);
}
}
小數據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];
}
}
大數貪心
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);
}
}
方法一:不改變原數字
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;
}
}
快速冪
把指數 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;
}
}
快速冪同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;
}
}
方法一:單個指針操作
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;
}
}
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];
}
}
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;
}
}
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;
}
}
/**
* 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;
}
}
/**
* 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;
}
}
/**
* 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;
}
}
/**
* 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);
}
}
遞歸
/**
* 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;
}
}
/**
* 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);
}
}
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;
}
}
函數設計:
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();
*/
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();
}
}
輸出爲一維數組
/**
* 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;
}
}
輸出二維數組
/**
* 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;
}
}
輸出二維數組帶奇偶
/**
* 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;
}
}
遞歸 時間複雜度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;
}
}
/**
* 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();
}
}
/*
// 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);
}
}
/*
// 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);
}
}
/**
* 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));
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;
}
}
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;
}
}
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
快排
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();
*/
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;
}
}
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;
}
}
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);
}
}
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();
}
}
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];
}
}
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];
}
}
左右邊界的維護
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. 醜數
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];
}
}
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 ' ';
}
}
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;
}
}
/**
* 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;
}
}
分別求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;
}
}
排序數組中的搜索問題,首先想到 二分法 解決。
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;
}
}
倒數第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);
}
}
/**
* 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;
}
}
異或,時間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();
}
}
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;
}
}
有序序列,使用雙指針
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];
}
}
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()][] );
}
}
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(); // 轉化爲字符串,刪除尾部空格,並返回
}
}
//給定一個數組 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;
}
}
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;
}
}
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;
}
}
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;
}
}
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);
}
}
規律
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;
}
}
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;
}
}
迭代
/**
* 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;
}
}
遞歸
/**
* 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;
}
}