劍指offer刷題總結


 

★ 二維數組的查找

在一個二維數組中(每個一維數組的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。

找規律題,
只要從左下角或右上角出發,就可以一步步縮小范圍,
比目標值小就向右/下,比目標值大就向左/

 


 

替換空格

請實現一個函數,將一個字符串中的每個空格替換成“%20”。例如,當字符串為We Are
Happy.則經過替換之后的字符串為We%20Are%20Happy。

重點在於創建新數組而不是直接替換,
直接替換會像ArrayList的插入一樣有 O() 的時間復雜度,
所以應該創建新數組,遍歷放入

 


 

從尾到頭打印鏈表

輸入一個鏈表,按鏈表從尾到頭的順序返回一個ArrayList。

這道題很簡單,用堆棧或者遞歸就可以了

 


 

★ 重建二叉樹

輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重復的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

這道題其實說難也難,說不難也不難,思路不難想,
無非是前序的結點為根結點,把中序的數組分割成左右子樹,不停的遞歸分割就可以了,
題目的關鍵在於在面試時手擼出這份代碼以及寫好各種邊界條件的限制。

 


 

★ 用兩個棧實現隊列

用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素為int類型。

簡單題,每次psuh是時先將stack2清空放入stack1,stack2始終是用來刪除的

 


 

★ 旋轉數組的最小數字

把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。 輸入一個非遞減排序的數組的一個旋轉,輸出旋轉數組的最小元素。
例如數組{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該數組的最小值為1。
NOTE:給出的所有元素都大於0,若數組大小為0,請返回0。

看到排序好的數組就應該想到二分法了,這道題是二分法的變形,
中間元素大於第一個元素,則中間元素位於前面的遞增子數組,
此時最小元素位於中間元素的后面。
中間元素小於第一個元素,則中間元素位於后面的遞增子數組,
此時最小元素位於中間元素的前面。
但是要注意數字重復這種情況,例如:{10111} 和 {11101} 
都可以看成是遞增排序數組{01111}的旋轉。
這種情況下只能 O(n)for循環來解決了

 


 

斐波那契數列

不用給題目了,就是普通題,正常寫,不要用遞歸就行

 


 

★ 跳台階

一只青蛙一次可以跳上1級台階,也可以跳上2級。求該青蛙跳上一個n級的台階總共有多少種跳法(先后次序不同算不同的結果)。

找規律題,一點點寫出來就會發現結果其實成斐波那契數列排列

 


 

★ 變態跳台階

一只青蛙一次可以跳上1級台階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的台階總共有多少種跳法。

這道題的思路非常巧妙,青蛙跳2級,即意味着經過一個台階,不經過另一個一個台階,
青蛙跳3級,則意味着前兩個台階沒經過(直接跳過了),只經過最后一個台階,
青蛙跳4級,則意味着前三個台階沒經過,只經過最后一個台階。
所以每個台階都有經過和不經過兩種可能,所以結果是2 * 2 * 2 * ....種跳法。

 


 

矩形覆蓋

我們可以用2 * 1的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個2 * 1的小矩形無重疊地覆蓋一個2 * n的大矩形,總共有多少種方法?

和第8題的跳台階一樣是規律題,斐波那契數列可解

 


 

★ 二進制中1的個數

輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼表示。

解法一、這種解法在輸入負數時會因為右移把負數變成正數

public static int NumberOf1(int n) {
        int count = 0;
        while (n != 0) {
           /* * 用1和n進行位與運算, * 結果要是為1則n的2進制形式 * 最右邊那位肯定是1,否則為0 */
            if ((n & 1) == 1) {
                count++;
            }
            n = n >> 1;
        }
        return count;
}

-----------------------------------------------------------------------
解法二、移動數字1,不移動n

private static int NumberOf1_low(int n) {
        int count = 0;
        int flag = 1;
        while (flag != 0) {
            if ((n & flag) != 0) {
                count++;
            }
            flag = flag << 1;
        }
        return count;
}

-----------------------------------------------------------------------
解法三、如果一個整數不為0,那么這個整數至少有一位是1。如果我們把這個整數減1,
那么原來處在整數最右邊的1就會變為0,原來在1后面的所有的0都會變成1
舉個例子:一個二進制數1100,從右邊數起第三位是處於最右邊的一個1。
減去1后,第三位變成0,它后面的兩位0變成了1,而前面的1保持不變,
因此得到的結果是1011.我們發現減1的結果是把最右邊的一個1開始的所有位都取反了。
這個時候如果我們再把原來的整數和減去1之后的結果做與運算,
從原來整數最右邊一個1那一位開始所有位都會變成0。如1100&1011=1000
也就是說消掉了一個1,這種方法不需要循環每一位,而是每有一個1就循環一次

public class Solution {
    public int NumberOf1(int n) {
        int count = 0;
        while (n != 0) {
            count++;
            n = (n - 1) & n;
        }
        return count;
    }
}

 


 

★ 數值的整數次方

給定一個double類型的浮點數base和int類型的整數exponent。求base的exponent次方。
保證base和exponent不同時為0

這道題主要是考察對邊界條件考慮是否全面以及使用快速冪算法進行優化

快速冪算法的核心部分
while (exponent != 0) {
	if ((exponent & 1) != 0) {
    	result *= base;
    }
    exponent >>= 1;
    base *= base;
}

 


 

★ 調整數組順序使奇數位於偶數前面

輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得所有的奇數位於數組的前半部分,所有的偶數位於數組的后半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。

這道題書上沒有相對位置保持不變這種說法,所以只要用快排的思想,
用兩個指針一個指頭一個指尾,前面指針為偶數時停下,后面指針為奇數時停下,
然后交換位置,直到兩個指針相遇為止。
但是,牛客這里加了相對位置不變的要求,所以快排這種不穩定的算法是不可以的,
因此可以用空間換時間,新建一個數組,遍歷第一次把奇數放入,第二次把偶數放入即可。

 


 

★ 鏈表中倒數第k個結點

輸入一個鏈表,輸出該鏈表中倒數第k個結點。

這道題很精妙,只要定義兩個指針,第一個指針先走k步,然后兩個指針一起走,
當第一個指針到達時,第二個指針指向的地方就是結果,這樣就只需要遍歷一遍就可以了。

 


 

反轉鏈表

輸入一個鏈表,反轉鏈表后,輸出新鏈表的表頭。

簡單題,沒什么可講的,只是為了考察考生對鏈表指針的操作能力。

 


 

★ 合並兩個排序的鏈表

輸入兩個單調遞增的鏈表,輸出兩個鏈表合成后的鏈表,當然我們需要合成后的鏈表滿足單調不減規則。

新建一個節點,兩個鏈表和節點一共三個指針,把新節點接到值小的那個上,
不停切換就可以了。最后結果返回新建節點的next。

 


 

★ 樹的子結構

輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)

這道題沒有特別的技巧或思路,但是也不簡單,所以直接貼代碼了

public class Solution {
    public static boolean HasSubtree(TreeNode root1, TreeNode root2) {
        boolean result = false;
        //當Tree1和Tree2都不為零的時候,才進行比較。否則直接返回false
        if (root2 != null && root1 != null) {
            //如果找到了對應Tree2的根節點的點
            if(root1.val == root2.val){
                //以這個根節點為為起點判斷是否包含Tree2
                result = doesTree1HaveTree2(root1,root2);
            }
            //如果找不到,那么就再去root的左兒子當作起點,去判斷時候包含Tree2
            if (!result) {
                result = HasSubtree(root1.left,root2);
            }
             
            //如果還找不到,那么就再去root的右兒子當作起點,去判斷時候包含Tree2
            if (!result) {
                result = HasSubtree(root1.right,root2);
               }
            }
            //返回結果
        return result;
    }
 
    public static boolean doesTree1HaveTree2(TreeNode node1, TreeNode node2) {
        //如果Tree2已經遍歷完了都能對應的上,返回true
        if (node2 == null) {
            return true;
        }
        //如果Tree2還沒有遍歷完,Tree1卻遍歷完了。返回false
        if (node1 == null) {
            return false;
        }
        //如果其中有一個點沒有對應上,返回false
        if (node1.val != node2.val) {  
                return false;
        }
         
        //如果根節點對應的上,那么就分別去子節點里面匹配
        return doesTree1HaveTree2(node1.left,node2.left) && doesTree1HaveTree2(node1.right,node2.right);
    }
}

 


 

★ 二叉樹的鏡像

操作給定的二叉樹,將其變換為源二叉樹的鏡像。
在這里插入圖片描述

思路比較簡單,后續遍歷就可以了
mirrorTree(root.left);
mirrorTree(root.right);
swap(root);

 


 

★ 順時針打印矩陣

輸入一個矩陣,按照從外向里以順時針的順序依次打印出每一個數字,例如,如果輸入如下4 X 4矩陣: 1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 則依次打印出數字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

這道題看起來不難,實際寫起來卻異常困難,因為涉及到各種邊界條件的考慮
在這里插入圖片描述


 

★ 包含min函數的棧

定義棧的數據結構,請在該類型中實現一個能夠得到棧中所含最小元素的min函數(時間復雜度應為O(1))。

這道題如果你只是用普通的一個min變量來存的話,
當你的棧pop掉這個min時,你就無法再次獲得棧中的min了,
當然你也可以全部彈出再統計一遍,但是這樣的時間復雜度就不符合要求了。
因此,我們需要定義一個minStack來存儲min,
當當前push的數小於min時,給min賦值,並將這個值壓入最小棧,
如果比min大或等於min,則意味着這個數被彈出后最小值還是min,
因此直接把min壓入minStack即可。
當需要min時只要minStack.peek()就可以了。

 


 

★ 棧的壓入、彈出序列

輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否可能為該棧的彈出順序。假設壓入棧的所有數字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。(注意:這兩個序列的長度是相等的)

簡單模擬題,雖然其實有其他解法就是了,不過還是模擬比較簡單易實現

 


 

從上往下打印二叉樹

從上往下打印出二叉樹的每個節點,同層節點從左至右打印。

簡單題,借個隊列就可以實現了

 


 

23.二叉搜索樹的后序遍歷序列

輸入一個整數數組,判斷該數組是不是某二叉搜索樹的后序遍歷的結果。如果是則輸出Yes,否則輸出No。假設輸入的數組的任意兩個數字都互不相同。

后續遍歷數組的最后一個數是根結點,根據根結點划分左右子樹,
過程中如果出現左子樹中有值大於根結點或者右子樹有值小於根結點則返回false

 


 

24.二叉樹中和為某一值的路徑

輸入一顆二叉樹的根節點和一個整數,打印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。(注意:
在返回值的list中,數組長度大的數組靠前)

簡單題,前序遍歷把值加入數組,當回到父節點時則把值從數組刪去,
在葉節點時如果值等於target,則保存到ArrayList中

 


 

25.復雜鏈表的復制

輸入一個復雜鏈表(每個節點中有節點值,以及兩個指針,一個指向下一個節點,另一個特殊指針指向任意一個節點),返回結果為復制后復雜鏈表的head。(注意,輸出結果中請不要返回參數中的節點引用,否則判題程序會直接返回空)

很難想到的解題思路,分三步

第一步、復制每個節點並接在舊節點前面
在這里插入圖片描述
第二步、A1.random = A.random.next;
在這里插入圖片描述
第三步、把鏈表拆成兩個就可以了
在這里插入圖片描述


 

26.二叉搜索樹與雙向鏈表

輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能創建任何新的結點,只能調整樹中結點指針的指向。

簡單題,中序遍歷即可

 


 

27.字符串的排列

題目描述
輸入一個字符串,按字典序打印出該字符串中字符的所有排列。例如輸入字符串abc,則打印出由字符a,b,c所能排列出來的所有字符串abc,acb,bac,bca,cab和cba。
輸入描述:
輸入一個字符串,長度不超過9(可能有字符重復),字符只包括大小寫字母。

簡單全排列

 


 

28.數組中出現次數超過一半的數字

數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度為9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。

解法賊機智

數組中有一個數字出現的次數超過數組長度的一半,
也就是說它出現的次數比其他所有數字出現次數的和還多,
因此我們可以在遍歷數組時保存兩個值,一個數字,一個次數,
當我們遍歷到下一個數字時,如果下一個數字和我們保存的數字不同,則次數減一,
如果次數為0,那么我們需要保存下一個數字,並把次數設為1,
最后還保存着的數字就是那個出現了一半的數字了。O(n)
當然還要記得檢查一下這個數字是否出現了一半。O(n)

 


 

29.最小的K個數

輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,。

如果可以改變數組,則可以采用Partition方法
(快排中的一部分,把比x小的交換到x左邊,比x大的交換到x右邊),時間復雜度是O(n²)

如果不可以修改數組,使用堆或紅黑樹,Java中堆用PriorityQueue優先隊列即可
(默認最小堆),時間復雜度是O(nlogk),創建一個容量為k的最大堆,
然后每次放入新的,取出最大的即可。

 


 

30.連續子數組的最大和

HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會后,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如:{6,-3,-2,7,-15,1,2,2},連續子向量的最大和為8(從第0個開始,到第3個為止)。給一個數組,返回它的最大連續子序列的和,你會不會被他忽悠住?(子向量的長度至少是1)

dp

 


 

31.整數中1出現的次數(從1到n整數中1出現的次數)

求出1 ~ 13的整數中1出現的次數,並算出100 ~ 1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於后面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數(從1到 n 中1出現的次數)。

沒想到會遇到這種leetcode的困難題,頂不順惹啦

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
    //主要思路:設定整數點(如1、10、100等等)作為位置點i(對應n的各位、十位、百位等等),分別對每個數位上有多少包含1的點進行分析
    //根據設定的整數位置,對n進行分割,分為兩部分,高位n/i,低位n%i
    //當i表示百位,且百位對應的數>=2,如n=31456,i=100,則a=314,b=56,此時百位為1的次數有a/10+1=32(最高兩位0~31),每一次都包含100個連續的點,即共有(a%10+1)*100個點的百位為1
    //當i表示百位,且百位對應的數為1,如n=31156,i=100,則a=311,b=56,此時百位對應的就是1,則共有a%10(最高兩位0-30)次是包含100個連續點,當最高兩位為31(即a=311),本次只對應局部點00~56,共b+1次,所有點加起來共有(a%10*100)+(b+1),這些點百位對應為1
    //當i表示百位,且百位對應的數為0,如n=31056,i=100,則a=310,b=56,此時百位為1的次數有a/10=31(最高兩位0~30)
    //綜合以上三種情況,當百位對應0或>=2時,有(a+8)/10次包含所有100個點,還有當百位為1(a%10==1),需要增加局部點b+1
    //之所以補8,是因為當百位為0,則a/10==(a+8)/10,當百位>=2,補8會產生進位位,效果等同於(a/10+1)
    int count=0;
    long long i=1;
    for(i=1;i<=n;i*=10)
    {
        //i表示當前分析的是哪一個數位
        int a = n/i,b = n%i;
        count=count+(a+8)/10*i+(a%10==1)*(b+1);
    }
    return count;
    }
};

 


 

32. 把數組排成最小的數

輸入一個正整數數組,把數組里所有數字拼接起來排成一個數,打印能拼接出的所有數字中最小的一個。例如輸入數組{3,32,321},則打印出這三個數字能排成的最小數字為321323。

字典序,只要把compare方法改寫成332比較323即可

 


 

33.丑數

把只包含質因子2、3和5的數稱作丑數(Ugly Number)。例如6、8都是丑數,但14不是,因為它包含質因子7。習慣上我們把1當做是第一個丑數。求按從小到大的順序的第N個丑數。

public int GetUglyNumber_Solution(int n) {
        if(n<=0)return 0;
        ArrayList<Integer> list=new ArrayList<Integer>();
        list.add(1);
        int i2=0,i3=0,i5=0;
        while(list.size()<n)//循環的條件
        {
            int m2=list.get(i2)*2;
            int m3=list.get(i3)*3;
            int m5=list.get(i5)*5;
            int min=Math.min(m2,Math.min(m3,m5));
            list.add(min);
            if(min==m2)i2++;
            if(min==m3)i3++;
            if(min==m5)i5++;
        }
        return list.get(list.size()-1);
    }

 


 

34.第一個只出現一次的字符

在一個字符串(0<=字符串長度<=10000,全部由字母組成)中找到第一個只出現一次的字符,並返回它的位置, 如果沒有則返回 -1(需要區分大小寫)

hashmap

 


 

35.數組中的逆序對

在數組中的兩個數字,如果前面一個數字大於后面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007

歸並排序


 

36.兩個鏈表的第一個公共結點

輸入兩個鏈表,找出它們的第一個公共結點。

堆棧法,把兩個鏈表放入兩個棧,彈出,直到結果不相等為止,
最后一個相等的就是第一個公共結點。用空間換時間。

遍歷一次后得出兩個鏈表的長度,之后采用快慢指針法,遍歷到相等就是第一個公共結點。

 


 

37.數字在排序數組中出現的次數

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

二分法,找到開始和結尾位置

 


 

38.二叉樹的深度

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

遞歸解法,左子樹最長和右子樹最長中長的一個

 


 

39.數組中只出現一次的數字

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

異或所有數字,得到的結果就是兩個不相同的數字的異或結果。
以結果中某個位為1的位為標准(即兩個數不相同的位),將數組分成兩個子數組,
這時候兩個不相同的數一定被分配到兩個不同的子數組,
這時候再異或一次即可得到結果

 


 

40.和為S的連續正數序列

小明很喜歡數學,有一天他在做數學作業時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他並不滿足於此,他在想究竟有多少種連續的正數序列的和為100(至少包括兩個數)。沒多久,他就得到另一組連續正數和為100的序列:18,19,20,21,22。現在把問題交給你,你能不能也很快的找出所有和為S的連續正數序列?
Good Luck!

在這里插入圖片描述


 

41. 和為S的兩個數字

輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,使得他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。

前后兩指針,大了后面的指針前移,小了前面的指針后移

 


 

42. 左旋轉字符串

匯編語言中有一種移位指令叫做循環左移(ROL),現在有個簡單的任務,就是用字符串模擬這個指令的運算結果。對於一個給定的字符序列S,請你把其循環左移K位后的序列輸出。例如,字符序列S=”abcXYZdef”,要求輸出循環左移3位后的結果,即“XYZdefabc”。是不是很簡單?OK,搞定它!

 


 

43. 翻轉單詞順序列

牛客最近來了一個新員工Fish,每天早晨總是會拿着一本英文雜志,寫些句子在本子上。同事Cat對Fish寫的內容頗感興趣,有一天他向Fish借來翻看,但卻讀不懂它的意思。例如,“student. a am I”。后來才意識到,這家伙原來把句子單詞的順序翻轉了,正確的句子應該是“I am a student.”。Cat對一一的翻轉這些單詞順序可不在行,你能幫助他么?

先全部反轉,再單詞內反轉。

 


 

44. 撲克牌順子

LL今天心情特別好,因為他去買了一副撲克牌,發現里面居然有2個大王,2個小王(一副牌原本是54張_)…他隨機從中抽出了5張牌,想測測自己的手氣,看看能不能抽到順子,如果抽到的話,他決定去買體育彩票,嘿嘿!!“紅心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是順子…LL不高興了,他想了想,決定大\小王可以看成任何數字,並且A看作1,J為11,Q為12,K為13。上面的5張牌就可以變成“1,2,3,4,5”(大小王分別看作2和4),“So Lucky!”。LL決定去買體育彩票啦。 現在,要求你使用這幅牌模擬上面的過程,然后告訴我們LL的運氣如何,如果牌能組成順子就輸出true,否則就輸出false。為了方便起見,你可以認為大小王是0。

先排序,然后排除:
max - min <50外沒有重復的數字()

 


 

45. 孩子們的游戲(圓圈中最后剩下的數)

每年六一兒童節,牛客都會准備一些小禮物去看望孤兒院的小朋友,今年亦是如此。HF作為牛客的資深元老,自然也准備了一些小游戲。其中,有個游戲是這樣的:首先,讓小朋友們圍成一個大圈。然后,他隨機指定一個數m,讓編號為0的小朋友開始報數。每次喊到m-1的那個小朋友要出列唱首歌,然后可以在禮品箱中任意的挑選禮物,並且不再回到圈中,從他的下一個小朋友開始,繼續0…m-1報數…這樣下去…直到剩下最后一個小朋友,可以不用表演,並且拿到牛客名貴的“名偵探柯南”典藏版(名額有限哦!!_)。請你試着想下,哪個小朋友會得到這份禮品呢?(注:小朋友的編號是從0到n-1)

鏈表或數學方法,數學方法不懂
for(int i = 2; i <= n; i++) {
    last = (last + m) % i;
}
return last;

 


 

46. 求1+2+3+…+n

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。

public class Solution {
    public int Sum_Solution(int n) {
        int sum = n;
        boolean ans = (n>0)&&((sum+=Sum_Solution(n-1))>0);
        return sum;
    }
}

 


 

47. 不用加減乘除做加法

寫一個函數,求兩個整數之和,要求在函數體內不得使用+、-、*、/四則運算符號。

public class Solution {
    public int Add(int num1,int num2) {
        // 當進位為0時結束
        while (num2!=0) {
            // 第一步:相加各位的值,不算進位,得到2。
            // 即:5-101,7-111,不考慮進位的相加,即101異或111 = 010
            int temp = num1^num2;
            // 第二步:計算進位值
            // 0和0,1和0,0和1這種不會進位的相與得0,而1和1得1
            // 即相與得到進位的位,然后左移一位就是進位值,如101與111 = 101左移得1010
            num2 = (num1&num2)<<1;
            // 將結果賦給num1,再次進行相加(即把不考慮進位的值和進位值相加,
            // 因為有可能還會再次進位,所以要循環多次直到沒有進位)
            num1 = temp;
        }
        return num1;
    }
}

 


 

48. 把字符串轉換成整數

將一個字符串轉換成一個整數,要求不能使用字符串轉換整數的庫函數。 數值為0或者字符串不是一個合法的數值則返回0
輸入描述:
輸入一個字符串,包括數字字母符號,可以為空
輸出描述:
如果是合法的數值表達則返回該數字,否則返回0
示例1
輸入
+2147483647
1a33
輸出
2147483647
0

這是一道不求膽大只求心細的題目
但是要注意如何判斷整型溢出:

https://blog.csdn.net/qq_33330687/article/details/81626157


 

49. 數組中重復的數字

在一個長度為n的數組里的所有數字都在0到n-1的范圍內。數組中某些數字是重復的,但不知道有幾個數字是重復的。也不知道每個數字重復幾次。請找出數組中任意一個重復的數字。 例如,如果輸入長度為7的數組{2,3,1,0,2,5,3},那么對應的輸出是第一個重復的數字2。

用hashmap有空間消耗,直接把數組中的值換到對應下標中即可,
即{1,3,2,0,2,5,3}-->{3,1,2,0,2,5,3}-->{0,1,2,3,2,5,3}此時掃到2,
發現2和下標4不一樣,換回去發現已經有了,返回2

 


 

50. 構建乘積數組

給定一個數組A[0,1,…,n-1],請構建一個數組B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。

在這里插入圖片描述


 

51. 正則表達式匹配

請實現一個函數用來匹配包括’.‘和’ * ‘的正則表達式。模式中的字符’.‘表示任意一個字符,而’ * '表示它前面的字符可以出現任意次(包含0次)。在本題中,匹配是指字符串的所有字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"ab * ac * a"匹配。但是與"aa.a"和"ab * a"均不匹配

理清思路,每次從字符串中拿一個字符和模式匹配,如果模式是' . '則匹配,
如果不是則看看第二位是不是 * ,如果不是則直接匹配,如果是則看字符是不是匹配,
不匹配則模式后移兩位當做取0個,如果匹配則直接取下一個字符串。

 


 

52. 表示數值的字符串

請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示數值。但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。

 


 

53. 字符流中第一個不重復的字符

請實現一個函數用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是"g"。當從該字符流中讀出前六個字符“google"時,第一個只出現一次的字符是"l"。

hashmap思路,但是由於char流的大小為8bit,所以有256種可能,
所以只要建立一個256長的數組就可以了。

 


 

54. 鏈表中環的入口結點

給一個鏈表,若其中包含環,請找出該鏈表的環的入口結點,否則,輸出null。

快慢指針可以判斷是否存在環,指針相遇后,可以從這個結點出發計數,
直到再次遇到這個結點,則是環的長度,之后兩個指針間隔環的長度一前一后出發,
相遇的結點就是入口結點

 


 

55. 刪除鏈表中重復的結點

在一個排序的鏈表中,存在重復的結點,請刪除該鏈表中重復的結點,重復的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理后為 1->2->5

簡單題

 


 

56. 二叉樹的下一個結點

給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指針。

常規題,注意題目給出的結點是剛剛打印過的

 


 

57. 對稱的二叉樹

請實現一個函數,用來判斷一顆二叉樹是不是對稱的。注意,如果一個二叉樹同此二叉樹的鏡像是同樣的,定義其為對稱的。

在這里插入圖片描述

// 可以簡單看到,左右等於右左,左左等於右右,所以:

public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        if(pRoot == null){
            return true;
        }
        return comRoot(pRoot.left, pRoot.right);
    }
    private boolean comRoot(TreeNode left, TreeNode right) {
        // TODO Auto-generated method stub
        if(left == null) return right==null;
        if(right == null) return false;
        if(left.val != right.val) return false;
        return comRoot(left.right, right.left) && comRoot(left.left, right.right);
    }
}

 


 

58. 按之字形順序打印二叉樹

請實現一個函數按照之字形打印二叉樹,即第一行按照從左到右的順序打印,第二層按照從右至左的順序打印,第三行按照從左到右的順序打印,其他行以此類推。

簡單題

 


 

59. 把二叉樹打印成多行

從上到下按層打印二叉樹,同一層結點從左至右輸出。每一層輸出一行。

簡單題

 


 

60. 序列化二叉樹

請實現兩個函數,分別用來序列化和反序列化二叉樹

二叉樹的序列化是指:把一棵二叉樹按照某種遍歷方式的結果以某種格式保存為字符串,從而使得內存中建立起來的二叉樹可以持久保存。序列化可以基於先序、中序、后序、層序的二叉樹遍歷方式來進行修改,序列化的結果是一個字符串,序列化時通過某種符號表示空節點(#),以! 表示一個結點值的結束(value!)。

二叉樹的反序列化是指:根據某種遍歷順序得到的序列化字符串結果str,重構二叉樹。

常規的前序加中序或后序加中序有兩個缺點,一是二叉樹中不能有重復數值的結點,
二是只有當兩個序列中的所有數據都讀出來后才能開始反序列化。
因此需要插入#來代表空,如:{1,2,4,#,#,#,3,5,#,#,6,#,#}

在這里插入圖片描述


 

61. 平衡二叉樹

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

注意是平衡二叉樹不是平衡二叉搜索樹,
平衡二叉樹(Balanced Binary Tree)具有以下性質:
它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1
遞歸遍歷一下比較左右高度差即可

 


 

62. 二叉搜索樹的第k個結點

給定一棵二叉搜索樹,請找出其中的第k小的結點。例如, (5,3,7,2,4,6,8) 中,按結點數值大小順序第三小結點的值為4。

簡單題,中序遍歷

 


 

63. 數據流中的中位數

如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那么中位數就是所有數值排序之后位於中間的數值。如果從數據流中讀出偶數個數值,那么中位數就是所有數值排序之后中間兩個數的平均值。我們使用Insert()方法讀取數據流,使用GetMedian()方法獲取當前讀取數據的中位數。

假設{1,2,3,4,5,6}
兩個堆,最大堆中的數據{1,2,3}都小於最小堆中的數據{4,5,6},
最大堆中的最大值即是3,最小堆中的最小值即是4,,兩個數取中位數。
所以需要保證兩個堆的數據量相同,所以規定奇數插入最大堆,偶數最小堆。
還要保證最大堆中的數據都小於最小堆的數據,
所以可以把插入最大堆的數據先插入最小堆,然后取出最小值插回最大堆,
同理插入最小堆的值先插入最大堆,然后取出最大值插回最小堆

PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2.compareTo(o1);
        }
});

 


 

64. 滑動窗口的最大值

給定一個數組和滑動窗口的大小,找出所有滑動窗口里數值的最大值。例如,如果輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3,那么一共存在6個滑動窗口,他們的最大值分別為{4,4,6,6,6,5}; 針對數組{2,3,4,2,6,2,5,1}的滑動窗口有以下6個: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

用一個雙端隊列解決問題
分四種情況,
加入的數比隊頭的小,只要隊頭移出窗口它還是有機會的,所以加入隊列
加入的數比隊頭大,把前面的數都移出去,把它加入隊列的隊頭
加入的數比隊頭的小,但是比隊伍里其他的大,把其他的去掉,把它接在隊頭后面
隊頭從窗口滑出,移除隊頭

LinkedList<Integer> indexDeque = new LinkedList<>();
indexDeque.removeLast();      indexDeque.addLast(i);
indexDeque.removeFirst(); ...

 


 

65. 矩陣中的路徑

請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則該路徑不能再進入該格子。 例如 a b c e s f c s a d e e 矩陣中包含一條字符串"bcced"的路徑,但是矩陣中不包含"abcb"路徑,因為字符串的第一個字符b占據了矩陣中的第一行第二個格子之后,路徑不能再次進入該格子。

回溯法

 


 

66. 機器人的運動范圍

地上有一個m行和n列的方格。一個機器人從坐標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行坐標和列坐標的數位之和大於k的格子。 例如,當k為18時,機器人能夠進入方格(35,37),因為3+5+3+7 = 18。但是,它不能進入方格(35,38),因為3+5+3+8 = 19。請問該機器人能夠達到多少個格子?

回溯法

 


 

67. 剪繩子

給你一根長度為n的繩子,請把繩子剪成整數長的m段(m、n都是整數,n>1並且m>1),每段繩子的長度記為k[0],k[1],…,k[m]。請問k[0]xk[1]x…xk[m]可能的最大乘積是多少?例如,當繩子的長度是8時,我們把它剪成長度分別為2、3、3的三段,此時得到的最大乘積是18

動態規划

 



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM