天天看點

劍指offer/36-40

文章目錄

    • 36、兩個連結清單第一個公共節點
    • 37、統計一個數字在升序數組中出現的次數
    • 38、二叉樹的深度
    • 39、平衡二叉樹
    • 40、數組中隻出現一次的數

36、兩個連結清單第一個公共節點

題目描述

輸入兩個連結清單,找出它們的第一個公共結點。(注意因為傳入資料是連結清單,是以錯誤測試資料的提示是用其他方式顯示的,保證傳入資料是正确的)

思路:

對于兩個這樣的序列:

0-1-2-3-4-5-null
a-b-4-5-null
           

他們的公共點後的長度必定是相同的。

也就是說

4-5-null

這後兩個節點是共同的。

那麼可以這麼推理:

0-1-2-3-4-5-null a-b-4-5-null

a-b-4-5-null 0-1-2-3-4-5-null

的長度是相同的,且他們的節點都是

4-5-null

,且到這個公共節點的最後一個節點的距離相同,都是第九個。

連結:https://www.nowcoder.com/questionTerminal/6ab1d9a29e88450685099d45c9e31e46?answerType=1&f=discussion
來源:牛客網

    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if(pHead1 == null || pHead2 == null) return null;
        ListNode p1 = pHead1;
        ListNode p2 = pHead2;
        while (p1 != p2) {
            p1 = p1.next;
            p2 = p2.next;
            if (p1 != p2 && p1 == null) {
                p1 = pHead2;
            }
            if (p1 != p2 && p2 == null) {
                p2 = pHead1;
            }
        }
        return p1;
    }
           

37、統計一個數字在升序數組中出現的次數

題目描述:

統計一個數字在升序數組中出現的次數。

顯然是利用二分查找。因為有序,是以目标值target如果有多個,肯定是連在一起。又已知我們可以在有序數組中查找任意一個值,是以我們可以先查找目标範圍的下界和上界。

下界定義為:如果存在目标值,則指向第一個目标值,否則,如果不存在, 則指向大于目标值的第一個值。

上界定義為:不管目标值存在與否,都指向大于目标值的第一個值。

package M36TO40;

public class SoluGetNumberOfK {
    public int GetNumberOfK(int [] array , int k) {
        if (array ==null || array.length==0) return 0;
        int lowIndex = lowerBound(array,k);
        int upperIndex = upperBound(array,k);
        return upperIndex-lowIndex;
    }
    //這裡左邊界和右邊界,關鍵是看當等于target時,是l = mid + 1還是r = mid-1
    private int upperBound(int[] array,int val){
        int l = 0,r = array.length-1,mid;
        while (l<=r){
            mid = (l+r)/2;
            //要找的值比中間值大則,值位于中間點右邊,l= mid +1;,直到找到大于val的第一個值
            if (array[mid]<=val){
                l = mid + 1;
            //要找的值比中間值小則,值位于中間點左邊,r= mid-1;
            }else{
                r = mid-1;
            }
        }
        return l;
    }
    private int lowerBound(int[] array,int val){
        int l = 0,r = array.length-1,mid;
        while (l<=r){
            mid=(l+r)/2;
            //與上面的差別是,即使相等也向右找知道找最小的val的值
            if (array[mid]<val){
                l = mid +1;
            }else{
                r = mid-1;
            }
        }
        return l;
    }

}

           

38、二叉樹的深度

題目描述

輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度為樹的深度。

package M36TO40;

import M16TO20.TreeNode;
import java.util.LinkedList;
import java.util.Queue;

public class SoluTreeDepth {
    public int TreeDepth(TreeNode root){
        if (root == null) return 0;

        //用層次周遊(廣度優先周遊)
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int depth = 0;
        while (!queue.isEmpty()){
            for (int i = 0;i< queue.size();i++){
                TreeNode node = queue.poll();
                if (node.left !=null) queue.offer(node.left);
                if (node.right !=null) queue.offer(node.right);
            }
            depth++;
        }
        return depth;
    }
}
           

39、平衡二叉樹

題目描述

輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。

在這裡,我們隻需要考慮其平衡性,不需要考慮其是不是排序二叉樹

package M36TO40;

import M16TO20.TreeNode;

public class SoluIsBalanced_Solution {
    public int depth(TreeNode root){
        if (root==null) return 0;
        int left = depth(root.left);
        if (left==-1) return -1;//如果發現子樹不平衡之後就沒有必要進行下面的高度的求解了
        int right = depth(root.right);
        if (right==-1) return -1;//如果發現子樹不平衡之後就沒有必要進行下面的高度的求解了
        //left,right初始化都是0
        if (Math.abs(left-right)>1) return -1;
        else{
            return 1+(left>right ?left:right);
        }
    }
    public boolean IsBalanced_Solution(TreeNode root){
        return depth(root) !=-1;
    }
}
///二
class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root==null)
            return true;
        if(dfs(root)<0){
            return false;
        }else{
            return true;
        }

    }
    public int dfs(TreeNode root){
        if(root==null)
            return 0;
        int left=dfs(root.left);
        int right=dfs(root.right);
        if(left<-1||right<-1||Math.abs(left-right)>1){
            return -2;
        }
        return Math.max(left,right)+1;
    }
}
           

40、數組中隻出現一次的數

一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。請寫程式找出這兩個隻出現一次的數字。

用的map

package M36TO40;

import java.util.HashMap;

public class SoluFindNumsAppearOnce {
    public void FindNumsAppearOnce(int[] array,int num1[],int num2[]) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < array.length; i++) {
            if (map.containsKey(array[i])) {
                map.put(array[i], 2);
            } else {
                map.put(array[i], 1);
            }
        }
        int count = 0;
        for (int i=0;i<array.length;i++){
            if (map.get(array[i])==1){
                if (count==0){
                    num1[0] = array[i];
                    count++;
                }else{
                    num2[0] = array[i];
                }
            }
        }
    }
}

           

用亦或的:

class Solution {
    public int[] singleNumbers(int[] nums) {
        //假設a b隻出現一次
        //先求出 a^b
        int mid=nums[0];
        for(int i=1;i<nums.length;i++){
            mid ^=nums[i];
        }
        //a^b 找到值的最後一個1
        //則 a b兩個值的二進制在這一個位置是一定一個是0一個是1
        mid -= mid&(mid-1);
        int[] res = new int[2];
        for(int i=0;i<nums.length;i++){
            //數組可以分為兩組[a x1 x2 x3...] [b x4 x5 x6...]
            //一組中對應二進制為1的位置上的數為0 一組為1,然後組内進行異或運算,這最後分别剩下 a b
            if((mid&nums[i])==0){
                res[0] ^=nums[i];
            }else{
                res[1] ^=nums[i];
            }
        }
        if (res[0] > res[1]) {
            int temp = res[0];
            res[0] = res[1];
            res[1] = temp;
        }
        return res;
    }
}
           

繼續閱讀